]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.35 1.3.35
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:18 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:18 +0000 (15:10 -0500)
50 files changed:
Documentation/networking/z8530drv.txt
MAGIC
Makefile
arch/alpha/config.in
arch/alpha/kernel/irq.c
arch/i386/config.in
arch/i386/kernel/irq.c
arch/sparc/config.in
drivers/Makefile
drivers/block/Makefile
drivers/block/README.aztcd
drivers/block/README.sjcd
drivers/block/aztcd.c
drivers/block/ide.c
drivers/block/sjcd.c
drivers/block/triton.c
drivers/char/README.scc
drivers/char/atixlmouse.c
drivers/char/busmouse.c
drivers/char/keyboard.c
drivers/char/mem.c
drivers/char/msbusmouse.c
drivers/char/psaux.c
drivers/char/random.c
drivers/net/lance.c
drivers/net/ppp.c
drivers/scsi/aha1542.c
drivers/scsi/eata_dma_proc.c
drivers/scsi/scsi.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/sound/sb_dsp.c
fs/binfmt_elf.c
include/linux/aztcd.h
include/linux/major.h
include/linux/random.h
include/linux/rpcsock.h
include/linux/sjcd.h
kernel/module.c
scripts/Configure
scripts/Makefile [new file with mode: 0644]
scripts/header.tk [new file with mode: 0644]
scripts/tail.tk [new file with mode: 0644]
scripts/tkcond.c [new file with mode: 0644]
scripts/tkgen.c [new file with mode: 0644]
scripts/tkparse.c [new file with mode: 0644]
scripts/tkparse.h [new file with mode: 0644]

index 61f47b0e417d25ff8439cbfdadcc3f1178bf11b7..60ee0c454f5ecb776f89428d7257ea7365a20d15 100644 (file)
@@ -1,5 +1,5 @@
-// 950824: note -- I will upload the new version 1.9 to ftp.ucsd.edu
-//         as soon as possible... 
+// 950913: note -- I will upload the new version 1.9a to ftp.ucsd.edu
+//         as soon as possible...
 //
 // ******
 // ****** The driver has a  n e w  MAJOR number (34) now! ******
@@ -7,15 +7,25 @@
 //
 // please remake /dev/sc*:
 //
-// mknod /dev/sc1 c 34 0
-// mknod /dev/sc2 c 34 1
-// mknod /dev/sc3 c 34 2
-// mknod /dev/sc4 c 34 3
+// mknod /dev/scc0 c 34 0
+// mknod /dev/scc1 c 34 1
+// mknod /dev/scc2 c 34 2
+// mknod /dev/scc3 c 34 3
 //
 // (and so on...)
 //
+// If you want to use the old device naming scheme use:
+//
+// ln -f /dev/scc0 /dev/sc1
+// ln -f /dev/scc1 /dev/sc2
+// ln -f /dev/scc2 /dev/sc3
+// ln -f /dev/scc3 /dev/sc4
+//
+// (you get the idea...)
+//
 // -dl1bke-
 
+
 This is a subset of the documentation. To use this driver you MUST have the
 full package from:
 
@@ -252,11 +262,11 @@ and sets the MODEM and KISS parameters. A sample file is
 delivered with this package. Change it to your needs:
 
 Each channel definition is divided into three sections. An
-example for /dev/sc1:
+example for /dev/scc0:
 
 # DEVICE
 
-device /dev/sc               # the device for the following params
+device /dev/scc0               # the device for the following params
 
 # MODEM
 
@@ -318,10 +328,10 @@ Example Wampes:
 # NOTE: Interfacename and the device must be the same!!
 # Usage: attach asy 0 0 slip|vjslip|ax25ui|ax25i|nrs|kissui <label> 0 <mtu> <speed> [ip_addr]
 #
-attach asy 0 0 kissi sc1 256 256 1200    # Attach SCC channel 1 in 1200 baud
-attach asy 0 0 kissi sc2 256 256 1200    # Attach SCC channel 2 in 1200 baud
-attach asy 0 0 kissui sc3 256 256 38400  # Attach SCC channel 3 in 38400 baud
-attach asy 0 0 kissui sc4 256 256 9600   # Attach SCC channel 4 in 9600 baud
+attach asy 0 0 kissi scc0 256 256 1200    # Attach SCC channel 1 in 1200 baud
+attach asy 0 0 kissi scc1 256 256 1200    # Attach SCC channel 2 in 1200 baud
+attach asy 0 0 kissui scc2 256 256 38400  # Attach SCC channel 3 in 38400 baud
+attach asy 0 0 kissui scc3 256 256 9600   # Attach SCC channel 4 in 9600 baud
 #                ^
 #                 for WAMPES 921229 use here: ax25
 #
@@ -331,10 +341,10 @@ Example JNOS:
 ############################################
 # JNOS device attach
 #
-#attach asy sc1 0 ax25 sc1 256 256 1200
-#attach asy sc2 0 ax25 sc2 256 256 1200
-#attach asy sc3 0 ax25 sc3 256 256 300
-#attach asy sc4 0 ax25 sc4 256 256 4800
+#attach asy scc0 0 ax25 scc0 256 256 1200
+#attach asy scc1 0 ax25 scc1 256 256 1200
+#attach asy scc2 0 ax25 scc2 256 256 300
+#attach asy scc3 0 ax25 scc3 256 256 4800
 #
 #
 
@@ -361,7 +371,7 @@ still install it.
 Once a SCC channel has been attached, the parameter settings and 
 some statistic information can be shown using the param program:
 
-dl1bke-u:~$ sccstat /dev/sc1
+dl1bke-u:~$ sccstat /dev/scc0
 
 Parameters:
 
@@ -462,7 +472,7 @@ The parameters have the following meaning:
 speed:
      The baudrate on this channel in bits/sec
 
-     Example: sccparam /dev/sc4 speed 9600
+     Example: sccparam /dev/scc3 speed 9600
 
 txdelay:
      The delay (in units of 10ms) after keying of the 
@@ -474,7 +484,7 @@ txdelay:
      transmitter is ready for data.
      A normal value of this parameter is 30-36.
 
-     Example: sccparam /dev/sc1 txd 20
+     Example: sccparam /dev/scc0 txd 20
 
 persist:
      This is the probability that the transmitter will be keyed 
@@ -483,14 +493,14 @@ persist:
      should be somewhere near 50-60, and should be lowered when 
      the channel is used more heavily.
 
-     Example: sccparam /dev/sc3 persist 20
+     Example: sccparam /dev/scc2 persist 20
 
 slottime:
      This is the time between samples of the channel. It is 
      expressed in units of 10ms.  About 200-300 ms (value 20-30) 
      seems to be a good value.
 
-     Example: sccparam /dev/sc1 slot 20
+     Example: sccparam /dev/scc0 slot 20
 
 tail:
      The time the transmitter will remain keyed after the last 
@@ -501,7 +511,7 @@ tail:
      sufficient, e.g. 40ms at 1200 baud. (value 4)
      The value of this parameter is in 10ms units.
 
-     Example: sccparam /dev/sc3 4
+     Example: sccparam /dev/scc2 4
 
 full:
      The full-duplex mode switch. This can be one of the folowing 
@@ -517,7 +527,7 @@ full:
           sent in that case, until a timeout (parameter 10) 
           occurs.
 
-     Example: sccparam /dev/sc1 fulldup off
+     Example: sccparam /dev/scc0 fulldup off
 
 wait:
      The initial waittime before any transmit attempt, after the 
@@ -526,7 +536,7 @@ wait:
      set to 0 for maximum performance.
      The value of this parameter is in 10ms units. 
 
-     Example: sccparam /dev/sc2 wait 4
+     Example: sccparam /dev/scc1 wait 4
 
 maxkey:
      The maximal time the transmitter will be keyed to send 
@@ -540,13 +550,13 @@ maxkey:
      The value 0 as well as "off" will disable this feature, 
      and allow infinite transmission time. 
 
-     Example: sccparam /dev/sc1 maxk 20
+     Example: sccparam /dev/scc0 maxk 20
 
 min:
      This is the time the transmitter will be switched off when 
      the maximum transmission time is exceeded.
 
-     Example: sccparam /dev/sc4 min 10
+     Example: sccparam /dev/scc3 min 10
 
 idle
      This parameter specifies the maximum idle time in fullduplex 
@@ -555,7 +565,7 @@ idle
      has same result as the fullduplex mode 1. This parameter
      can be disabled.
 
-     Example: sccparam /dev/sc3 idle off       # transmit forever
+     Example: sccparam /dev/scc2 idle off      # transmit forever
 
 maxdefer
      This is the maximum time (in seconds) to wait for a free channel
@@ -563,14 +573,14 @@ maxdefer
      IMMEDIATLY. If you love to get trouble with other users you
      should set this to a very low value ;-)
 
-     Example: sccparam /dev/sc1 maxdefer 240   # 2 minutes
+     Example: sccparam /dev/scc0 maxdefer 240  # 2 minutes
 
 
 txoff:
      When this parameter has the value 0, the transmission of packets
      is enable. Otherwise it is disabled.
 
-     Example: sccparam /dev/sc3 txoff on
+     Example: sccparam /dev/scc2 txoff on
 
 group:
      It is possible to build special radio equipment to use more than 
@@ -610,56 +620,21 @@ softdcd:
      use a software dcd instead of the real one... Useful for a very
      slow squelch.
 
-     Example: sccparam /dev/sc1 soft on
+     Example: sccparam /dev/scc0 soft on
 
 
 slip:
      use slip encoding instead of kiss
 
-     Example: sccparam /dev/sc2 slip on
+     Example: sccparam /dev/scc1 slip on
 
 
 
 2. Problems
 ===========
 
-We are poking around in somebody else's code, so everything may change
-from one patchlevel to another... If the patches fail, try the
-following:
-
-2.1 /linux/drivers/char/Makefile
-================================
-
-Add "scc.o" to the definition of OBJS and "scc.c" to SRCS
-
-
-2.2 /linux/include/linux/tty_driver.h
-=====================================
-
-add the following DEFINE:
-
-#define TTY_DRIVER_TYPE_SCC 0x0005
-
-
-2.3 /linux/drivers/char/tty_io.c
-================================
-
-in tty_init() add the line
-
-       kmem_start=scc_init(kmem_start);
-
-just before "return kmem_start".
-
-2.4 /linux/arch/i386/config.in
-==============================
-
-somewhere in that file add:
-
-       comment 'Z8530 SCC driver for Amateur Packet Radio'
-       bool 'KISS emulator for Z8530 based HDLC cards' CONFIG_SCC y
-       comment ''
-  
 
+[..]
 
 2.5 Other problems
 ==================
@@ -697,78 +672,15 @@ Delayed processing of received data: This depends on
 - NET's speed itself.
 
 
-Kernel panics (based on excerpts from /linux/README)
-
-
-- if a bug results in a message like
-
-       unable to handle kernel paging request at address C0000010
-       Oops: 0002
-       EIP:   0010:XXXXXXXX
-       eax: xxxxxxxx   ebx: xxxxxxxx   ecx: xxxxxxxx   edx: xxxxxxxx
-       esi: xxxxxxxx   edi: xxxxxxxx   ebp: xxxxxxxx
-       ds: xxxx  es: xxxx  fs: xxxx  gs: xxxx
-       Pid: xx, process nr: xx
-       xx xx xx xx xx xx xx xx xx xx
-
-  or similar kernel debugging information on your screen or in your
-  system log, please duplicate it *exactly*.  The dump may look
-  incomprehensible to you, but it does contain information that may
-  help debugging the problem.  The text above the dump is also
-  important: it tells something about why the kernel dumped code (in
-  the above example it's due to a bad kernel pointer)
-
-- in debugging dumps like the above, please look up what the EIP value 
-  means.  The hex value as such doesn't help me or anybody else very much: 
-  it will depend on your particular kernel setup.  What you should do is 
-  take the hex value from the EIP line (ignore the "0010:"), and look it up 
-  in the kernel namelist to see which kernel function contains the offending 
-  address.
-
-  To find out the kernel function name, you'll need to 
-
-         less /linux/System.map
-
-  This will give you a list of kernel addresses sorted in ascending
-  order, from which it is simple to find the function that contains the
-  offending address.  Note that the address given by the kernel
-  debugging messages will not necessarily match exactly with the
-  function addresses (in fact, that is very unlikely), so you can't
-  just 'grep' the list: the list will, however, give you the starting
-  point of each kernel function, so by looking for the function that
-  has a starting address lower than the one you are searching for but
-  is followed by a function with a higher address you will find the one
-  you want.  In fact, it may be [IS!] a good idea to include a bit of
-  "context" in your problem report, giving a few lines around the
-  interesting one. 
-
-  I included a small program which does this for you. Just call
-
-         grep_eip /linux/System.map address
-
-  for example: grep_eip /linux/System.map 182f98
-
-- alternately, you can use gdb on a running kernel. (read-only; i.e. you
-  cannot change values or set break points.) To do this, first compile the
-  kernel with -g; edit arch/i386/Makefile appropriately, then do a "make
-  clean". You'll also need to enable CONFIG_PROC_FS (via "make config").
-
-  After you've rebooted with the new kernel, do "gdb vmlinux /proc/kcore".
-  You can now use all the usual gdb commands. The command to look up the
-  point where your system crashed is "l *0xXXXXXXXX". (Replace the XXXes
-  with the EIP value.)
-
-  gdb'ing a non-running kernel currently fails because gdb (wrongly)
-  disregards the starting offset for which the kernel is compiled.
-
-
+Kernel panics: please read to /linux/README and find out if it
+really occured within the scc driver.
 
 If you can't solve a problem, send me
 
 - a description of the problem,
 - information on your hardware (computer system, scc board, modem)
 - your kernel version
-- the output of sccstat /dev/sc# ("#" is the No. of the channel)
+- the output of sccstat /dev/scc# ("#" is the No. of the channel)
 - the settings of "speed", "clock" and "mode" for that channel
   in /etc/z8530drv.rc
 - your scc_config.h
@@ -779,79 +691,9 @@ The 1.1.* kernel series is for alpha tests -- use at your own risk ;-)
 The 1.2.* series should run reliable. This driver perhaps NOT!
 The 1.3.* kernel series is for alpha tests again... you get the idea!
 
-------------
-
-Example scc_config.h
 
-#include <linux/scc.h>
-
-/********* CONFIGURATION PARAMATERES; PLEASE CHANGE THIS TO YOUR OWN SITUATION **********/
-
-/* SCC hardware parameters */
-
-/* use the following board types: 
- *
- *     PA0HZP          OptoSCC (PA0HZP)
- *     EAGLE           EAGLE
- *     PC100           PC100 
- *     PRIMUS          PRIMUS-PC (DG9BL)
- *     DRSI            DRSI PC*Packet
- *     BAYCOM          BayCom (U)SCC
- *     
- */
-
-int     Nchips      = 2        ; /* number of chips */
-io_port Vector_Latch = 0       ; /* addr. of INTACK-Latch (0 for poll mode) */
-int     Ivec        = 7        ; /* interrupt vector */
-long    Clock       = 4915200  ; /* frequency of the scc clock */
-char   Board        = BAYCOM   ; /* what type of SCC card do you use? */
-int    Option       = 0        ; /* command for extra hardware */
-io_port Special_Port = 0       ; /* port address for special hardware */
-                                 /* (for EAGLE, PC100, PRIMUS, DRSI) */
-
-                       /*      ^  never remove the semicolon !! */
-                       
-
-
-/*                     Channel    A      B         Chip        */
-/*                              ============     ========      */
-/* Control ports:                                              */
-
-io_port SCC_ctrl[MAXSCC * 2] =         {0x304, 0x305,  /* ...one...    */
-                                0x306, 0x307,  /* ...two...    */
-                                    0,     0,  /* ...three...  */
-                                    0,     0}; /* ...four...   */
-
-/* Data ports:                                                 */
-
-io_port SCC_data[MAXSCC * 2] =  {0x300, 0x301, /* ...one...    */
-                                0x302, 0x303,  /* ...two...    */
-                                    0,     0,  /* ...three...  */
-                                    0,     0}; /* ...four...   */
-
-
-/* set to '1' if you have and want ESCC chip (8580/85180/85280) support */
-
-/*                                           Chip      */
-/*                                         ========    */
-int SCC_Enhanced[MAXSCC] =     {0,     /* ...one...    */
-                                0,     /* ...two...    */
-                                0,     /* ...three...  */
-                                0};    /* ...four...   */
-
-/* some useful #defines. You might need them or not */
-
-#define VERBOSE_BOOTMSG 1
-#undef  SCC_DELAY              /* perhaps a 486DX2 is a *bit* too fast */
-#undef  SCC_LDELAY             /* slow it even a bit more down */
-#undef  DONT_CHECK             /* don't look if the SCCs you specified are available */
-
-
-/* The external clocking, nrz and fullduplex divider configuration is gone */
-/* you can set these parameters in /etc/z8530drv.rc and initialize the  */
-/* driver with sccinit */
-
----------
+3. DRSI Boards
+==============
 
 I still can't test the DRSI board, but this configuration derived from
 the PE1CHL SCC driver configuration should work:
@@ -933,9 +775,6 @@ int SCC_Enhanced[MAXSCC] =  {0,     /* ...one...    */
 #undef  DONT_CHECK             /* don't look if the SCCs you specified are available */
 
 
-
-
-
 *****************
 
 You  m u s t  use "clock dpll" in /etc/z8530drv.rc for operation, 
@@ -944,9 +783,16 @@ the on-board baudrate generator is not supported.
 *****************
 (mni tnx to Mike Bilow)
 
-...an many thanks to Linus Torvalds and Alan Cox for including the driver
-   in the LinuX standard distribution...
+
+4. Thor RLC100
+==============
+
+Mysteriously this board seems not to work with the driver. Anyone
+got it up-and-running?
+
+
+Many thanks to Linus Torvalds and Alan Cox for including the driver
+in the LinuX standard distribution and their support.
 
 Joerg Reuter   ampr-net: dl1bke@db0pra.ampr.org
                AX-25   : DL1BKE @ DB0ACH.#NRW.DEU.EU
diff --git a/MAGIC b/MAGIC
index e19118228585e29da2c5c20eb00cc35c742739f2..999694d513b22571ed5d3bbc3215f71b46bcf57a 100644 (file)
--- a/MAGIC
+++ b/MAGIC
@@ -50,6 +50,7 @@ SLIP_MAGIC          0x5302  struct slip          drivers/net/slip.h
 Ioctl  Include File    Comments
 ========================================================
 0x00   fd.h
+0x01   random.h        subcodes starting at 0x080000
 0x03   hdreg.h
 0x06   lp.h
 0x12   fs.h
index eb0c0b9b95bcfbee7500929c321c55c1f2988662..b76e84b48b65e0d4cdc6f3ae2069bb9d0c316a67 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 34
+SUBLEVEL = 35
 
 ARCH = i386
 
@@ -134,6 +134,10 @@ symlinks:
 oldconfig: symlinks
        $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
 
+xconfig: symlinks
+       ( cd scripts ; make kconfig.tk)
+       ./scripts/kconfig.tk
+
 config: symlinks
        $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
 
@@ -243,6 +247,7 @@ mrproper: clean
        rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h
        rm -f drivers/char/uni_hash.tbl drivers/char/conmakehash
        rm -f .version .config* config.in config.old
+       rm -f scripts/tkparse scripts/kconfig.tk
        rm -f include/asm
        rm -f .depend `find . -name .depend -print`
        rm -f .hdepend
index 186c7170c4df188280200694ace6c6af8949aaa1..93b13e162ae0ce97f53b7f5306bd1af858f625d5 100644 (file)
@@ -2,7 +2,9 @@
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
+mainmenu_name "Kernel configuration of Linux for Alpha machines"
 
+mainmenu_option next_comment
 comment 'General setup'
 
 if [ "`uname`" != "Linux" ]; then
@@ -63,6 +65,7 @@ comment 'Loadable module support'
 bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n
 
 if [ "$CONFIG_NET" = "y" ]; then
+mainmenu_option next_comment
 comment 'Networking options'
 bool 'TCP/IP networking' CONFIG_INET y
 if [ "$CONFIG_INET" = "y" ]; then
@@ -94,6 +97,7 @@ if [ "$CONFIG_AX25" = "y" ]; then
 fi
 fi
 
+mainmenu_option next_comment
 comment 'SCSI support'
 
 tristate 'SCSI support' CONFIG_SCSI y
@@ -115,6 +119,7 @@ comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
 
 bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n
 
+mainmenu_option next_comment
 comment 'SCSI low-level drivers'
 
 dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n $CONFIG_SCSI
@@ -144,6 +149,7 @@ fi
 
 if [ "$CONFIG_NET" = "y" ]; then
 
+mainmenu_option next_comment
 comment 'Network device support'
 
 bool 'Network device support' CONFIG_NETDEVICES y
@@ -237,6 +243,7 @@ tristate 'Arcnet support' CONFIG_ARCNET n
 fi
 fi
 
+mainmenu_option next_comment
 comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
 
 bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI n
@@ -262,6 +269,7 @@ if [ "$CONFIG_CD_NO_IDESCSI" = "y" ]; then
   bool 'Experimental Sanyo H94A CDROM support' CONFIG_SJCD n
 fi
 
+mainmenu_option next_comment
 comment 'Filesystems'
 
 tristate 'Standard (minix) fs support' CONFIG_MINIX_FS y
@@ -281,6 +289,7 @@ tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
 tristate 'SMB filesystem (to mount WfW shares etc..) support' CONFIG_SMB_FS n
 
+mainmenu_option next_comment
 comment 'character devices'
 
 bool 'Cyclades async mux support' CONFIG_CYCLADES n
@@ -314,10 +323,12 @@ if [ "$CONFIG_FTAPE" = "y" ]; then
   int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
 fi
 
+mainmenu_option next_comment
 comment 'Sound'
 
 bool 'Sound card support' CONFIG_SOUND n
 
+mainmenu_option next_comment
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
index 5b6e7ec7cde9466e3a6b144c82b0d22a16afa36a..84e94c664d1a7a39a52a30d773366cdbc304cd9f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/random.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -322,10 +323,8 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
 
        kstat.interrupts[irq]++;
        action = irq_action + irq;
-#ifdef CONFIG_RANDOM
        if (action->flags & SA_SAMPLE_RANDOM)
                add_interrupt_randomness(irq);
-#endif
        /* quick interrupts get executed with no extra overhead */
        if (action->flags & SA_INTERRUPT) {
                action->handler(irq, regs);
index 4d58db244c57b498d13727a4116929093e40ed1f..22dc4a867a17dd7a14aa61205d09ba3e9b8d34b1 100644 (file)
@@ -2,7 +2,9 @@
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
+mainmenu_name "Linux Kernel Configuration"
 
+mainmenu_option next_comment
 comment 'General setup'
 
 bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
@@ -42,10 +44,12 @@ bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
 #fi
 bool 'SMP Kernel (experimental - gcc2.5.8 only: see Documentation/SMP.txt)' CONFIG_SMP n
 
+mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n
 
 if [ "$CONFIG_NET" = "y" ]; then
+mainmenu_option next_comment
 comment 'Networking options'
 bool 'TCP/IP networking' CONFIG_INET y
 if [ "$CONFIG_INET" = "y" ]; then
@@ -81,6 +85,7 @@ if [ "$CONFIG_NETLINK" = "y" ]; then
 fi
 fi
 
+mainmenu_option next_comment
 comment 'SCSI support'
 
 tristate 'SCSI support' CONFIG_SCSI n
@@ -102,6 +107,7 @@ comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
 
 bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n
 
+mainmenu_option next_comment
 comment 'SCSI low-level drivers'
 
 dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n $CONFIG_SCSI
@@ -132,6 +138,7 @@ fi
 
 if [ "$CONFIG_NET" = "y" ]; then
 
+mainmenu_option next_comment
 comment 'Network device support'
 
 bool 'Network device support' CONFIG_NETDEVICES y
@@ -225,6 +232,7 @@ tristate 'Arcnet support' CONFIG_ARCNET n
 fi
 fi
 
+mainmenu_option next_comment
 comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
 
 bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI n
@@ -247,9 +255,10 @@ if [ "$CONFIG_CD_NO_IDESCSI" = "y" ]; then
   tristate 'Goldstar R420 CDROM support' CONFIG_GSCD n
   tristate 'Philips/LMS CM206 CDROM support' CONFIG_CM206 n
   tristate 'Experimental Optics Storage DOLPHIN 8000AT CDROM support' CONFIG_OPTCD n
-  bool 'Experimental Sanyo H94A CDROM support' CONFIG_SJCD n
+  tristate 'Experimental Sanyo H94A CDROM support' CONFIG_SJCD n
 fi
 
+mainmenu_option next_comment
 comment 'Filesystems'
 
 tristate 'Standard (minix) fs support' CONFIG_MINIX_FS y
@@ -269,6 +278,7 @@ tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
 tristate 'SMB filesystem (to mount WfW shares etc..) support' CONFIG_SMB_FS n
 
+mainmenu_option next_comment
 comment 'character devices'
 
 bool 'Cyclades async mux support' CONFIG_CYCLADES n
@@ -302,10 +312,12 @@ comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02
 fi
 fi
 
+mainmenu_option next_comment
 comment 'Sound'
 
 tristate 'Sound card support' CONFIG_SOUND n
 
+mainmenu_option next_comment
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
index 680a1c8a77a65411f5f18227dfebd744e63be75c..266af4d679f0a9e26229dc27e854b83aa96a56c2 100644 (file)
@@ -214,10 +214,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 #endif
 
        kstat.interrupts[irq]++;
-#ifdef CONFIG_RANDOM
        if (action->flags & SA_SAMPLE_RANDOM)
                add_interrupt_randomness(irq);
-#endif
        action->handler(irq, regs);
 }
 
@@ -236,10 +234,8 @@ asmlinkage void do_fast_IRQ(int irq)
 #endif
 
        kstat.interrupts[irq]++;
-#ifdef CONFIG_RANDOM
        if (action->flags & SA_SAMPLE_RANDOM)
                add_interrupt_randomness(irq);
-#endif
        action->handler(irq, NULL);
 }
 
@@ -258,6 +254,8 @@ int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
                return -EBUSY;
        if (!handler)
                return -EINVAL;
+       if (irqflags & SA_SAMPLE_RANDOM)
+               rand_initialize_irq(irq);
        save_flags(flags);
        cli();
        action->handler = handler;
index 6c66331a3d4079964b964d9eb5094382930b6ee8..d1ceddafa5dc8e1c1730677efffef0ee5a491dfb 100644 (file)
@@ -8,10 +8,12 @@
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
+mainmenu_name 'Sparc Linux Kernel Configuration'
 
 echo "#define CONFIG_SPARCDEVS 1" >> $CONFIG_H
 echo "CONFIG_SPARCDEVS=y" >> $CONFIG
 
+mainmenu_option next_comment
 comment 'Sparc Kernel setup'
 
 bool 'Sun floppy controller support' CONFIG_BLK_DEV_SUNFD n
@@ -21,6 +23,7 @@ bool 'System V IPC' CONFIG_SYSVIPC y
 bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
 
 if [ "$CONFIG_NET" = "y" ]; then
+mainmenu_option next_comment
 comment 'Networking options'
 bool 'TCP/IP networking' CONFIG_INET y
 if [ "$CONFIG_INET" "=" "y" ]; then
@@ -38,6 +41,7 @@ bool 'The IPX protocol' CONFIG_IPX n
 #bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
 fi
 
+mainmenu_option next_comment
 comment 'SCSI support'
 
 bool 'SCSI support?' CONFIG_SCSI n
@@ -64,6 +68,7 @@ fi
 
 if [ "$CONFIG_NET" = "y" ]; then
 
+mainmenu_option next_comment
 comment 'Network device support'
 
 bool 'Network device support?' CONFIG_NETDEVICES y
@@ -86,6 +91,7 @@ bool 'Sun Intel Ethernet support' CONFIG_SUN_INTEL n
 fi
 fi
 
+mainmenu_option next_comment
 comment 'Filesystems'
 
 bool 'Standard (minix) fs support' CONFIG_MINIX_FS n
@@ -106,6 +112,7 @@ bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
 bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
 
 
+mainmenu_option next_comment
 comment 'character devices'
 
 bool 'Zilog serial support' CONFIG_SUN_ZS n
@@ -114,6 +121,7 @@ comment 'Sound'
 
 bool 'Sun Audio support' CONFIG_SUN_AUDIO n
 
+mainmenu_option next_comment
 comment 'Kernel hacking'
 
 bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
index bca73c3d72b48524082e4f89cfb99e66f2372dbb..dd8fba734419542d8ccbef24e2f3c0b3c9a628fc 100644 (file)
@@ -15,8 +15,11 @@ ifdef CONFIG_PCI
 SUB_DIRS += pci
 endif
 
+# If CONFIG_SCSI is set, the core of scsi support will be added to the kernel,
+# but some of the low-level things may also be modules.
 ifeq ($(CONFIG_SCSI),y)
 SUB_DIRS += scsi
+MOD_SUB_DIRS += scsi
 else
   ifeq ($(CONFIG_SCSI),m)
   MOD_SUB_DIRS += scsi
index 6cc98f1a5ba1639fe2323cfd31f1c0ccdb6426de..0123f1aa1fc68a92829ddc360a0b907ca3406d73 100644 (file)
@@ -114,10 +114,10 @@ endif #CONFIG_OPTCD
 
 ifeq ($(CONFIG_SJCD),y)
 L_OBJS += sjcd.o
-#else
-#  ifeq ($(CONFIG_SJCD),m)
-#  M_OBJS += sjcd.o
-#  endif
+else
+  ifeq ($(CONFIG_SJCD),m)
+  M_OBJS += sjcd.o
+  endif
 endif #CONFIG_SJCD
 
 ifeq ($(CONFIG_BLK_DEV_HD),y)
index 9c6453792530d9e257e74efbdb50711dd658d419..6fa8ce53ba86d3dabbf7baa6236cdc42e0d19041 100644 (file)
@@ -1,4 +1,4 @@
-$Id: README.aztcd,v 1.70 1995/08/19 16:21:05 root Exp root $
+$Id: README.aztcd,v 1.80 1995/10/11 19:37:49 root Exp root $
                        Readme-File README.aztcd
    for Aztech CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 
                           CD-ROM  Driver 
@@ -15,6 +15,7 @@ NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE
       THE STANDARD-KERNEL 1.2.x NOW ALSO SUPPORTS IDE-CDROM-DRIVES, SEE THE
       HARDDISK (!) SECTION OF make config, WHEN COMPILING A NEW KERNEL!!!
 ----------------------------------------------------------------------------
+
 Contents of this file:
                          1.  NOTE
                          2.  INSTALLATION
index 8c97ef5780f213413e06839b66a63ee6b34ceefa..f475e80ccba92639f35f8894d046d865d8cfd418 100644 (file)
@@ -6,7 +6,7 @@
                                Once started, training can not be stopped...
                                                (StarWars)
 
-This is the README for the sjcd cdrom driver, version 1.3.
+This is the README for the sjcd cdrom driver, version 1.5.
 
 This file is meant as a tips & tricks edge for the usage of the SANYO CDR-H94A
 cdrom drive. It will grow as the questions arise. ;-)
@@ -21,8 +21,8 @@ The suggestion to configure the ISP16 soundcard by booting DOS and
 a warm reboot to boot Linux somehow doesn't work, at least not
 on Eric's machine (IPC P90), with the version of the ISP16
 card he has (there appear to be at least two versions: Eric's card with
-no jumpered IDE support and Vadim's version with a jumper to enable
-IDE support).
+no jumpered IDE support and OPTi 82C928 chip, and Vadim's version
+with a jumper to enable IDE support, probably with a OPTi 82C929 chip).
 Therefore detection and configuration of the ISP16 interfaces is included
 in the driver.
 If we should support any other interfaces (which cannot be configured
@@ -30,13 +30,18 @@ through DOS) or if there are any more ISP16 types, please let us
 know (maarel@marin.nl) and we'll see.
 
 Otherwise, you should boot DOS once (and by this, run the "configuration driver")
-and then switch to Linux by use of CTL-ALT-DEL. Each use of the RESET
+and then switch to Linux by use of CTRL-ALT-DEL. Each use of the RESET
 button or the power switch makes this procedure necessary again.
 If no ISP16 is detected, there's no harm done; a card configured trough DOS
 may still work as expected.
 
+As of version 1.4 sound through the speakers is supported; only for MSS-mode 
+and no volume controle yet.
+
+PAUSE and STOP ioctl commands don't seem to work yet.
+
 ISP16 configuration routines reside at Vadim's server
-      rbrf.msk.su:/linux/mediamagic/
+      ftp.rbrf.ru:/linux/mediamagic/
 and at Eberhard's mirror
       ftp.gwdg.de:/pub/linux/cdrom/drivers/sanyo/
 
@@ -51,13 +56,13 @@ This, and any related stuff may be found by anonymous ftp at
 
 The device major for sjcd is 18, and minor is 0. Create a block special
 file in your /dev directory (e.g., /dev/sjcd) with these numbers.
-(For those who don't know, being root and the following should do the trick:
+(For those who don't know, being root and doing the following should do the trick:
   mknod -m 644 /dev/sjcd b 18 0
 and mount the cdrom by /dev/sjcd).
 
 The default configuration parameters are:
   base address 0x340
-  irq 10
+  no irq
   no dma
 As of version 1.2, setting base address, irq and dma at boot time is supported
 through the use of command line options: type at the "boot:" prompt:
@@ -65,7 +70,7 @@ through the use of command line options: type at the "boot:" prompt:
 (where your kernel is assumed to be called by saying "linux" to
 the boot manager).
 
-If something is wrong, e-mail to               vadim@rbrf.msk.su
+If something is wrong, e-mail to               vadim@rbrf.ru
                                        or      vadim@ipsun.ras.ru
                                        or      model@cecmow.enet.dec.com
 
index 45743873bd88927f3bfef589a3a055ccbe089ede..99cd26d004a902339e6c48dbd17c63d097bac2bb 100644 (file)
@@ -1,5 +1,5 @@
-#define AZT_VERSION "1.70"
-/*      $Id: aztcd.c,v 1.70 1995/08/19 16:16:39 root Exp root $
+#define AZT_VERSION "1.80"
+/*      $Id: aztcd.c,v 1.80 1995/10/11 19:35:03 root Exp root $
        linux/drivers/block/aztcd.c - AztechCD268 CDROM driver
 
        Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
                 enough testing done. If you can test it, please contact me. For
                 details please read README.aztcd.
                 Werner Zimmermann, August 19, 1995
+        V1.80   Modification to suit the new kernel boot procedure introduced
+                with kernel 1.3.33. Will definitely not work with older kernels.
+                Programming done by Linus himself.
+                Werner Zimmermann, October 11, 1995
        NOTE: 
        Points marked with ??? are questionable !
 */
index c0050af25d88b11ccb8fd1c19685fe3a853c87d6..e336918e3fd144fd28fed72673001646c923072f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 5.14  Sep 14, 1995
+ *  linux/drivers/block/ide.c  Version 5.15  Oct 13, 1995
  *
  *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
  * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
  * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
  * 
+ * It is easy to extend ide.c to handle more than four interfaces:
+ *
+ *     Change the MAX_HWIFS constant in ide.h.
+ * 
+ *     Define some new major numbers (in major.h), and insert them into
+ *     the ide_hwif_to_major table in ide.c.
+ * 
+ *     Fill in the extra values for the new interfaces into the two tables
+ *     inside ide.c:  default_io_base[]  and  default_irqs[].
+ * 
+ *     Create the new request handlers by cloning "do_ide3_request()"
+ *     for each new interface, and add them to the switch statement
+ *     in the ide_init() function in ide.c.
+ *
+ *     Recompile, create the new /dev/ entries, and it will probably work.
+ *
  *  From hd.c:
  *  |
  *  | It traverses the request-list, using interrupts to jump between functions.
  *  Version 5.14       fixes to cmd640 support.. maybe it works now(?)
  *                     added & tested full EZ-DRIVE support -- don't use LILO!
  *                     don't enable 2nd CMD640 PCI port during init - conflict
+ *  Version 5.15       bug fix in init_cmd640_vlb()
+ *                     bug fix in interrupt sharing code
  *
  *  Driver compile-time options are in ide.h
  *
@@ -2400,6 +2418,7 @@ void init_cmd640_vlb (void)
        if (reg == 0xff || (reg & 0x90) != 0x90) {
 #if TRY_CMD640_VLB_AT_0x78
                port = 0x78;
+               reg = read_cmd640_vlb(port, 0x50);
                if (reg == 0xff || (reg & 0x90) != 0x90)
 #endif
                {
@@ -2735,17 +2754,17 @@ static int init_irq (ide_hwif_t *hwif)
         */
        save_flags(flags);
        cli();
-       if (request_irq(hwif->irq, ide_intr,
-                       SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name)) {
-               restore_flags(flags);
-               printk(" -- FAILED!");
-               return 1;
-       }
-
-       /*
-        * Got the irq,  now set everything else up
-        */
        if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) {
+               if (request_irq(hwif->irq, ide_intr,
+                               SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name)) {
+                       restore_flags(flags);
+                       printk(" -- FAILED!");
+                       return 1;
+               }
+
+               /*
+                * Got the irq,  now set everything else up
+                */
                hwgroup = kmalloc (sizeof(ide_hwgroup_t), GFP_KERNEL);
                irq_to_hwgroup[hwif->irq] = hwgroup;
                hwgroup->hwif    = hwif->next = hwif;
index 16216120f3084c02173874938377297537b8d223..93facbadfb73451ec3b69012651036a70667c308 100644 (file)
@@ -1,24 +1,23 @@
 /* -- sjcd.c
  *
- *   Sanyo CD-ROM device driver implementation, Version 1.3
+ *   Sanyo CD-ROM device driver implementation, Version 1.5
  *   Copyright (C) 1995  Vadim V. Model
  *
  *   model@cecmow.enet.dec.com
- *   vadim@rbrf.msk.su
+ *   vadim@rbrf.ru
  *   vadim@ipsun.ras.ru
  *
  *   ISP16 detection and configuration.
  *   Copyright (C) 1995  Eric van der Maarel (maarel@marin.nl)
+ *                   and Vadim Model (vadim@cecmow.enet.dec.com)
  *
  *
  *  This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de);
  *  it was developed under use of mcd.c from Martin Harriss, with help of
  *  Eric van der Maarel (maarel@marin.nl).
  *
- *  ISP16 detection and configuration by Eric van der Maarel (maarel@marin.nl),
- *  with some data communicated by Vadim V. Model (vadim@rbrf.msk.su)
- *  and Leo Spiekman (spiekman@et.tudelft.nl)
- *
+ *  ISP16 detection and configuration by Eric van der Maarel (maarel@marin.nl).
+ *  Sound configuration by Vadim V. Model (model@cecmow.enet.dec.com)
  *
  *  It is planned to include these routines into sbpcd.c later - to make
  *  a "mixed use" on one cable possible for all kinds of drives which use
  *      on ISP16 soundcard.
  *      Allow for command line options: sjcd=<io_base>,<irq>,<dma>
  *  1.3 Some minor changes to README.sjcd.
+ *  1.4 MSS Sound support!! Listen to a CD through the speakers.
+ *  1.5 Module support and bugfixes.
+ *      Tray locking.
  *
  */
 
+#include <linux/major.h>
+#include <linux/config.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#define sjcd_init init_module
+#ifndef CONFIG_MODVERSIONS
+char kernel_version[]= UTS_RELEASE;
+#endif
+#endif
+
 #include <linux/errno.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/timer.h>
@@ -59,7 +72,6 @@
 #include <linux/cdrom.h>
 #include <linux/ioport.h>
 #include <linux/string.h>
-#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #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 */
+/* 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_NO_IDE__CTRL  0xE2  /* ISP16 without IDE interface */
-#define ISP16_IDE__CTRL  0xE3  /* ISP16 with IDE interface */
+#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_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_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_cdrom_port;
-
+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
+};
 
 #define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */
 
@@ -137,6 +155,7 @@ static volatile int sjcd_buf_in, sjcd_buf_out = -1;
  */
 static unsigned short sjcd_status_valid = 0;
 static unsigned short sjcd_door_closed;
+static unsigned short sjcd_door_was_open;
 static unsigned short sjcd_media_is_available;
 static unsigned short sjcd_media_is_changed;
 static unsigned short sjcd_toc_uptodate = 0;
@@ -151,9 +170,9 @@ static int sjcd_open_count;
 static int sjcd_audio_status;
 static struct sjcd_play_msf sjcd_playing;
 
-static short    sjcd_port = SJCD_BASE_ADDR;
-static int      sjcd_irq  = SJCD_INTR_NR;
-static int      sjcd_dma  = SJCD_DMA;
+static int sjcd_port = SJCD_BASE_ADDR;
+static int sjcd_irq  = SJCD_INTR_NR;
+static int sjcd_dma  = SJCD_DMA_NR;
 
 static struct wait_queue *sjcd_waitq = NULL;
 
@@ -174,17 +193,16 @@ enum sjcd_transfer_state {
 static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE;
 static long sjcd_transfer_timeout = 0;
 static int sjcd_read_count = 0;
-#if 0
-static unsigned short sjcd_tries;
-#endif
 static unsigned char sjcd_mode = 0;
 
 #define SJCD_READ_TIMEOUT 5000
 
+#if defined( SJCD_GATHER_STAT )
 /*
  * Statistic.
  */
 static struct sjcd_stat statistic;
+#endif
 
 /*
  * Timer.
@@ -202,8 +220,8 @@ static struct timer_list sjcd_delay_timer = { NULL, NULL, 0, 0, NULL };
  * Set up device, i.e., use command line data to set
  * base address, irq and dma.
  */
-void sjcd_setup( char *str, int *ints ){
-
+void sjcd_setup( char *str, int *ints )
+{
    if (ints[0] > 0)
       sjcd_port = ints[1];
    if (ints[0] > 1)      
@@ -243,7 +261,7 @@ static void hsg2msf( long hsg, struct msf *msf ){
  * Send a command to cdrom. Invalidate status.
  */
 static void sjcd_send_cmd( unsigned char cmd ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: send_cmd( 0x%x )\n", cmd );
 #endif
   outb( cmd, SJCDPORT( 0 ) );
@@ -256,7 +274,7 @@ static void sjcd_send_cmd( unsigned char cmd ){
  * Send a command with one arg to cdrom. Invalidate status.
  */
 static void sjcd_send_1_cmd( unsigned char cmd, unsigned char a ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: send_1_cmd( 0x%x, 0x%x )\n", cmd, a );
 #endif
   outb( cmd, SJCDPORT( 0 ) );
@@ -271,7 +289,7 @@ static void sjcd_send_1_cmd( unsigned char cmd, unsigned char a ){
  */
 static void sjcd_send_4_cmd( unsigned char cmd, unsigned char a,
            unsigned char b, unsigned char c, unsigned char d ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: send_4_cmd( 0x%x )\n", cmd );
 #endif
   outb( cmd, SJCDPORT( 0 ) );
@@ -288,7 +306,7 @@ static void sjcd_send_4_cmd( unsigned char cmd, unsigned char a,
  * Send a play or read command to cdrom. Invalidate Status.
  */
 static void sjcd_send_6_cmd( unsigned char cmd, struct sjcd_play_msf *pms ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: send_long_cmd( 0x%x )\n", cmd );
 #endif
   outb( cmd, SJCDPORT( 0 ) );
@@ -312,7 +330,7 @@ static int sjcd_load_response( void *buf, int len ){
 
   for( ; len; --len ){ 
     int i;
-    for( i = 200; i-- && inb( SJCDPORT( 1 ) ) !=  0x09; );
+    for( i = 200; i-- && !SJCD_STATUS_AVAILABLE( inb( SJCDPORT( 1 ) ) ); );
     if( i > 0 ) *resp++ = ( unsigned char )inb( SJCDPORT( 0 ) );
     else break;
   }
@@ -320,7 +338,8 @@ static int sjcd_load_response( void *buf, int len ){
 }
 
 /*
- * Load and parse status.
+ * Load and parse command completion status (drive info byte and maybe error).
+ * Sorry, no error classification yet.
  */
 static void sjcd_load_status( void ){
   sjcd_media_is_changed = 0;
@@ -333,7 +352,10 @@ static void sjcd_load_status( void ){
     if( sjcd_completion_status & SST_MEDIA_CHANGED )
       sjcd_media_is_available = sjcd_media_is_changed = 1;
     else if( sjcd_completion_status & 0x0F ){
-      while( ( inb( SJCDPORT( 1 ) ) & 0x0B ) != 0x09 );
+      /*
+       * OK, we seem to catch an error ...
+       */
+      while( !SJCD_STATUS_AVAILABLE( inb( SJCDPORT( 1 ) ) ) );
       sjcd_completion_error = inb( SJCDPORT( 0 ) );
       if( ( sjcd_completion_status & 0x08 ) &&
         ( sjcd_completion_error & 0x40 ) )
@@ -346,8 +368,12 @@ static void sjcd_load_status( void ){
    */
   sjcd_status_valid = 1, sjcd_error_reported = 0;
   sjcd_command_is_in_progress = 0;
+
+  /*
+   * If the disk is changed, the TOC is not valid.
+   */
   if( sjcd_media_is_changed ) sjcd_toc_uptodate = 0;
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: status %02x.%02x loaded.\n",
         ( int )sjcd_completion_status, ( int )sjcd_completion_error );
 #endif
@@ -360,7 +386,7 @@ static int sjcd_check_status( void ){
   /*
    * Try to load the response from cdrom into buffer.
    */
-  if( ( inb( SJCDPORT( 1 ) ) & 0x0B ) == 0x09 ){
+  if( SJCD_STATUS_AVAILABLE( inb( SJCDPORT( 1 ) ) ) ){
     sjcd_load_status();
     return( 1 );
   } else {
@@ -371,31 +397,55 @@ static int sjcd_check_status( void ){
   }
 }
 
+/*
+ * This is just timout counter, and nothing more. Surprized ? :-)
+ */
 static volatile long sjcd_status_timeout;
+
+/*
+ * We need about 10 seconds to wait. The longest command takes about 5 seconds
+ * to probe the disk (usually after tray closed or drive reset). Other values
+ * should be thought of for other commands.
+ */
 #define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000
 
 static void sjcd_status_timer( void ){
   if( sjcd_check_status() ){
+    /*
+     * The command completed and status is loaded, stop waiting.
+     */
     wake_up( &sjcd_waitq );
   } else if( --sjcd_status_timeout <= 0 ){
+    /*
+     * We are timed out. 
+     */
     wake_up( &sjcd_waitq );
   } else {
-    SJCD_SET_TIMER( sjcd_status_timer, HZ/100 );
+    /*
+     * We have still some time to wait. Try again.
+     */
+    SJCD_SET_TIMER( sjcd_status_timer, 1 );
   }
 }
 
+/*
+ * Wait for status for 10 sec approx. Returns non-positive when timed out.
+ * Should not be used while reading data CDs.
+ */
 static int sjcd_wait_for_status( void ){
   sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT;
-  SJCD_SET_TIMER( sjcd_status_timer, HZ/100 );
+  SJCD_SET_TIMER( sjcd_status_timer, 1 ); 
   sleep_on( &sjcd_waitq );    
+#if defined( SJCD_DIAGNOSTIC ) || defined ( SJCD_TRACE )
   if( sjcd_status_timeout <= 0 )
     printk( "sjcd: Error Wait For Status.\n" );
+#endif
   return( sjcd_status_timeout );
 }
 
 static int sjcd_receive_status( void ){
   int i;
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: receive_status\n" );
 #endif
   /*
@@ -403,7 +453,7 @@ static int sjcd_receive_status( void ){
    */
   for( i = 200; i-- && ( sjcd_check_status() == 0 ); );
   if( i < 0 ){
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: long wait for status\n" );
 #endif
     if( sjcd_wait_for_status() <= 0 )
@@ -414,10 +464,10 @@ static int sjcd_receive_status( void ){
 }
 
 /*
- * Load the status.
+ * Load the status. Issue get status command and wait for status available.
  */
 static void sjcd_get_status( void ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: get_status\n" );
 #endif
   sjcd_send_cmd( SCMD_GET_STATUS );
@@ -425,7 +475,7 @@ static void sjcd_get_status( void ){
 }
 
 /*
- * Check the drive if the disk is changed.
+ * Check the drive if the disk is changed. Should be revised.
  */
 static int sjcd_disk_change( kdev_t full_dev ){
 #if 0
@@ -444,14 +494,14 @@ static int sjcd_disk_change( kdev_t full_dev ){
  * Read the table of contents (TOC) and TOC header if necessary.
  * We assume that the drive contains no more than 99 toc entries.
  */
-static struct sjcd_hw_disk_info sjcd_table_of_contents[ 100 ];
+static struct sjcd_hw_disk_info sjcd_table_of_contents[ SJCD_MAX_TRACKS ];
 static unsigned char sjcd_first_track_no, sjcd_last_track_no;
 #define sjcd_disk_length  sjcd_table_of_contents[0].un.track_msf
 
 static int sjcd_update_toc( void ){
   struct sjcd_hw_disk_info info;
   int i;
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: update toc:\n" );
 #endif
   /*
@@ -485,7 +535,7 @@ static int sjcd_update_toc( void ){
     printk( "get first failed\n" );
     return( -1 );
   }
-#if 0
+#if defined( SJCD_TRACE )
   printk( "TOC start 0x%02x ", sjcd_first_track_no );
 #endif
   /*
@@ -514,7 +564,7 @@ static int sjcd_update_toc( void ){
     printk( "get last failed\n" );
     return( -1 );
   }
-#if 0
+#if defined( SJCD_TRACE )
   printk( "TOC finish 0x%02x ", sjcd_last_track_no );
 #endif
   for( i = sjcd_first_track_no; i <= sjcd_last_track_no; i++ ){
@@ -574,7 +624,7 @@ static int sjcd_update_toc( void ){
     printk( "get size failed\n" );
     return( 1 );
   }
-#if 0
+#if defined( SJCD_TRACE )
   printk( "(%02x:%02x.%02x)\n", sjcd_disk_length.min,
         sjcd_disk_length.sec, sjcd_disk_length.frame );
 #endif
@@ -586,7 +636,7 @@ static int sjcd_update_toc( void ){
  */
 static int sjcd_get_q_info( struct sjcd_hw_qinfo *qp ){
   int s;
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: load sub q\n" );
 #endif
   sjcd_send_cmd( SCMD_GET_QINFO );
@@ -631,12 +681,47 @@ static int sjcd_play( struct sjcd_play_msf *mp ){
   return( sjcd_receive_status() );
 }
 
+/*
+ * Tray control functions.
+ */
+static int sjcd_tray_close( void ){
+#if defined( SJCD_TRACE )
+  printk( "sjcd: tray_close\n" );
+#endif
+  sjcd_send_cmd( SCMD_CLOSE_TRAY );
+  return( sjcd_receive_status() );
+}
+
+static int sjcd_tray_lock( void ){
+#if defined( SJCD_TRACE )
+  printk( "sjcd: tray_lock\n" );
+#endif
+  sjcd_send_cmd( SCMD_LOCK_TRAY );
+  return( sjcd_receive_status() );
+}
+
+static int sjcd_tray_unlock( void ){
+#if defined( SJCD_TRACE )
+  printk( "sjcd: tray_unlock\n" );
+#endif
+  sjcd_send_cmd( SCMD_UNLOCK_TRAY );
+  return( sjcd_receive_status() );
+}
+
+static int sjcd_tray_open( void ){
+#if defined( SJCD_TRACE )
+  printk( "sjcd: tray_open\n" );
+#endif
+  sjcd_send_cmd( SCMD_EJECT_TRAY );
+  return( sjcd_receive_status() );
+}
+
 /*
  * Do some user commands.
  */
 static int sjcd_ioctl( struct inode *ip, struct file *fp,
                       unsigned int cmd, unsigned long arg ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd:ioctl\n" );
 #endif
 
@@ -648,14 +733,14 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
 
   switch( cmd ){
   case CDROMSTART:{
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: start\n" );
 #endif
     return( 0 );
   }
 
   case CDROMSTOP:{
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: stop\n" );
 #endif
     sjcd_send_cmd( SCMD_PAUSE );
@@ -666,7 +751,7 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
 
   case CDROMPAUSE:{
     struct sjcd_hw_qinfo q_info;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: pause\n" );
 #endif
     if( sjcd_audio_status == CDROM_AUDIO_PLAY ){
@@ -683,7 +768,7 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
   }
 
   case CDROMRESUME:{
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: resume\n" );
 #endif
     if( sjcd_audio_status == CDROM_AUDIO_PAUSED ){
@@ -702,11 +787,11 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
 
   case CDROMPLAYTRKIND:{
     struct cdrom_ti ti; int s;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: playtrkind\n" );
 #endif
-    if( ( s = verify_area( VERIFY_READ, (void *) arg, sizeof( ti ) ) ) == 0 ){
-      memcpy_fromfs( &ti, (void *) arg, sizeof( ti ) );
+    if( ( s = verify_area( VERIFY_READ, (void *)arg, sizeof( ti ) ) ) == 0 ){
+      memcpy_fromfs( &ti, (void *)arg, sizeof( ti ) );
 
       if( ti.cdti_trk0 < sjcd_first_track_no ) return( -EINVAL );
       if( ti.cdti_trk1 > sjcd_last_track_no )
@@ -728,17 +813,17 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
 
   case CDROMPLAYMSF:{
     struct cdrom_msf sjcd_msf; int s;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: playmsf\n" );
 #endif
-    if( ( s = verify_area( VERIFY_READ, (void *) arg, sizeof( sjcd_msf ) ) ) == 0 ){
+    if( ( s = verify_area( VERIFY_READ, (void *)arg, sizeof( sjcd_msf ) ) ) == 0 ){
       if( sjcd_audio_status == CDROM_AUDIO_PLAY ){
        sjcd_send_cmd( SCMD_PAUSE );
        ( void )sjcd_receive_status();
        sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
       }
 
-      memcpy_fromfs( &sjcd_msf, ( void * )arg, sizeof( sjcd_msf ) );
+      memcpy_fromfs( &sjcd_msf, (void *)arg, sizeof( sjcd_msf ) );
 
       sjcd_playing.start.min = bin2bcd( sjcd_msf.cdmsf_min0 );
       sjcd_playing.start.sec = bin2bcd( sjcd_msf.cdmsf_sec0 );
@@ -757,26 +842,26 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
 
   case CDROMREADTOCHDR:{
     struct cdrom_tochdr toc_header; int s;
-#if 0
+#if defined (SJCD_TRACE )
     printk( "sjcd: ioctl: readtocheader\n" );
 #endif
-    if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( toc_header ) ) ) == 0 ){
+    if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( toc_header ) ) ) == 0 ){
       toc_header.cdth_trk0 = sjcd_first_track_no;
       toc_header.cdth_trk1 = sjcd_last_track_no;
-      memcpy_tofs( ( void * )arg, &toc_header, sizeof( toc_header ) );
+      memcpy_tofs( (void *)arg, &toc_header, sizeof( toc_header ) );
     }
     return( s );
   }
 
   case CDROMREADTOCENTRY:{
     struct cdrom_tocentry toc_entry; int s;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: readtocentry\n" );
 #endif
-    if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( toc_entry ) ) ) == 0 ){
+    if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( toc_entry ) ) ) == 0 ){
       struct sjcd_hw_disk_info *tp;
 
-      memcpy_fromfs( &toc_entry, ( void * )arg, sizeof( toc_entry ) );
+      memcpy_fromfs( &toc_entry, (void *)arg, sizeof( toc_entry ) );
 
       if( toc_entry.cdte_track == CDROM_LEADOUT )
        tp = &sjcd_table_of_contents[ 0 ];
@@ -798,20 +883,20 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
        break;
       default: return( -EINVAL );
       }
-      memcpy_tofs( ( void * )arg, &toc_entry, sizeof( toc_entry ) );
+      memcpy_tofs( (void *)arg, &toc_entry, sizeof( toc_entry ) );
     }
     return( s );
   }
 
   case CDROMSUBCHNL:{
     struct cdrom_subchnl subchnl; int s;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: subchnl\n" );
 #endif
-    if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( subchnl ) ) ) == 0 ){
+    if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( subchnl ) ) ) == 0 ){
       struct sjcd_hw_qinfo q_info;
 
-      memcpy_fromfs( &subchnl, ( void * )arg, sizeof( subchnl ) );
+      memcpy_fromfs( &subchnl, (void *)arg, sizeof( subchnl ) );
       if( sjcd_get_q_info( &q_info ) < 0 ) return( -EIO );
 
       subchnl.cdsc_audiostatus = sjcd_audio_status;
@@ -835,20 +920,20 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
        break;
       default: return( -EINVAL );
       }
-      memcpy_tofs( ( void * )arg, &subchnl, sizeof( subchnl ) );
+      memcpy_tofs( (void *)arg, &subchnl, sizeof( subchnl ) );
     }
     return( s );
   }
 
   case CDROMVOLCTRL:{
     struct cdrom_volctrl vol_ctrl; int s;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: volctrl\n" );
 #endif
-    if( ( s = verify_area( VERIFY_READ, (void *) arg, sizeof( vol_ctrl ) ) ) == 0 ){
+    if( ( s = verify_area( VERIFY_READ, (void *)arg, sizeof( vol_ctrl ) ) ) == 0 ){
       unsigned char dummy[ 4 ];
 
-      memcpy_fromfs( &vol_ctrl, ( void * )arg, sizeof( vol_ctrl ) );
+      memcpy_fromfs( &vol_ctrl, (void *)arg, sizeof( vol_ctrl ) );
       sjcd_send_4_cmd( SCMD_SET_VOLUME, vol_ctrl.channel0, 0xFF,
                      vol_ctrl.channel1, 0xFF );
       if( sjcd_receive_status() < 0 ) return( -EIO );
@@ -858,41 +943,34 @@ static int sjcd_ioctl( struct inode *ip, struct file *fp,
   }
 
   case CDROMEJECT:{
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: eject\n" );
 #endif
     if( !sjcd_command_is_in_progress ){
+      sjcd_tray_unlock();
       sjcd_send_cmd( SCMD_EJECT_TRAY );
       ( void )sjcd_receive_status();
     }
     return( 0 );
   }
 
+#if defined( SJCD_GATHER_STAT )
   case 0xABCD:{
     int s;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: ioctl: statistic\n" );
 #endif
-    if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( statistic ) ) ) == 0 )
-      memcpy_tofs( ( void * )arg, &statistic, sizeof( statistic ) );
+    if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( statistic ) ) ) == 0 )
+      memcpy_tofs( (void *)arg, &statistic, sizeof( statistic ) );
     return( s );
   }
+#endif
 
   default:
     return( -EINVAL );
   }
 }
 
-#if 0
-/*
- * We only seem to get interrupts after an error.
- * Just take the interrupt and clear out the status reg.
- */
-static void sjcd_interrupt( int irq, struct pt_regs *regs ){
-  printk( "sjcd: interrupt is cought\n" );
-}
-#endif
-
 /*
  * Invalidate internal buffers of the driver.
  */
@@ -912,7 +990,7 @@ static void sjcd_invalidate_buffers( void ){
       CURRENT->cmd == READ && CURRENT->sector != -1 )
 
 static void sjcd_transfer( void ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: transfer:\n" );
 #endif
   if( CURRENT_IS_VALID ){
@@ -931,7 +1009,7 @@ static void sjcd_transfer( void ){
        }
        if( nr_sectors > CURRENT->nr_sectors )
          nr_sectors = CURRENT->nr_sectors;
-#if 0
+#if defined( SJCD_TRACE )
        printk( "copy out\n" );
 #endif
        memcpy( CURRENT->buffer, sjcd_buf + offs, nr_sectors * 512 );
@@ -944,35 +1022,41 @@ static void sjcd_transfer( void ){
       }
     }
   }
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: transfer: done\n" );
 #endif
 }
 
 static void sjcd_poll( void ){
+#if defined( SJCD_GATHER_STAT )
   /*
    * Update total number of ticks.
    */
   statistic.ticks++;
   statistic.tticks[ sjcd_transfer_state ]++;
+#endif
 
  ReSwitch: switch( sjcd_transfer_state ){
       
   case SJCD_S_IDLE:{
+#if defined( SJCD_GATHER_STAT )
     statistic.idle_ticks++;
-#if 0
+#endif
+#if defined( SJCD_TRACE )
     printk( "SJCD_S_IDLE\n" );
 #endif
     return;
   }
 
   case SJCD_S_START:{
+#if defined( SJCD_GATHER_STAT )
     statistic.start_ticks++;
+#endif
     sjcd_send_cmd( SCMD_GET_STATUS );
     sjcd_transfer_state =
       sjcd_mode == SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE;
     sjcd_transfer_timeout = 500;
-#if 0
+#if defined( SJCD_TRACE )
     printk( "SJCD_S_START: goto SJCD_S_%s mode\n",
           sjcd_transfer_state == SJCD_S_READ ? "READ" : "MODE" );
 #endif
@@ -982,10 +1066,10 @@ static void sjcd_poll( void ){
   case SJCD_S_MODE:{
     if( sjcd_check_status() ){
       /*
-       * Previos command is completed.
+       * Previous command is completed.
        */
       if( !sjcd_status_valid || sjcd_command_failed ){
-#if 0
+#if defined( SJCD_TRACE )
        printk( "SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n" );
 #endif
        sjcd_transfer_state = SJCD_S_STOP;
@@ -995,10 +1079,13 @@ static void sjcd_poll( void ){
       sjcd_mode = 0; /* unknown mode; should not be valid when failed */
       sjcd_send_1_cmd( SCMD_SET_MODE, SCMD_MODE_COOKED );
       sjcd_transfer_state = SJCD_S_READ; sjcd_transfer_timeout = 1000;
-#if 0
+#if defined( SJCD_TRACE )
       printk( "SJCD_S_MODE: goto SJCD_S_READ mode\n" );
 #endif
-    } else statistic.mode_ticks++;
+    }
+#if defined( SJCD_GATHER_STAT )
+    else statistic.mode_ticks++;
+#endif
     break;
   }
 
@@ -1008,14 +1095,14 @@ static void sjcd_poll( void ){
        * Previos command is completed.
        */
       if( !sjcd_status_valid || sjcd_command_failed ){
-#if 0
+#if defined( SJCD_TRACE )
        printk( "SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n" );
 #endif
        sjcd_transfer_state = SJCD_S_STOP;
        goto ReSwitch;
       }
       if( !sjcd_media_is_available ){
-#if 0
+#if defined( SJCD_TRACE )
        printk( "SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n" );
 #endif
        sjcd_transfer_state = SJCD_S_STOP;
@@ -1026,14 +1113,14 @@ static void sjcd_poll( void ){
         * We seem to come from set mode. So discard one byte of result.
         */
        if( sjcd_load_response( &sjcd_mode, 1 ) != 0 ){
-#if 0
+#if defined( SJCD_TRACE )
          printk( "SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n" );
 #endif
          sjcd_transfer_state = SJCD_S_STOP;
          goto ReSwitch;
        }
        if( sjcd_mode != SCMD_MODE_COOKED ){
-#if 0
+#if defined( SJCD_TRACE )
          printk( "SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n" );
 #endif
          sjcd_transfer_state = SJCD_S_STOP;
@@ -1048,7 +1135,7 @@ static void sjcd_poll( void ){
        hsg2msf( sjcd_next_bn, &msf.start );
        msf.end.min = 0; msf.end.sec = 0;            
        msf.end.frame = sjcd_read_count = SJCD_BUF_SIZ;
-#if 0
+#if defined( SJCD_TRACE )
        printk( "---reading msf-address %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 );
@@ -1059,28 +1146,31 @@ static void sjcd_poll( void ){
        sjcd_send_6_cmd( SCMD_DATA_READ, &msf );
        sjcd_transfer_state = SJCD_S_DATA;
        sjcd_transfer_timeout = 500;
-#if 0
+#if defined( SJCD_TRACE )
        printk( "SJCD_S_READ: go to SJCD_S_DATA mode\n" );
 #endif
       } else {
-#if 0
+#if defined( SJCD_TRACE )
        printk( "SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n" );
 #endif
        sjcd_transfer_state = SJCD_S_STOP;
        goto ReSwitch;
       }
-    } else statistic.read_ticks++;
+    }
+#if defined( SJCD_GATHER_STAT )
+    else statistic.read_ticks++;
+#endif
     break;
   }
 
   case SJCD_S_DATA:{
     unsigned char stat;
 
-  sjcd_s_data: stat = inb( SJCDPORT( 1 ) ) & 0x0B;
-#if 0
+  sjcd_s_data: stat = inb( SJCDPORT( 1 ) );
+#if defined( SJCD_TRACE )
     printk( "SJCD_S_DATA: status = 0x%02x\n", stat );
 #endif
-    if( stat == 0x09 ){
+    if( SJCD_STATUS_AVAILABLE( stat ) ){
       /*
        * No data is waiting for us in the drive buffer. Status of operation
        * completion is available. Read and parse it.
@@ -1088,10 +1178,14 @@ static void sjcd_poll( void ){
       sjcd_load_status();
 
       if( !sjcd_status_valid || sjcd_command_failed ){
+#if defined( SJCD_TRACE )
        printk( "sjcd: read block %d failed, maybe audio disk? Giving up\n",
               sjcd_next_bn );
+#endif
        if( CURRENT_IS_VALID ) end_request( 0 );
+#if defined( SJCD_TRACE )
        printk( "SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n" );
+#endif
        sjcd_transfer_state = SJCD_S_STOP;
        goto ReSwitch;
       }
@@ -1102,17 +1196,19 @@ static void sjcd_poll( void ){
        goto ReSwitch;
       }
 
-      sjcd_transfer_state = SJCD_S_START;
+      sjcd_transfer_state = SJCD_S_READ;
       goto ReSwitch;
-    } else if( stat == 0x0A ){
+    } else if( SJCD_DATA_AVAILABLE( stat ) ){
       /*
        * One frame is read into device buffer. We must copy it to our memory.
-       * Otherwise cdrom hangs up. Check to see if we have something to read
+       * Otherwise cdrom hangs up. Check to see if we have something to copy
        * to.
        */
       if( !CURRENT_IS_VALID && sjcd_buf_in == sjcd_buf_out ){
+#if defined( SJCD_TRACE )
        printk( "SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n" );
        printk( " ... all the date would be discarded\n" );
+#endif
        sjcd_transfer_state = SJCD_S_STOP;
        goto ReSwitch;
       }
@@ -1123,7 +1219,7 @@ static void sjcd_poll( void ){
        */
       sjcd_buf_bn[ sjcd_buf_in ] = -1; /* ??? */
       insb( SJCDPORT( 2 ), sjcd_buf + 2048 * sjcd_buf_in, 2048 );
-#if 0
+#if defined( SJCD_TRACE )
       printk( "SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n",
             sjcd_next_bn, sjcd_buf_in, sjcd_buf_out,
             sjcd_buf_bn[ sjcd_buf_in ] );
@@ -1153,16 +1249,21 @@ static void sjcd_poll( void ){
        if( CURRENT_IS_VALID &&
           ( CURRENT->sector / 4 < sjcd_next_bn ||
            CURRENT->sector / 4 > sjcd_next_bn + SJCD_BUF_SIZ ) ){
-#if 0
+#if defined( SJCD_TRACE )
          printk( "SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n" );
 #endif
          sjcd_transfer_state = SJCD_S_STOP;
          goto ReSwitch;
        }
       }
+      /*
+       * Now we should turn around rather than wait for while.
+       */
       goto sjcd_s_data;
-      /* sjcd_transfer_timeout = 500; */
-    } else statistic.data_ticks++;
+    }
+#if defined( SJCD_GATHER_STAT )
+    else statistic.data_ticks++;
+#endif
     break;
   }
 
@@ -1171,20 +1272,22 @@ static void sjcd_poll( void ){
     sjcd_send_cmd( SCMD_STOP );
     sjcd_transfer_state = SJCD_S_STOPPING;
     sjcd_transfer_timeout = 500;
+#if defined( SJCD_GATHER_STAT )
     statistic.stop_ticks++;
+#endif
     break;
   }
 
   case SJCD_S_STOPPING:{
     unsigned char stat;
     
-    stat = inb( SJCDPORT( 1 ) ) & 0x0B;
-#if 0
+    stat = inb( SJCDPORT( 1 ) );
+#if defined( SJCD_TRACE )
     printk( "SJCD_S_STOP: status = 0x%02x\n", stat );
 #endif      
-    if( stat == 0x0A ){
+    if( SJCD_DATA_AVAILABLE( stat ) ){
       int i;
-#if 0
+#if defined( SJCD_TRACE )
       printk( "SJCD_S_STOP: discard data\n" );
 #endif
       /*
@@ -1192,7 +1295,7 @@ static void sjcd_poll( void ){
        */
       for( i = 2048; i--; ( void )inb( SJCDPORT( 2 ) ) );
       sjcd_transfer_timeout = 500;
-    } else if( stat == 0x09 ){
+    } else if( SJCD_STATUS_AVAILABLE( stat ) ){
       sjcd_load_status();
       if( sjcd_status_valid && sjcd_media_is_changed ) {
        sjcd_toc_uptodate = 0;
@@ -1203,7 +1306,10 @@ static void sjcd_poll( void ){
        else sjcd_transfer_state = SJCD_S_START;
       } else sjcd_transfer_state = SJCD_S_IDLE;
       goto ReSwitch;
-    } else statistic.stopping_ticks++;
+    }
+#if defined( SJCD_GATHER_STAT )
+    else statistic.stopping_ticks++;
+#endif
     break;
   }
 
@@ -1218,16 +1324,17 @@ static void sjcd_poll( void ){
     sjcd_send_cmd( SCMD_STOP );
     sjcd_transfer_state = SJCD_S_IDLE;
     goto ReSwitch;
-  }
+    }
 
   /*
-   * Get back in some time.
+   * Get back in some time. 1 should be replaced with count variable to
+   * avoid unnecessary testings.
    */
-  SJCD_SET_TIMER( sjcd_poll, HZ/100 );
+  SJCD_SET_TIMER( sjcd_poll, 1 );
 }
 
 static void do_sjcd_request( void ){
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd: do_sjcd_request(%ld+%ld)\n",
         CURRENT->sector, CURRENT->nr_sectors );
 #endif
@@ -1258,7 +1365,7 @@ static void do_sjcd_request( void ){
     }
   }
   sjcd_transfer_is_active = 0;
-#if 0
+#if defined( SJCD_TRACE )
   printk( "sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n",
         sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, sjcd_buf_bn[ sjcd_buf_in ] );
   printk( "do_sjcd_request ends\n" );
@@ -1266,7 +1373,7 @@ static void do_sjcd_request( void ){
 }
 
 /*
- * Open the device special file. Check that a disk is in.
+ * Open the device special file. Check disk is in.
  */
 int sjcd_open( struct inode *ip, struct file *fp ){
   /*
@@ -1280,44 +1387,96 @@ int sjcd_open( struct inode *ip, struct file *fp ){
   if( fp->f_mode & 2 ) return( -EROFS );
   
   if( sjcd_open_count == 0 ){
+    int s, sjcd_open_tries;
+/* We don't know that, do we? */
+/*
     sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
+*/
     sjcd_mode = 0;
+    sjcd_door_was_open = 0;
     sjcd_transfer_state = SJCD_S_IDLE;
     sjcd_invalidate_buffers();
+    sjcd_status_valid = 0;
 
     /*
      * Strict status checking.
      */
-    sjcd_get_status();
-    if( !sjcd_status_valid ){
-#if 0
-      printk( "sjcd: open: timed out when check status.\n" );
+    for( sjcd_open_tries = 4; --sjcd_open_tries; ){
+      if( !sjcd_status_valid ) sjcd_get_status();
+      if( !sjcd_status_valid ){
+#if defined( SJCD_DIAGNOSTIC )
+       printk( "sjcd: open: timed out when check status.\n" );
 #endif
-      return( -EIO );
-    } else if( !sjcd_media_is_available ){
-#if 0
-      printk("sjcd: open: no disk in drive\n");
+       return( -EIO );
+      } else if( !sjcd_media_is_available ){
+#if defined( SJCD_DIAGNOSTIC )
+       printk("sjcd: open: no disk in drive\n");
+#endif
+       if( !sjcd_door_closed ){
+         sjcd_door_was_open = 1;
+#if defined( SJCD_TRACE )
+         printk("sjcd: open: close the tray\n");
+#endif
+         s = sjcd_tray_close();
+         if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
+#if defined( SJCD_DIAGNOSTIC )
+           printk("sjcd: open: tray close attempt failed\n");
+#endif
+           return( -EIO );
+         }
+         continue;
+       } else return( -EIO );
+      }
+      break;
+    }
+    s = sjcd_tray_lock();
+    if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
+#if defined( SJCD_DIAGNOSTIC )
+      printk("sjcd: open: tray lock attempt failed\n");
 #endif
       return( -EIO );
     }
-#if 0
+#if defined( SJCD_TRACE )
     printk( "sjcd: open: done\n" );
 #endif
   }
-  return( ++sjcd_open_count, 0 );
+#ifdef MODULE
+  MOD_INC_USE_COUNT;
+#endif
+  ++sjcd_open_count;
+  return( 0 );
 }
 
 /*
  * On close, we flush all sjcd blocks from the buffer cache.
  */
 static void sjcd_release( struct inode *inode, struct file *file ){
-#if 0
+  int s;
+
+#if defined( SJCD_TRACE )
   printk( "sjcd: release\n" );
+#endif
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
 #endif
   if( --sjcd_open_count == 0 ){
     sjcd_invalidate_buffers();
     sync_dev( inode->i_rdev );
     invalidate_buffers( inode->i_rdev );
+    s = sjcd_tray_unlock();
+    if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
+#if defined( SJCD_DIAGNOSTIC )
+      printk("sjcd: release: tray unlock attempt failed.\n");
+#endif
+    }
+    if( sjcd_door_was_open ){
+      s = sjcd_tray_open();
+      if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
+#if defined( SJCD_DIAGNOSTIC )
+       printk("sjcd: release: tray unload attempt failed.\n");
+#endif
+      }
+    }
   }
 }
 
@@ -1344,6 +1503,7 @@ static struct file_operations sjcd_fops = {
  * Following stuff is intended for initialization of the cdrom. It
  * first looks for presence of device. If the device is present, it
  * will be reset. Then read the version of the drive and load status.
+ * The version is two BCD-coded bytes.
  */
 static struct {
   unsigned char major, minor;
@@ -1361,20 +1521,27 @@ int sjcd_init( void ){
   else {
     u_char expected_drive;
 
-    printk( "ISP16 cdrom interface (%s optional IDE) detected.\n",
-      (isp16_type==2)?"with":"without" );
+    printk( "ISP16 cdrom interface (with OPTi 82C92%s chip) detected.\n",
+      (isp16_type==2)?"9":"8" );
+
+    printk( "ISP16 sound configuration.\n" );
+    isp16_sound_config();
 
     expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0);
 
-    if ( isp16_config( sjcd_port, expected_drive, sjcd_irq, sjcd_dma ) < 0 ) {
+    if ( isp16_cdi_config( sjcd_port, expected_drive, sjcd_irq, sjcd_dma ) < 0 ) {
       printk( "ISP16 cdrom interface has not been properly configured.\n" );
-      return -1;
+      return( -EIO );
     }
   }
 
+#if defined( SJCD_TRACE )
+  printk( "sjcd=0x%x,%d: ", sjcd_port, sjcd_irq );
+#endif  
+
   if( register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){
     printk( "Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR );
-    return -1;
+    return( -EIO );
   }
   
   blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST;
@@ -1382,54 +1549,101 @@ int sjcd_init( void ){
   
   if( check_region( sjcd_port, 4 ) ){
     printk( "Init failed, I/O port (%X) is already in use\n",
-          sjcd_port );
-    return -1;
+      sjcd_port );
+    return( -EIO );
   }
   
-  printk( "Sanyo CDR-H94A:" );
-
   /*
-   * Check for card.
+   * Check for card. Since we are booting now, we can't use standard
+   * wait algorithm.
    */
-  for( i = 100; i > 0; --i )
-    if( !( inb( SJCDPORT( 1 ) ) & 0x04 ) ) break;
-  if( i == 0 ){
-    printk( " No device at 0x%x found.\n", sjcd_port );
-    return -1;
-  }
-  
+  printk( "Sanyo: Resetting: " );
   sjcd_send_cmd( SCMD_RESET );
-  while( !sjcd_status_valid ) ( void )sjcd_check_status();
+  for( i = 1000; i-- > 0 && !sjcd_status_valid; ){
+    unsigned long timer;
+
+    /*
+     * Wait 10ms approx.
+     */
+    for( timer = jiffies; jiffies <= timer; );
+    if ( (i % 100) == 0 ) printk( "." );
+    ( void )sjcd_check_status();
+  }
+  if( i == 0 || sjcd_command_failed ){
+    printk( " reset failed, no drive found.\n" );
+    return( -EIO );
+  } else printk( "\n" );
 
   /*
    * Get and print out cdrom version.
    */
+  printk( "Sanyo: Getting version: " );
   sjcd_send_cmd( SCMD_GET_VERSION );
-  while( !sjcd_status_valid ) ( void )sjcd_check_status();
+  for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
+    unsigned long timer;
+
+    /*
+     * Wait 10ms approx.
+     */
+    for( timer = jiffies; jiffies <= timer; );
+    if ( (i % 100) == 0 ) printk( "." );
+    ( void )sjcd_check_status();
+  }
+  if( i == 0 || sjcd_command_failed ){
+    printk( " get version failed, no drive found.\n" );
+    return( -EIO );
+  }
 
   if( sjcd_load_response( &sjcd_version, sizeof( sjcd_version ) ) == 0 ){
-    printk( " Version %1x.%02x.", ( int )sjcd_version.major,
+    printk( " %1x.%02x\n", ( int )sjcd_version.major,
             ( int )sjcd_version.minor );
   } else {
-    printk( " Read version failed.\n" );
-    return -1;
+    printk( " read version failed, no drive found.\n" );
+    return( -EIO );
   }
 
   /*
    * Check and print out the tray state. (if it is needed?).
    */
   if( !sjcd_status_valid ){
+    printk( "Sanyo: Getting status: " );
     sjcd_send_cmd( SCMD_GET_STATUS );
-    while( !sjcd_status_valid ) ( void )sjcd_check_status();
+    for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
+      unsigned long timer;
+
+      /*
+       * Wait 10ms approx.
+       */
+      for( timer = jiffies; jiffies <= timer; );
+      if ( (i % 100) == 0 ) printk( "." );
+      ( void )sjcd_check_status();
+    }
+    if( i == 0 || sjcd_command_failed ){
+      printk( " get status failed, no drive found.\n" );
+      return( -EIO );
+    } else printk( "\n" );
   }
 
-  printk( " Status: port=0x%x, irq=%d\n",
-        sjcd_port, sjcd_irq );
+  printk( "SANYO CDR-H94A: Status: port=0x%x, irq=%d, dma=%d.\n",
+        sjcd_port, sjcd_irq, sjcd_dma );
 
   sjcd_present++;
-  return 0;
+  return( 0 );
 }
 
+#ifdef MODULE
+void cleanup_module( void ){
+  if( MOD_IN_USE ){
+    printk( "sjcd: module: in use - can not remove.\n" );
+  } else if( ( unregister_blkdev( MAJOR_NR, "sjcd" ) == -EINVAL ) ){
+    printk( "sjcd: module: can not unregister device.\n" );
+  } else {
+    release_region( sjcd_port, 4 );
+    printk( "sjcd: module: removed.\n");
+  }
+}
+#endif
+
 /*
  * -- ISP16 detection and configuration
  *
@@ -1439,11 +1653,12 @@ int sjcd_init( void ){
  *
  *    Detect cdrom interface on ISP16 soundcard.
  *    Configure cdrom interface.
+ *    Configure sound interface.
  *
- *    Algorithm for the card with no IDE support option taken
+ *    Algorithm for the card with OPTi 82C928 taken
  *    from the CDSETUP.SYS driver for MSDOS,
  *    by OPTi Computers, version 2.03.
- *    Algorithm for the IDE supporting ISP16 as communicated
+ *    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
@@ -1459,22 +1674,22 @@ static short
 isp16_detect(void)
 {
 
-  if ( !( isp16_with_ide__detect() < 0 ) )
+  if ( !( isp16_c929__detect() < 0 ) )
     return(2);
   else
-    return( isp16_no_ide__detect() );
+    return( isp16_c928__detect() );
 }
 
 static short
-isp16_no_ide__detect(void)
+isp16_c928__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;
+  isp16_ctrl = ISP16_C928__CTRL;
+  isp16_enable_port = ISP16_C928__ENABLE_PORT;
 
   /* read' and write' are a special read and write, respectively */
 
@@ -1483,7 +1698,7 @@ isp16_no_ide__detect(void)
   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;
+  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 */
@@ -1497,7 +1712,7 @@ isp16_no_ide__detect(void)
         i = 1;
         enable_cdrom |= 0x28;
       }
-      ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom );
+      ISP16_OUT( ISP16_C928__ENABLE_PORT, enable_cdrom );
     }
     else {  /* bits are not the same */
       ISP16_OUT( ISP16_CTRL_PORT, ctrl );
@@ -1515,13 +1730,13 @@ isp16_no_ide__detect(void)
 }
 
 static short
-isp16_with_ide__detect(void)
+isp16_c929__detect(void)
 {
   u_char ctrl;
   u_char tmp;
 
-  isp16_ctrl = ISP16_IDE__CTRL;
-  isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT;
+  isp16_ctrl = ISP16_C929__CTRL;
+  isp16_enable_port = ISP16_C929__ENABLE_PORT;
 
   /* read' and write' are a special read and write, respectively */
 
@@ -1532,7 +1747,7 @@ isp16_with_ide__detect(void)
   ISP16_OUT( ISP16_CTRL_PORT, 0 );
   tmp = ISP16_IN( ISP16_CTRL_PORT );
 
-  if ( tmp != 2 )  /* isp16 with ide option not detected */
+  if ( tmp != 2 )  /* isp16 with 82C929 not detected */
     return(-1);
 
   /* restore ctrl port value */
@@ -1542,7 +1757,7 @@ isp16_with_ide__detect(void)
 }
 
 static short
-isp16_config( int base, u_char drive_type, int irq, int dma )
+isp16_cdi_config( int base, u_char drive_type, int irq, int dma )
 {
   u_char base_code;
   u_char irq_code;
@@ -1606,9 +1821,9 @@ isp16_config( int base, u_char drive_type, int irq, int dma )
   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 */
+  /* enable cdrom on interface with 82C929 chip */
   if ( isp16_type > 1 )
-    ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM );
+    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 */
@@ -1616,3 +1831,85 @@ isp16_config( int base, u_char drive_type, int irq, int dma )
 
   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 );
+*/
+
+}
index 2ec8e8718ef79dfc2a3a3b517128096c37f8b517..972baf1a831a803a2c0cb069c69fef6d05a40a6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/triton.c       Version 1.01  Aug 28, 1995
+ *  linux/drivers/block/triton.c       Version 1.02  Oct 13, 1995
  *
  *  Copyright (c) 1995  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -109,8 +109,13 @@ const char *good_dma_drives[] = {"Micropolis 2112A"};
  * Note that 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,
+ * 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.
  */
-#define PRD_ENTRIES    128     /* max memory area count per DMA */
+#define PRD_BYTES      8
+#define PRD_ENTRIES    (PAGE_SIZE / (2 * PRD_BYTES))
 
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
@@ -298,6 +303,7 @@ void ide_init_triton (byte bus, byte fn)
        int rc = 0, h;
        unsigned short bmiba, pcicmd;
        unsigned int timings;
+       unsigned char *dmatable = NULL;
        extern ide_hwif_t ide_hwifs[];
 
        /*
@@ -351,13 +357,22 @@ void ide_init_triton (byte bus, byte fn)
                if (check_region(base, 8)) {
                        printk(" -- ERROR, PORTS ALREADY IN USE");
                } else {
-                       unsigned long *table;
                        request_region(base, 8, hwif->name);
-                       hwif->dma_base  = base;
-                       table = (void *) __get_dma_pages(GFP_KERNEL, 0);
-                       hwif->dmatable = table;
-                       outl(virt_to_bus(table), base + 4);
-                       hwif->dmaproc  = &triton_dmaproc;
+                       hwif->dma_base = base;
+                       if (dmatable == NULL) {
+                               /*
+                                * 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 = (void *) __get_dma_pages(GFP_KERNEL, 0);
+                       }
+                       if (dmatable != NULL) {
+                               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);
index c4d21dc48373cfcd8894b1a1370a314ceb955515..3d2db4ab35420b96b6643810e96a0b1124c9bb08 100644 (file)
@@ -1,4 +1,4 @@
-// 950824: note -- I will upload the new version 1.9 to ftp.ucsd.edu
+// 950913: note -- I will upload the new version 1.9a to ftp.ucsd.edu
 //         as soon as possible... 
 //
 // ******
@@ -7,13 +7,22 @@
 //
 // please remake /dev/sc*:
 //
-// mknod /dev/sc1 c 34 0
-// mknod /dev/sc2 c 34 1
-// mknod /dev/sc3 c 34 2
-// mknod /dev/sc4 c 34 3
+// mknod /dev/scc0 c 34 0
+// mknod /dev/scc1 c 34 1
+// mknod /dev/scc2 c 34 2
+// mknod /dev/scc3 c 34 3
 //
 // (and so on...)
 //
+// If you want to use the old device naming scheme use:
+//
+// ln -f /dev/scc0 /dev/sc1
+// ln -f /dev/scc1 /dev/sc2
+// ln -f /dev/scc2 /dev/sc3
+// ln -f /dev/scc3 /dev/sc4
+//
+// (you get the idea...)
+//
 // -dl1bke-
 
 
index 94908d6cd226db6c1fae9e769b2e98b18556d185..56c24d401f7a8f1ed4b0866e5ad3ce5e60e9b6e8 100644 (file)
@@ -26,6 +26,7 @@ char kernel_version[] = UTS_RELEASE;
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/mouse.h>
+#include <linux/random.h>
 
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -89,6 +90,7 @@ void mouse_interrupt(int irq, struct pt_regs * regs)
        outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */
        buttons = inb( ATIXL_MSE_DATA_PORT);
        if (dx != 0 || dy != 0 || buttons != mouse.latch_buttons) {
+               add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
                mouse.latch_buttons |= buttons;
                mouse.dx += dx;
                mouse.dy += dy;
index 27b0866f759c9e323ee4c83f75c86a0c5415f9ca..ad4579ac3192886cd4a96210c89e23ffc5168db7 100644 (file)
@@ -46,6 +46,7 @@ char kernel_version[] = UTS_RELEASE;
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/mouse.h>
+#include <linux/random.h>
 
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -78,6 +79,7 @@ static void mouse_interrupt(int irq, struct pt_regs *regs)
        dy |= (buttons & 0xf) << 4;
        buttons = ((buttons >> 5) & 0x07);
        if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
+         add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
          mouse.buttons = buttons;
          mouse.dx += dx;
          mouse.dy -= dy;
index 485524eba1f4925ae1196374a2a46ac689fbc372..8441ca9482ad845b5d5755eedbdcc3416ae49fb4 100644 (file)
@@ -373,9 +373,7 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs)
                prev_scancode = 0;
                goto end_kbd_intr;
        }
-#ifdef CONFIG_RANDOM
        add_keyboard_randomness(scancode);
-#endif
 
        tty = ttytab[fg_console];
        kbd = kbd_table + fg_console;
index bfdb021707da67d40460bfc7cce200b487d1bf9d..8c5ed824c61e8625fda4f14a4dc94a0a1cf68e92 100644 (file)
@@ -233,7 +233,6 @@ static int memory_lseek(struct inode * inode, struct file * file, off_t offset,
 #define mmap_kmem      mmap_mem
 #define zero_lseek     null_lseek
 #define write_zero     write_null
-#define write_random   write_null
 
 static struct file_operations ram_fops = {
        memory_lseek,
@@ -324,15 +323,14 @@ static struct file_operations full_fops = {
        NULL            /* no special release code */
 };
 
-#ifdef CONFIG_RANDOM
 static struct file_operations random_fops = {
        memory_lseek,
        read_random,
        write_random,
-       NULL,           /* full_readdir */
-       NULL,           /* full_select */
-       NULL,           /* full_ioctl */        
-       NULL,           /* full_mmap */
+       NULL,           /* random_readdir */
+       NULL,           /* random_select */
+       random_ioctl,
+       NULL,           /* random_mmap */
        NULL,           /* no special open code */
        NULL            /* no special release code */
 };
@@ -341,14 +339,13 @@ static struct file_operations urandom_fops = {
        memory_lseek,
        read_random_unlimited,
        write_random,
-       NULL,           /* full_readdir */
-       NULL,           /* full_select */
-       NULL,           /* full_ioctl */        
-       NULL,           /* full_mmap */
+       NULL,           /* urandom_readdir */
+       NULL,           /* urandom_select */
+       random_ioctl,
+       NULL,           /* urandom_mmap */
        NULL,           /* no special open code */
        NULL            /* no special release code */
 };
-#endif
 
 static int memory_open(struct inode * inode, struct file * filp)
 {
@@ -374,14 +371,12 @@ static int memory_open(struct inode * inode, struct file * filp)
                case 7:
                        filp->f_op = &full_fops;
                        break;
-#ifdef CONFIG_RANDOM
                case 8:
                        filp->f_op = &random_fops;
                        break;
                case 9:
                        filp->f_op = &urandom_fops;
                        break;
-#endif
                default:
                        return -ENODEV;
        }
@@ -407,9 +402,7 @@ int chr_dev_init(void)
 {
        if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
                printk("unable to get major %d for memory devs\n", MEM_MAJOR);
-#ifdef CONFIG_RANDOM
        rand_initialize();
-#endif
        tty_init();
 #ifdef CONFIG_PRINTER
        lp_init();
index 9b2f6dc8bb69a20ac22694f68028f08df00ba045..9411abdd5b658c86b473e5d337d0698353f2accb 100644 (file)
@@ -48,6 +48,7 @@ char kernel_version[] = UTS_RELEASE;
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/mouse.h>
+#include <linux/random.h>
 
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -77,6 +78,7 @@ static void ms_mouse_interrupt(int irq, struct pt_regs * regs)
        outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
 
        if (dx != 0 || dy != 0 || buttons != mouse.buttons || ((~buttons) & 0x07)) {
+               add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
                mouse.buttons = buttons;
                mouse.dx += dx;
                mouse.dy += dy;
index 432e0d01f8de592ab34362a75c77dd0ccbaa1afe..23599c4db3a3bbde9bf02991029a2cd8ff313b84 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/timer.h>
 #include <linux/malloc.h>
 #include <linux/mouse.h>
+#include <linux/random.h>
 
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -221,7 +222,7 @@ static void aux_interrupt(int cpl, struct pt_regs * regs)
        if ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL)
                return;
 
-       queue->buf[head] = inb(AUX_INPUT_PORT);
+       add_mouse_randomness(queue->buf[head] = inb(AUX_INPUT_PORT));
        if (head != maxhead) {
                head++;
                head &= AUX_BUF_SIZE-1;
@@ -244,7 +245,7 @@ static void qp_interrupt(int cpl, struct pt_regs * regs)
        int head = queue->head;
        int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
 
-       queue->buf[head] = inb(qp_data);
+       add_mouse_randomness(queue->buf[head] = inb(qp_data));
        if (head != maxhead) {
                head++;
                head &= AUX_BUF_SIZE-1;
index 992b4f04655f277cb55ad88c5cdad56b963e0030..e395d00dff824e765a6c8f8a31b8994433c5d86d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * random.c -- A strong random number generator
  *
- * Version 0.92, last modified 21-Sep-95
+ * Version 0.94, last modified 11-Oct-95
  * 
  * Copyright Theodore Ts'o, 1994, 1995.  All rights reserved.
  *
  * timings, inter-interrupt timings from some interrupts, and other
  * events which are both (a) non-deterministic and (b) hard for an
  * outside observer to measure.  Randomness from these sources are
- * added to an "entropy pool", which is periodically mixed using the
- * MD5 compression function in CBC mode.  As random bytes are mixed
- * into the entropy pool, the routines keep an *estimate* of how many
- * bits of randomness have been stored into the random number
- * generator's internal state.
+ * added to an "entropy pool", which is mixed using a CRC-like function.
+ * This is not cryptographically strong, but it is adequate assuming
+ * the randomness is not chosen maliciously, and it is fast enough that
+ * the overhead of doing it on every interrupt is very reasonable.
+ * As random bytes are mixed into the entropy pool, the routines keep
+ * an *estimate* of how many bits of randomness have been stored into
+ * the random number generator's internal state.
  * 
  * When random bytes are desired, they are obtained by taking the MD5
- * hash of a counter plus the contents of the "entropy pool".  The
- * reason for the MD5 hash is so that we can avoid exposing the
- * internal state of random number generator.  Although the MD5 hash
- * does protect the pool, as each random byte which is generated from
- * the pool reveals some information which was derived from the
- * internal state, and thus increasing the amount of information an
- * outside attacker has available to try to make some guesses about
- * the random number generator's internal state.  For this reason,
- * the routine decreases its internal estimate of how many bits of
- * "true randomness" are contained in the entropy pool as it outputs
- * random numbers.
+ * hash of the contents of the "entropy pool".  The MD5 hash avoids
+ * exposing the internal state of the entropy pool.  It is believed to
+ * be computationally infeasible to derive any useful information
+ * about the input of MD5 from its output.  Even if it is possible to
+ * analyze MD5 in some clever way, as long as the amount of data
+ * returned from the generator is less than the inherent entropy in
+ * the pool, the output data is totally unpredictable.  For this
+ * reason, the routine decreases its internal estimate of how many
+ * bits of "true randomness" are contained in the entropy pool as it
+ * outputs random numbers.
  * 
- * If this estimate goes to zero, the routine can still generate random
- * numbers; however it may now be possible for an attacker to analyze
- * the output of the random number generator, and the MD5 algorithm,
- * and thus have some success in guessing the output of the routine.
- * Phil Karn (who devised this mechanism of using MD5 plus a counter
- * to extract random numbers from an entropy pool) calls this
- * "practical randomness", since in the worse case this is equivalent
- * to hashing MD5 with a counter and an undisclosed secret.  If MD5 is
- * a strong cryptographic hash, this should be fairly resistant to attack.
+ * If this estimate goes to zero, the routine can still generate
+ * random numbers; however, an attacker may (at least in theory) be
+ * able to infer the future output of the generator from prior
+ * outputs.  This requires successful cryptanalysis of MD5, which is
+ * not believed to be feasible, but there is a remote possiblility.
+ * Nonetheless, these numbers should be useful for the vast majority
+ * of purposes.
  * 
  * Exported interfaces ---- output
  * ===============================
  * 
  * The two other interfaces are two character devices /dev/random and
  * /dev/urandom.  /dev/random is suitable for use when very high
- * quality randomness is desired (for example, for key generation.),
- * as it will only return a maximum of the number of bits of
- * randomness (as estimated by the random number generator) contained
- * in the entropy pool.
+ * quality randomness is desired (for example, for key generation or
+ * one-time pads), as it will only return a maximum of the number of
+ * bits of randomness (as estimated by the random number generator)
+ * contained in the entropy pool.
  * 
  * The /dev/urandom device does not have this limit, and will return
  * as many bytes as are requested.  As more and more random bytes are
  * requested without giving time for the entropy pool to recharge,
- * this will result in lower quality random numbers.  For many
- * applications, however, this is acceptable.
+ * this will result in random numbers that are merely cryptographically
+ * strong.  For many applications, however, this is acceptable.
  *
  * Exported interfaces ---- input
  * ==============================
- *
- * The two current exported interfaces for gathering environmental
- * noise from the devices are:
+ * 
+ * The current exported interfaces for gathering environmental noise
+ * from the devices are:
  * 
  *     void add_keyboard_randomness(unsigned char scancode);
+ *     void add_mouse_randomness(__u32 mouse_data);
  *     void add_interrupt_randomness(int irq);
+ *     void add_blkdev_randomness(int irq);
  * 
- * The first function uses the inter-keypress timing, as well as the
+ * add_keyboard_randomness() uses the inter-keypress timing, as well as the
  * scancode as random inputs into the "entropy pool".
+ * 
+ * add_mouse_randomness() uses the mouse interrupt timing, as well as
+ * the reported position of the mouse from the hardware.
  *
- * The second function uses the inter-interrupt timing as random
+ * add_interrupt_randomness() uses the inter-interrupt timing as random
  * inputs to the entropy pool.  Note that not all interrupts are good
  * sources of randomness!  For example, the timer interrupts is not a
  * good choice, because the periodicity of the interrupts is to
  * regular, and hence predictable to an attacker.  Disk interrupts are
  * a better measure, since the timing of the disk interrupts are more
- * unpredictable.  The routines try to estimate how many bits of
- * randomness a particular interrupt channel offers, by keeping track
- * of the first and second order deltas in the interrupt timings.
+ * unpredictable.
+ * 
+ * add_blkdev_randomness() times the finishing time of block requests.
+ * 
+ * All of these routines try to estimate how many bits of randomness a
+ * particular randomness source.  They do this by keeping track of the
+ * first and second order deltas of the event timings.
  *
  * Acknowledgements:
  * =================
- * 
+ *
  * Ideas for constructing this random number generator were derived
  * from the Pretty Good Privacy's random number generator, and from
- * private discussions with Phil Karn.  This design has been further
- * modified by myself, so any flaws are solely my responsibility, and
- * should not be attributed to the authors of PGP or to Phil.
+ * private discussions with Phil Karn.  Colin Plumb provided a faster
+ * random number generator, which speed up the mixing function of the
+ * entropy pool, taken from PGP 3.0 (under development).  It has since
+ * been modified by myself to provide better mixing in the case where
+ * the input values to add_entropy_word() are mostly small numbers.
+ * 
+ * Any flaws in the design are solely my responsibility, and should
+ * not be attributed to the Phil, Colin, or any of authors of PGP.
  * 
  * The code for MD5 transform was taken from Colin Plumb's
  * implementation, which has been placed in the public domain.  The
  * Eastlake, Steve Crocker, and Jeff Schiller.
  */
 
-#ifdef linux
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
 #include <linux/random.h>
 
 #include <asm/segment.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#endif
 
-#ifdef CONFIG_RANDOM
-
-#define RANDPOOL 512
+/*
+ * The pool is stirred with a primitive polynomial of degree 128
+ * over GF(2), namely x^128 + x^119 + x^72 + x^64 + x^14 + x^8 + 1.
+ * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
+ */
+#define POOLWORDS 128    /* Power of 2 - note that this is 32-bit words */
+#define POOLBITS (POOLWORDS*32)
+#if POOLWORDS == 128
+#define TAP1    119     /* The polynomial taps */
+#define TAP2    72
+#define TAP3    64
+#define TAP4    14
+#define TAP5    8
+#elif POOLWORDS == 64
+#define TAP1    62      /* The polynomial taps */
+#define TAP2    38
+#define TAP3    10
+#define TAP4    6
+#define TAP5    1
+#else
+#error No primitive polynomial available for chosen POOLWORDS
+#endif
 
+/* There is actually only one of these, globally. */
 struct random_bucket {
-       int add_ptr;
-       int entropy_count;
-       int length;
-       int bit_length;
-       int delay_mix:1;
-       __u8 *pool;
+       unsigned add_ptr;
+       unsigned entropy_count;
+       int input_rotate;
+       __u32 *pool;
 };
 
+/* There is one of these per entropy source */
 struct timer_rand_state {
        unsigned long   last_time;
        int             last_delta;
@@ -191,34 +223,206 @@ struct timer_rand_state {
 };
 
 static struct random_bucket random_state;
-static __u32 rand_pool_key[16];
-static __u8 random_pool[RANDPOOL];
-static __u32 random_counter[16];
+static __u32 random_pool[POOLWORDS];
 static struct timer_rand_state keyboard_timer_state;
-static struct timer_rand_state irq_timer_state[NR_IRQS];
+static struct timer_rand_state mouse_timer_state;
+static struct timer_rand_state extract_timer_state;
+static struct timer_rand_state *irq_timer_state[NR_IRQS];
+static struct timer_rand_state *blkdev_timer_state[MAX_BLKDEV];
+static struct wait_queue *random_wait;
 
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
        
-static void flush_random(struct random_bucket *random_state)
+void rand_initialize(void)
+{
+       random_state.add_ptr = 0;
+       random_state.entropy_count = 0;
+       random_state.pool = random_pool;
+       memset(irq_timer_state, 0, sizeof(irq_timer_state));
+       memset(blkdev_timer_state, 0, sizeof(blkdev_timer_state));
+       random_wait = NULL;}
+
+void rand_initialize_irq(int irq)
 {
-       random_state->add_ptr = 0;
-       random_state->bit_length = random_state->length * 8;
-       random_state->entropy_count = 0;
-       random_state->delay_mix = 0;
+       if (irq >= NR_IRQS || irq_timer_state[irq])
+               return;
+
+       /*
+        * If kamlloc returns null, we just won't use that entropy
+        * source.
+        */
+       irq_timer_state[irq] = kmalloc(sizeof(struct timer_rand_state), 
+                                      GFP_KERNEL);
 }
 
-void rand_initialize(void)
+void rand_initialize_blkdev(int major)
 {
-       random_state.length = RANDPOOL;
-       random_state.pool = random_pool;
-       flush_random(&random_state);
+       if (major >= MAX_BLKDEV || blkdev_timer_state[major])
+               return;
+
+       /*
+        * If kamlloc returns null, we just won't use that entropy
+        * source.
+        */
+       blkdev_timer_state[major] = kmalloc(sizeof(struct timer_rand_state), 
+                                           GFP_KERNEL);
+}
+
+/*
+ * This function adds a byte into the entropy "pool".  It does not
+ * update the entropy estimate.  The caller must do this if appropriate.
+ *
+ * The pool is stirred with a primitive polynomial of degree 128
+ * over GF(2), namely x^128 + x^119 + x^72 + x^64 + x^14 + x^8 + 1.
+ * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
+ * 
+ * We rotate the input word by a changing number of bits, to help
+ * assure that all bits in the entropy get toggled.  Otherwise, if we
+ * consistently feed the entropy pool small numbers (like jiffies and
+ * scancodes, for example), the upper bits of the entropy pool don't
+ * get affected. --- TYT, 10/11/95
+ */
+static inline void add_entropy_word(struct random_bucket *r,
+                                   const __u32 input)
+{
+       unsigned i;
+       __u32 w;
+
+       w = (input << r->input_rotate) | (input >> (32 - r->input_rotate));
+       i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1);
+       if (i)
+               r->input_rotate = (r->input_rotate + 7) & 31;
+       else
+               /*
+                * At the beginning of the pool, add an extra 7 bits
+                * rotation, so that successive passes spread the
+                * input bits across the pool evenly.
+                */
+               r->input_rotate = (r->input_rotate + 14) & 31;
+
+       /* XOR in the various taps */
+       w ^= r->pool[(i+TAP1)&(POOLWORDS-1)];
+       w ^= r->pool[(i+TAP2)&(POOLWORDS-1)];
+       w ^= r->pool[(i+TAP3)&(POOLWORDS-1)];
+       w ^= r->pool[(i+TAP4)&(POOLWORDS-1)];
+       w ^= r->pool[(i+TAP5)&(POOLWORDS-1)];
+       w ^= r->pool[i];
+       /* Rotate w left 1 bit (stolen from SHA) and store */
+       r->pool[i] = (w << 1) | (w >> 31);
+}
+
+/*
+ * This function adds entropy to the entropy "pool" by using timing
+ * delays.  It uses the timer_rand_state structure to make an estimate
+ * of how many bits of entropy this call has added to the pool.
+ *
+ * The number "num" is also added to the pool - it should somehow describe
+ * the type of event which just happened.  This is currently 0-255 for
+ * keyboard scan codes, and 256 upwards for interrupts.
+ * On the i386, this is assumed to be at most 16 bits, and the high bits
+ * are used for a high-resolution timer.
+ *
+ * TODO: Read the time stamp register on the Pentium.
+ */
+static void add_timer_randomness(struct random_bucket *r,
+                                struct timer_rand_state *state, unsigned num)
+{
+       int     delta, delta2;
+       unsigned        nbits;
+       __u32           time;
+
+#if defined (__i386__)
+       if (x86_capability & 16) {
+               unsigned long low, high;
+               __asm__(".byte 0x0f,0x31"
+                       :"=a" (low), "=d" (high));
+               time = (__u32) low;
+               num ^= (__u32) high;
+       } else {
+#if 0
+               /*
+                * On a 386, read the high resolution timer.  We assume that
+                * this gives us 2 bits of randomness.
+                *
+                * This is turned off for now because of the speed hit
+                * it entails.
+                */ 
+               outb_p(0x00, 0x43);     /* latch the count ASAP */
+               num |= inb_p(0x40) << 16;
+               num |= inb(0x40) << 24;
+               r->entropy_count += 2;
+#endif
+               
+               time = jiffies;
+       }
+#else
+       time = jiffies;
+#endif
+
+       add_entropy_word(r, (__u32) num);
+       add_entropy_word(r, time);
+
+       /*
+        * Calculate number of bits of randomness we probably
+        * added.  We take into account the first and second order
+        * deltas in order to make our estimate.
+        */
+       delta = time - state->last_time;
+       state->last_time = time;
+
+       delta2 = delta - state->last_delta;
+       state->last_delta = delta;
+
+       if (delta < 0) delta = -delta;
+       if (delta2 < 0) delta2 = -delta2;
+       delta = MIN(delta, delta2) >> 1;
+       for (nbits = 0; delta; nbits++)
+               delta >>= 1;
+
+       r->entropy_count += nbits;
+       
+       /* Prevent overflow */
+       if (r->entropy_count > POOLBITS)
+               r->entropy_count = POOLBITS;
+       
+       wake_up_interruptible(&random_wait);    
+}
+
+void add_keyboard_randomness(unsigned char scancode)
+{
+       add_timer_randomness(&random_state, &keyboard_timer_state, scancode);
+}
+
+void add_mouse_randomness(__u32 mouse_data)
+{
+       add_timer_randomness(&random_state, &mouse_timer_state, mouse_data);
+}
+
+void add_interrupt_randomness(int irq)
+{
+       if (irq >= NR_IRQS || irq_timer_state[irq] == 0)
+               return;
+
+       add_timer_randomness(&random_state, irq_timer_state[irq], 0x100+irq);
+}
+
+void add_blkdev_randomness(int major)
+{
+       if (major >= MAX_BLKDEV || blkdev_timer_state[major] == 0)
+               return;
+
+       add_timer_randomness(&random_state, blkdev_timer_state[major],
+                            0x200+major);
 }
 
 /*
  * MD5 transform algorithm, taken from code written by Colin Plumb,
  * and put into the public domain
+ *
+ * QUESTION: Replace this with SHA, which as generally received better
+ * reviews from the cryptographic community?
  */
 
 /* The four core functions - F1 is optimized somewhat */
@@ -328,141 +532,10 @@ static void MD5Transform(__u32 buf[4],
 #undef F4
 #undef MD5STEP
 
-/*
- * The function signature should be take a struct random_bucket * as
- * input, but this makes tqueue unhappy.
- */
-static void mix_bucket(void *v)
-{
-       struct random_bucket *r = (struct random_bucket *) v;
-       int     i, num_passes;
-       __u32 *p;
-       __u32 iv[4];
-
-       r->delay_mix = 0;
-       
-       /* Start IV from last block of the random pool */
-       memcpy(iv, r->pool + r->length - sizeof(iv), sizeof(iv));
-
-       num_passes = r->length / 16;
-       for (i = 0, p = (__u32 *) r->pool; i < num_passes; i++) {
-               MD5Transform(iv, rand_pool_key);
-               iv[0] = (*p++ ^= iv[0]);
-               iv[1] = (*p++ ^= iv[1]);
-               iv[2] = (*p++ ^= iv[2]);
-               iv[3] = (*p++ ^= iv[3]);
-       }
-       memcpy(rand_pool_key, r->pool, sizeof(rand_pool_key));
-       
-       /* Wipe iv from memory */
-       memset(iv, 0, sizeof(iv));
-
-       r->add_ptr = 0;
-}
-
-/*
- * This function adds a byte into the entropy "pool".  It does not
- * update the entropy estimate.  The caller must do this if appropriate.
- */
-static inline void add_entropy_byte(struct random_bucket *r,
-                                   const __u8 ch,
-                                   int delay)
-{
-       if (!delay && r->delay_mix)
-               mix_bucket(r);
-       r->pool[r->add_ptr++] ^= ch;
-       if (r->add_ptr >= r->length) {
-               if (delay) {
-                       r->delay_mix = 1;
-                       r->add_ptr = 0;
-               } else
-                       mix_bucket(r);
-       }
-}
-
-/*
- * This function adds some number of bytes into the entropy pool and
- * updates the entropy count as appropriate.
- */
-void add_entropy(struct random_bucket *r, const __u8 *ptr,
-                int length, int entropy_level, int delay)
-{
-       while (length-- > 0)
-               add_entropy_byte(r, *ptr++, delay);
-               
-       r->entropy_count += entropy_level;
-       if (r->entropy_count > r->length*8)
-               r->entropy_count = r->length * 8;
-}
-
-/*
- * This function adds entropy to the entropy "pool" by using timing
- * delays.  It uses the timer_rand_state structure to make an estimate
- * of how many bits of entropy this call has added to the pool.
- */
-static void add_timer_randomness(struct random_bucket *r,
-                                struct timer_rand_state *state, int delay)
-{
-       int     delta, delta2;
-       int     nbits;
-
-       /*
-        * Calculate number of bits of randomness we probably
-        * added.  We take into account the first and second order
-        * delta's in order to make our estimate.
-        */
-       delta = jiffies - state->last_time;
-       delta2 = delta - state->last_delta;
-       state->last_time = jiffies;
-       state->last_delta = delta;
-       if (delta < 0) delta = -delta;
-       if (delta2 < 0) delta2 = -delta2;
-       delta = MIN(delta, delta2) >> 1;
-       for (nbits = 0; delta; nbits++)
-               delta >>= 1;
-       
-       add_entropy(r, (__u8 *) &jiffies, sizeof(jiffies),
-                   nbits, delay);
 
-#if defined (__i386__)
-       /*
-        * On a Pentium, read the cycle counter. We assume that
-        * this gives us 8 bits of randomness.  XXX This needs
-        * investigation.
-        */
-       if (x86_capability & 16) {
-               unsigned long low, high;
-               __asm__(".byte 0x0f,0x31"
-                       :"=a" (low), "=d" (high));
-               add_entropy_byte(r, low, 1);
-               r->entropy_count += 8;
-               if (r->entropy_count > r->bit_length)
-                       r->entropy_count = r->bit_length;
-       }
+#if POOLWORDS % 16
+#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
 #endif
-}
-
-void add_keyboard_randomness(unsigned char scancode)
-{
-       struct random_bucket *r = &random_state;
-
-       add_timer_randomness(r, &keyboard_timer_state, 0);
-       add_entropy_byte(r, scancode, 0);
-       r->entropy_count += 6;
-       if (r->entropy_count > r->bit_length)
-               r->entropy_count = r->bit_length;
-}
-
-void add_interrupt_randomness(int irq)
-{
-       struct random_bucket *r = &random_state;
-
-       if (irq >= NR_IRQS)
-               return;
-
-       add_timer_randomness(r, &irq_timer_state[irq], 1);
-}
-
 /*
  * This function extracts randomness from the "entropy pool", and
  * returns it in a buffer.  This function computes how many remaining
@@ -472,41 +545,57 @@ void add_interrupt_randomness(int irq)
 static inline int extract_entropy(struct random_bucket *r, char * buf,
                                  int nbytes, int to_user)
 {
-       int length, ret, passes, i;
+       int ret, i;
        __u32 tmp[4];
-       u8 *cp;
        
-       add_entropy(r, (u8 *) &jiffies, sizeof(jiffies), 0, 0);
+       add_timer_randomness(r, &extract_timer_state, nbytes);
        
-       if (r->entropy_count > r->bit_length) 
-               r->entropy_count = r->bit_length;
+       /* Redundant, but just in case... */
+       if (r->entropy_count > POOLBITS) 
+               r->entropy_count = POOLBITS;
+       /* Why is this here?  Left in from Ted Ts'o.  Perhaps to limit time. */
        if (nbytes > 32768)
                nbytes = 32768;
+
        ret = nbytes;
-       r->entropy_count -= ret * 8;
-       if (r->entropy_count < 0)
+       if (r->entropy_count / 8 >= nbytes)
+               r->entropy_count -= nbytes*8;
+       else
                r->entropy_count = 0;
-       passes = r->length / 64;
+
        while (nbytes) {
-               length = MIN(nbytes, 16);
-               for (i=0; i < 16; i++) {
-                       if (++random_counter[i] != 0)
-                               break;
-               }
+               /* Hash the pool to get the output */
                tmp[0] = 0x67452301;
                tmp[1] = 0xefcdab89;
                tmp[2] = 0x98badcfe;
                tmp[3] = 0x10325476;
-               MD5Transform(tmp, random_counter);
-               for (i = 0, cp = r->pool; i < passes; i++, cp+=64)
-                       MD5Transform(tmp, (__u32 *) cp);
+               for (i = 0; i < POOLWORDS; i += 16)
+                       MD5Transform(tmp, r->pool+i);
+               /* Modify pool so next hash will produce different results */
+               add_entropy_word(r, tmp[0]);
+               add_entropy_word(r, tmp[1]);
+               add_entropy_word(r, tmp[2]);
+               add_entropy_word(r, tmp[3]);
+               /*
+                * Run the MD5 Transform one more time, since we want
+                * to add at least minimal obscuring of the inputs to
+                * add_entropy_word().  --- TYT
+                */
+               MD5Transform(tmp, r->pool);
+               
+               /* Copy data to destination buffer */
+               i = MIN(nbytes, 16);
                if (to_user)
-                       memcpy_tofs(buf, tmp, length);
+                       memcpy_tofs(buf, (__u8 const *)tmp, i);
                else
-                       memcpy(buf, tmp, length);
-               nbytes -= length;
-               buf += length;
+                       memcpy(buf, (__u8 const *)tmp, i);
+               nbytes -= i;
+               buf += i;
        }
+
+       /* Wipe data from memory */
+       memset(tmp, 0, sizeof(tmp));
+       
        return ret;
 }
 
@@ -520,20 +609,73 @@ void get_random_bytes(void *buf, int nbytes)
        extract_entropy(&random_state, (char *) buf, nbytes, 0);
 }
 
-#ifdef linux
-int read_random(struct inode * inode,struct file * file,char * buf,int nbytes)
+int read_random(struct inode * inode, struct file * file,
+                char * buf, int nbytes)
 {
-       if ((nbytes * 8) > random_state.entropy_count)
+       if (nbytes > random_state.entropy_count / 8)
                nbytes = random_state.entropy_count / 8;
        
        return extract_entropy(&random_state, buf, nbytes, 1);
 }
 
-int read_random_unlimited(struct inode * inode,struct file * file,
-                         char * buf,int nbytes)
+int read_random_unlimited(struct inode * inode, struct file * file,
+                         char * buf, int nbytes)
 {
        return extract_entropy(&random_state, buf, nbytes, 1);
 }
-#endif
 
-#endif /* CONFIG_RANDOM */
+int write_random(struct inode * inode, struct file * file,
+                const char * buffer, int count)
+{
+       int i;
+       __u32 word, *p;
+
+       for (i = count, p = (__u32 *)buffer;
+            i >= sizeof(__u32);
+            i-= sizeof(__u32), p++) {
+               memcpy_fromfs(&word, p, sizeof(__u32));
+               add_entropy_word(&random_state, word);
+       }
+       if (i) {
+               word = 0;
+               memcpy_fromfs(&word, p, i);
+               add_entropy_word(&random_state, word);
+       }
+       inode->i_mtime = CURRENT_TIME;
+       return count;
+}
+
+int random_ioctl(struct inode * inode, struct file * file,
+                       unsigned int cmd, unsigned long arg)
+{
+       int *p, max_size;
+       
+       switch (cmd) {
+       case RNDGETENTCNT:
+               put_user(random_state.entropy_count, (int *) arg);
+               return 0;
+       case RNDADDTOENTCNT:
+               if (!suser())
+                       return -EPERM;
+               random_state.entropy_count += get_user((int *) arg);
+               if (random_state.entropy_count > POOLBITS)
+                       random_state.entropy_count = POOLBITS;
+               return 0;
+       case RNDGETPOOL:
+               if (!suser())
+                       return -EPERM;
+               p = (int *) arg;
+               put_user(random_state.entropy_count, p);
+               max_size = get_user(++p);
+               put_user(POOLWORDS, p);
+               if (max_size < 0)
+                       return -EINVAL;
+               if (max_size > POOLWORDS)
+                       max_size = POOLWORDS;
+               memcpy_tofs(++p, random_state.pool,
+                           max_size*sizeof(__u32));
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
index f83abb52b852590aac27c5dd19596d15927512f8..ebcaec9b5bada6dd3b43bb5f256a2da9f36a9480 100644 (file)
@@ -406,6 +406,7 @@ void lance_probe1(int ioaddr)
 
        /* Make certain the data structures used by the LANCE are aligned and DMAble. */
        lp = (struct lance_private *) kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+       memset(lp, 0, sizeof(*lp));
        dev->priv = lp;
        lp->name = chipname;
        lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
index 47b002d4d821d58f789b75b21453c95b4271dfc4..cd20e0c018455fc7f29bd9db0e2a1cfca3360dff 100644 (file)
@@ -3143,8 +3143,8 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  * Validate the tty linkage
  */
        if (ppp->flags & SC_DEBUG)
-               printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n",
-                       dev->name, (int) skb);
+               printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n",
+                       dev->name, skb);
 /*
  * Validate the tty interface
  */
index 0944d193e9753a2a21ca286c7b9b0f51cc49e42a..16d41a91cc9eb57b7072e79bf66cdc53bb754905 100644 (file)
@@ -1198,7 +1198,24 @@ int aha1542_reset(Scsi_Cmnd * SCpnt)
         * we do this?  Try this first, and we can add that later
         * if it turns out to be useful.
         */
-       outb(SCRST, CONTROL(SCpnt->host->io_port));
+       outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+
+       /*
+        * Wait for the thing to settle down a bit.  Unfortunately
+        * this is going to basically lock up the machine while we
+        * wait for this to complete.  To be 100% correct, we need to
+        * check for timeout, and if we are doing something like this
+        * we are pretty desperate anyways.
+        */
+       WAIT(STATUS(SCpnt->host->io_port), 
+            STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+
+       /*
+        * We need to do this too before the 1542 can interact with
+        * us again.
+        */
+       setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
        /*
         * Now try and pick up the pieces.  Restart all commands
         * that are currently active on the bus, and reset all of
@@ -1226,6 +1243,12 @@ int aha1542_reset(Scsi_Cmnd * SCpnt)
         * then report SUCCESS.
         */
        return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+fail:
+       printk("aha1542.c: Unable to perform hard reset.\n");
+       printk("Power cycle machine to reset\n");
+       return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET);
+
+
       }
     else
       {
index 94a672c947063b124d1213491fc78e25a3f3d093..986b910a177beacdd71f3fe87698f9a79c4156f7 100644 (file)
@@ -181,28 +181,16 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
        scmd.channel = 0;
        scmd.use_sg = 0;
 
-       /* Used for mutex if loading devices after boot */
-       scmd.request.sem = NULL;
-       scmd.request.rq_status = RQ_SCSI_BUSY;
-       
-       scsi_do_cmd (&scmd, cmnd, buff + 0x144, 0x66,  
-                    eata_scsi_done, 1 * HZ, 1);
        /*
-        * Wait for command to finish. Use simple wait if we are
-        * booting, else do it right and use a mutex
+        * Do the command and wait for it to finish.
         */     
-       if (current->pid == 0) {
-           while (scmd.request.rq_status != RQ_SCSI_DONE)
-               barrier();
-       } else if (scmd.request.rq_status != RQ_SCSI_DONE) {
+       {
            struct semaphore sem = MUTEX_LOCKED;
-           
+           scmd.request.rq_status = RQ_SCSI_BUSY;
            scmd.request.sem = &sem;
+           scsi_do_cmd (&scmd, cmnd, buff + 0x144, 0x66,  
+                        eata_scsi_done, 1 * HZ, 1);
            down(&sem);
-           
-           /* Hmm.. Have to ask about this one */
-           while (scmd.request.rq_status != RQ_SCSI_DONE)
-             schedule();
        }
 
        size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
@@ -321,30 +309,18 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
  
        scmd.cmd_len = 10;
 
-       /* Used for mutex if loading devices after boot */
-       scmd.request.sem = NULL;
-       scmd.request.rq_status = RQ_SCSI_BUSY; /* Mark busy */
-       
-       scsi_do_cmd (&scmd, cmnd, buff2, 0x144,  
-                    eata_scsi_done, 1 * HZ, 1);
        /*
-        * Wait for command to finish. Use simple wait if we are
-        * booting, else do it right and use a mutex
+        * Do the command and wait for it to finish.
         */     
-       if (current->pid == 0)
-           while (scmd.request.rq_status != RQ_SCSI_DONE)
-               barrier();
-       else if (scmd.request.rq_status != RQ_SCSI_DONE) {
+       {
            struct semaphore sem = MUTEX_LOCKED;
-           
+           scmd.request.rq_status = RQ_SCSI_BUSY;
            scmd.request.sem = &sem;
+           scsi_do_cmd (&scmd, cmnd, buff2, 0x144,
+                        eata_scsi_done, 1 * HZ, 1);
            down(&sem);
-           
-           /* Hmm.. Have to ask about this one */
-           while (scmd.request.rq_status != RQ_SCSI_DONE)
-             schedule();
        }
-       
+
        swap_statistics(buff2);
        rhcs = (hst_cmd_stat *)(buff2 + 0x2c); 
        whcs = (hst_cmd_stat *)(buff2 + 0x8c);           
index 9417412089d366abee5894a2fe4906e82b77cb63..70f6d23d7a7a9c7000ee06288d3fbdce8773c186 100644 (file)
@@ -68,6 +68,13 @@ static int update_timeout (Scsi_Cmnd *, int);
 static void print_inquiry(unsigned char *data);
 static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid);
 
+static unsigned char * dma_malloc_freelist = NULL;
+static int scsi_need_isa_bounce_buffers;
+static unsigned int dma_sectors = 0;
+unsigned int dma_free_sectors = 0;
+unsigned int need_isa_buffer = 0;
+static unsigned char ** dma_malloc_pages = NULL;
+
 static int time_start;
 static int time_elapsed;
 static volatile struct Scsi_Host * host_active = NULL;
@@ -102,6 +109,7 @@ Scsi_Device * scsi_devices = NULL;
 unsigned long scsi_pid = 0;
 
 static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+static void resize_dma_pool(void);
 
 /* This variable is merely a hook so that we can debug the kernel with gdb. */
 Scsi_Cmnd * last_cmnd = NULL;
@@ -192,10 +200,8 @@ struct dev_info{
 
 /*
  * This is what was previously known as the blacklist.  The concept
- * has been expanded so that we can specify other 
- * The blacklist is used to determine which devices cannot tolerate a
- * lun probe because of buggy firmware.  Far too many for my liking,
- * which is why the default is now for there to be no lun scan. 
+ * has been expanded so that we can specify other types of things we
+ * need to be aware of.
  */
 static struct dev_info device_list[] =
 {
@@ -394,7 +400,7 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded,
     if(scsi_devices) while(SDtail->next) SDtail = SDtail->next;
     
     /* Make sure we have something that is valid for DMA purposes */
-    scsi_result = ((current->pid == 0  || !shpnt->unchecked_isa_dma)
+    scsi_result = ((!dma_malloc_freelist  || !shpnt->unchecked_isa_dma)
                   ?  &scsi_result0[0] : scsi_malloc(512));
     
     if(scsi_result == NULL) {
@@ -455,33 +461,19 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded,
                    SCpnt->lun = SDpnt->lun;
                    SCpnt->channel = SDpnt->channel;
 
-                   /* Used for mutex if loading devices after boot */
-                   SCpnt->request.sem = NULL;
-                   SCpnt->request.rq_status = RQ_SCSI_BUSY;
-                   
-                   scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
-                                (void *) scsi_result,
-                                256,  scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
-                   
-                   /* 
-                    * Wait for command to finish. Use simple wait if we are 
-                    * booting, else do it right and use a mutex 
-                    */
-                   
-                   if (current->pid == 0)
-                       while (SCpnt->request.rq_status != RQ_SCSI_DONE) 
-                           barrier();
-                   else if (SCpnt->request.rq_status != RQ_SCSI_DONE) {
+                   {
+                       /*
+                        * Do the actual command, and wait for it to finish
+                        */
                        struct semaphore sem = MUTEX_LOCKED;
-                       
                        SCpnt->request.sem = &sem;
+                       SCpnt->request.rq_status = RQ_SCSI_BUSY;
+                       scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
+                                    (void *) scsi_result,
+                                    256,  scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
                        down(&sem);
-                       
-                       /* Hmm.. Have to ask about this one */
-                       while (SCpnt->request.rq_status != RQ_SCSI_DONE)
-                           schedule();
                    }
-                   
+
 #if defined(DEBUG) || defined(DEBUG_INIT)
                    printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
                    printk("scsi: return code %08x\n", SCpnt->result);
@@ -515,25 +507,16 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded,
                    scsi_cmd[4] = 255;
                    scsi_cmd[5] = 0;
                    
-                   SCpnt->request.rq_status = RQ_SCSI_BUSY;
                    SCpnt->cmd_len = 0;
 
-                   scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
-                                (void *) scsi_result,
-                                256,  scan_scsis_done, SCSI_TIMEOUT, 3);
-                   
-                   if (current->pid == 0)
-                       while (SCpnt->request.rq_status != RQ_SCSI_DONE) 
-                           barrier();
-                   else if (SCpnt->request.rq_status != RQ_SCSI_DONE) {
+                   {
                        struct semaphore sem = MUTEX_LOCKED;
-                       
                        SCpnt->request.sem = &sem;
+                       SCpnt->request.rq_status = RQ_SCSI_BUSY;
+                       scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
+                                (void *) scsi_result,
+                                256,  scan_scsis_done, SCSI_TIMEOUT, 3);
                        down(&sem);
-                       
-                       /* Hmm.. Have to ask about this one */
-                       while (SCpnt->request.rq_status != RQ_SCSI_DONE)
-                         schedule();
                    }
                    
                    the_result = SCpnt->result;
@@ -689,24 +672,15 @@ void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded,
                                scsi_cmd[4] = 0x2a;
                                scsi_cmd[5] = 0;
                                
-                               SCpnt->request.rq_status = RQ_SCSI_BUSY;
                                SCpnt->cmd_len = 0;
-                               
-                               scsi_do_cmd (SCpnt, (void *)  scsi_cmd,
-                                            (void *) scsi_result, 0x2a,  
-                                            scan_scsis_done, SCSI_TIMEOUT, 3);
-                               
-                               if (current->pid == 0)
-                                   while (SCpnt->request.rq_status != RQ_SCSI_DONE);
-                               else if (SCpnt->request.rq_status != RQ_SCSI_DONE) {
+                               {
                                    struct semaphore sem = MUTEX_LOCKED;
-                                   
+                                   SCpnt->request.rq_status = RQ_SCSI_BUSY;
                                    SCpnt->request.sem = &sem;
+                                   scsi_do_cmd (SCpnt, (void *)  scsi_cmd,
+                                            (void *) scsi_result, 0x2a,  
+                                            scan_scsis_done, SCSI_TIMEOUT, 3);
                                    down(&sem);
-                                   
-                                   /* Hmm.. Have to ask about this one */
-                                   while (SCpnt->request.rq_status != RQ_SCSI_DONE) 
-                                       schedule();
                                }
                            }
                            /* Add this device to the linked list at the end */
@@ -1324,38 +1298,6 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
 #endif
 }
 
-
-
-/*
- * The scsi_done() function disables the timeout timer for the scsi host,
- * marks the host as not busy, and calls the user specified completion
- * function for that host's current command.
- */
-
-static void reset (Scsi_Cmnd * SCpnt)
-{
-#ifdef DEBUG
-    printk("scsi: reset(%d, channel %d)\n", SCpnt->host->host_no, 
-          SCpnt->channel);
-#endif
-
-    SCpnt->flags |= (WAS_RESET | IS_RESETTING);
-    scsi_reset(SCpnt, FALSE);
-
-#ifdef DEBUG
-    printk("performing request sense\n");
-#endif
-
-#if 0  /* FIXME - remove this when done */
-    if(SCpnt->flags & NEEDS_JUMPSTART) {
-       SCpnt->flags &= ~NEEDS_JUMPSTART;
-       scsi_request_sense (SCpnt);
-    }
-#endif
-}
-
-
-
 static int check_sense (Scsi_Cmnd * SCpnt)
 {
     /* If there is no sense information, request it.  If we have already
@@ -1493,7 +1435,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                       " failed, performing reset.\n",
                       SCpnt->host->host_no, SCpnt->channel, SCpnt->target, 
                       SCpnt->lun);
-               reset(SCpnt);
+               scsi_reset(SCpnt, FALSE);
                return;
            }
            else
@@ -1594,7 +1536,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
            case RESERVATION_CONFLICT:
                printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
                       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
-               reset(SCpnt);
+               scsi_reset(SCpnt, FALSE);
                return;
 #if 0
                exit = DRIVER_SOFT | SUGGEST_ABORT;
@@ -1709,7 +1651,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
            {
                printk("scsi%d channel %d : resetting for second half of retries.\n",
                       SCpnt->host->host_no, SCpnt->channel);
-               reset(SCpnt);
+               scsi_reset(SCpnt, FALSE);
                break;
            }
            
@@ -1928,13 +1870,16 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
      */
     SCpnt1 = host->host_queue;
     while(SCpnt1) {
-        if( SCpnt->request.rq_status != RQ_INACTIVE
-           && (SCpnt->flags & WAS_RESET) == 0 )
+       if( SCpnt1->request.rq_status != RQ_INACTIVE
+          && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
+       {
             break;
+       }
         SCpnt1 = SCpnt1->next;
        }
-    if( SCpnt1 == NULL )
+    if( SCpnt1 == NULL ) {
         SCpnt->host->suggest_bus_reset = TRUE;
+    }
     
     
     /*
@@ -1942,8 +1887,9 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
      * definitely request it.  This usually occurs because a
      * BUS_DEVICE_RESET times out.
      */
-    if( bus_reset_flag )
+    if( bus_reset_flag ) {
         SCpnt->host->suggest_bus_reset = TRUE;
+    }
     
     while (1) {
        save_flags(flags);
@@ -1970,7 +1916,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
                            !(SCpnt1->internal_timeout & IN_ABORT))
                            scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
 #endif
-                       SCpnt1->flags |= IS_RESETTING;
+                       SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
                    }
                    SCpnt1 = SCpnt1->next;
                }
@@ -1984,6 +1930,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
                if (!host->block) host->host_busy++;
                restore_flags(flags);
                host->last_reset = jiffies;
+               SCpnt->flags |= (WAS_RESET | IS_RESETTING);
                temp = host->hostt->reset(SCpnt);
                host->last_reset = jiffies;
                if (!host->block) host->host_busy--;
@@ -2176,13 +2123,6 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
     return oldto;
 }
 
-
-static unsigned char * dma_malloc_freelist = NULL;
-static int scsi_need_isa_bounce_buffers;
-static unsigned int dma_sectors = 0;
-unsigned int dma_free_sectors = 0;
-unsigned int need_isa_buffer = 0;
-static unsigned char ** dma_malloc_pages = NULL;
 #define MALLOC_PAGEBITS 12
 
 static int scsi_register_host(Scsi_Host_Template *);
@@ -2341,11 +2281,9 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
 
 int scsi_dev_init(void)
 {
-    struct Scsi_Host * host = NULL;
     Scsi_Device * SDpnt;
     struct Scsi_Host * shpnt;
     struct Scsi_Device_Template * sdtpnt;
-    int i;
 #ifdef FOO_ON_YOU
     return;
 #endif
@@ -2391,50 +2329,13 @@ int scsi_dev_init(void)
     }
     
 
-    if (scsi_devicelist)
-       dma_sectors = 16;  /* Base value we use */
-    
-    if (high_memory-1 > ISA_DMA_THRESHOLD)
-       scsi_need_isa_bounce_buffers = 1;
-    else
-       scsi_need_isa_bounce_buffers = 0;
-    
-    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
-       host = SDpnt->host;
-       
-       if(SDpnt->type != TYPE_TAPE)
-           dma_sectors += ((host->sg_tablesize *
-                            sizeof(struct scatterlist) + 511) >> 9) *
-                                host->cmd_per_lun;
-       
-       if(host->unchecked_isa_dma &&
-          high_memory - 1 > ISA_DMA_THRESHOLD &&
-          SDpnt->type != TYPE_TAPE) {
-           dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-               host->cmd_per_lun;
-           need_isa_buffer++;
-       }
-    }
-    
-    dma_sectors = (dma_sectors + 15) & 0xfff0;
-    dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
-
-    if (dma_sectors)
-    {
-       dma_malloc_freelist = (unsigned char *)
-           scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
-       memset(dma_malloc_freelist, 0, dma_sectors >> 3);
-
-       dma_malloc_pages = (unsigned char **)
-           scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
-       memset(dma_malloc_pages, 0, dma_sectors >> 1);
+    /*
+     * This should build the DMA pool.
+     */
+    resize_dma_pool();
 
-       for(i=0; i< dma_sectors >> 3; i++)
-           dma_malloc_pages[i] = (unsigned char *)
-               scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-    
-    }
-    /* OK, now we finish the initialization by doing spin-up, read
+    /*
+     * OK, now we finish the initialization by doing spin-up, read
      * capacity, etc, etc 
      */
     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
@@ -2576,6 +2477,126 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
 }
 #endif
 
+/*
+ * Go through the device list and recompute the most appropriate size
+ * for the dma pool.  Then grab more memory (as required).
+ */
+static void resize_dma_pool(void)
+{
+    int i;
+    struct Scsi_Host * shpnt;
+    struct Scsi_Host * host = NULL;
+    Scsi_Device * SDpnt;
+    unsigned long flags;
+    unsigned char * new_dma_malloc_freelist = NULL;
+    unsigned int new_dma_sectors = 0;
+    unsigned int new_need_isa_buffer = 0;
+    unsigned char ** new_dma_malloc_pages = NULL;
+
+    if( !scsi_devices )
+    {
+       /*
+        * Free up the DMA pool.
+        */
+       if( dma_free_sectors != dma_sectors )
+           panic("SCSI DMA pool memory leak\n");
+
+       for(i=0; i < dma_sectors >> 3; i++)
+           scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
+       if (dma_malloc_pages)
+           scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+       dma_malloc_pages = NULL;
+       if (dma_malloc_freelist)
+           scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+       dma_malloc_freelist = NULL;
+       dma_sectors = 0;
+       dma_free_sectors = 0;
+       return;
+    }
+    /* Next, check to see if we need to extend the DMA buffer pool */
+       
+    new_dma_sectors = 16;  /* Base value we use */
+
+    if (high_memory-1 > ISA_DMA_THRESHOLD)
+       scsi_need_isa_bounce_buffers = 1;
+    else
+       scsi_need_isa_bounce_buffers = 0;
+    
+    if (scsi_devicelist)
+       for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+           new_dma_sectors += 8;  /* Increment for each host */
+    
+    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
+       host = SDpnt->host;
+       
+       if(SDpnt->type != TYPE_TAPE)
+           new_dma_sectors += ((host->sg_tablesize *
+                                sizeof(struct scatterlist) + 511) >> 9) *
+                                    host->cmd_per_lun;
+       
+       if(host->unchecked_isa_dma &&
+          scsi_need_isa_bounce_buffers &&
+          SDpnt->type != TYPE_TAPE) {
+           new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+               host->cmd_per_lun;
+           new_need_isa_buffer++;
+       }
+    }
+    
+    new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+    
+    /*
+     * We never shrink the buffers - this leads to
+     * race conditions that I would rather not even think
+     * about right now.
+     */
+    if( new_dma_sectors < dma_sectors )
+       new_dma_sectors = dma_sectors;
+    
+    if (new_dma_sectors)
+    {
+       new_dma_malloc_freelist = (unsigned char *)
+           scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
+       memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
+       
+       new_dma_malloc_pages = (unsigned char **)
+           scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
+       memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
+    }
+    
+    /*
+     * If we need more buffers, expand the list.
+     */
+    if( new_dma_sectors > dma_sectors ) { 
+       for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
+           new_dma_malloc_pages[i] = (unsigned char *)
+               scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+    }
+    
+    /* When we dick with the actual DMA list, we need to 
+     * protect things 
+     */
+    save_flags(flags);
+    cli();
+    if (dma_malloc_freelist)
+    {
+       memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
+       scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+    }
+    dma_malloc_freelist = new_dma_malloc_freelist;
+    
+    if (dma_malloc_pages)
+    {
+       memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
+       scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+    }
+    
+    dma_free_sectors += new_dma_sectors - dma_sectors;
+    dma_malloc_pages = new_dma_malloc_pages;
+    dma_sectors = new_dma_sectors;
+    need_isa_buffer = new_need_isa_buffer;
+    restore_flags(flags);
+}
 
 /*
  * This entry point should be called by a loadable module if it is trying
@@ -2585,11 +2606,8 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
 {
     int pcount;
     struct Scsi_Host * shpnt;
-    struct Scsi_Host * host = NULL;
-    unsigned long flags;
     Scsi_Device * SDpnt;
     struct Scsi_Device_Template * sdtpnt;
-    int i;
     const char * name;
     
     if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
@@ -2653,90 +2671,12 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
                if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
            }
        
-       /* Next, check to see if we need to extend the DMA buffer pool */
-    {
-       unsigned char * new_dma_malloc_freelist = NULL;
-       unsigned int new_dma_sectors = 0;
-       unsigned int new_need_isa_buffer = 0;
-       unsigned char ** new_dma_malloc_pages = NULL;
-       
-       new_dma_sectors = 16;  /* Base value we use */
-       if (scsi_devicelist)
-           for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-               new_dma_sectors += 8;  /* Increment for each host */
-       
-       for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
-           host = SDpnt->host;
-           
-           if(SDpnt->type != TYPE_TAPE)
-               new_dma_sectors += ((host->sg_tablesize *
-                                    sizeof(struct scatterlist) + 511) >> 9) *
-                                        host->cmd_per_lun;
-           
-           if(host->unchecked_isa_dma &&
-              scsi_need_isa_bounce_buffers &&
-              SDpnt->type != TYPE_TAPE) {
-               new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-                   host->cmd_per_lun;
-               new_need_isa_buffer++;
-           }
-       }
-       
-       new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
-       
        /*
-        * We never shrink the buffers - this leads to
-        * race conditions that I would rather not even think
-        * about right now.
-        */
-       if( new_dma_sectors < dma_sectors )
-           new_dma_sectors = dma_sectors;
-
-       if (new_dma_sectors)
-       {
-           new_dma_malloc_freelist = (unsigned char *)
-               scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
-           memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
-
-           new_dma_malloc_pages = (unsigned char **)
-               scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
-           memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
-       }
+        * Now that we have all of the devices, resize the DMA pool,
+        * as required.  */
+       resize_dma_pool();
 
-       /*
-        * If we need more buffers, expand the list.
-        */
-       if( new_dma_sectors > dma_sectors ) { 
-           for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
-               new_dma_malloc_pages[i] = (unsigned char *)
-             scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-       }
-       
-       /* When we dick with the actual DMA list, we need to 
-        * protect things 
-        */
-       save_flags(flags);
-       cli();
-       if (dma_malloc_freelist)
-       {
-           memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
-           scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
-       }
-       dma_malloc_freelist = new_dma_malloc_freelist;
-       
-       if (dma_malloc_pages)
-       {
-           memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
-           scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-       }
 
-       dma_free_sectors += new_dma_sectors - dma_sectors;
-       dma_malloc_pages = new_dma_malloc_pages;
-       dma_sectors = new_dma_sectors;
-       need_isa_buffer = new_need_isa_buffer;
-       restore_flags(flags);
-    }
-       
        /* This does any final handling that is required. */
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
            if(sdtpnt->finish && sdtpnt->nr_dev)
@@ -2749,7 +2689,7 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
            (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
            (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
-    
+       
     MOD_INC_USE_COUNT;
     return 0;
 }
@@ -2869,6 +2809,14 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
        shpnt = sh1;
     }
     
+    /*
+     * If there are absolutely no more hosts left, it is safe
+     * to completely nuke the DMA pool.  The resize operation will
+     * do the right thing and free everything.
+     */
+    if( !scsi_devices )
+       resize_dma_pool();
+
     printk ("scsi : %d host%s.\n", next_scsi_host,
            (next_scsi_host == 1) ? "" : "s");
     
@@ -3165,13 +3113,8 @@ void cleanup_module( void)
     /*
      * Free up the DMA pool.
      */
-    for(i=0; i < dma_sectors >> 3; i++)
-       scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
-    if (dma_malloc_pages)
-       scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-    if (dma_malloc_freelist)
-       scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
-    
+    resize_dma_pool();
+
     timer_table[SCSI_TIMER].fn = NULL;
     timer_table[SCSI_TIMER].expires = 0;
     /*
index dc112b0f404b6bb09ff119858c50d2b910cb2878..f7d0d2c3e16b5ba85da14bde678325d01802cbad 100644 (file)
@@ -113,18 +113,14 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
     Scsi_Cmnd * SCpnt;
     
     SCpnt = allocate_device(NULL, dev, 1);
-    scsi_do_cmd(SCpnt,  cmd, NULL,  0,
-               scsi_ioctl_done,  MAX_TIMEOUT,
-               MAX_RETRIES);
-    
-    if (SCpnt->request.rq_status != RQ_SCSI_DONE){
+    {
        struct semaphore sem = MUTEX_LOCKED;
        SCpnt->request.sem = &sem;
+       scsi_do_cmd(SCpnt,  cmd, NULL,  0,
+                   scsi_ioctl_done,  MAX_TIMEOUT,
+                   MAX_RETRIES);
        down(&sem);
-       /* Hmm.. Have to ask about this one */
-       while (SCpnt->request.rq_status != RQ_SCSI_DONE)
-           schedule();
-    };
+    }
     
     if(driver_byte(SCpnt->result) != 0)
        switch(SCpnt->sense_buffer[2] & 0xf) {
@@ -248,20 +244,15 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
 #ifndef DEBUG_NO_CMD
     
     SCpnt = allocate_device(NULL, dev, 1);
-    
-    scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,  MAX_TIMEOUT, 
-               MAX_RETRIES);
-    
-    if (SCpnt->request.rq_status != RQ_SCSI_DONE){
+
+    {
        struct semaphore sem = MUTEX_LOCKED;
        SCpnt->request.sem = &sem;
+       scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,  MAX_TIMEOUT, 
+                   MAX_RETRIES);
        down(&sem);
-       /* Hmm.. Have to ask about this one */
-       while (SCpnt->request.rq_status != RQ_SCSI_DONE)
-           schedule();
     }
     
-    
     /* 
      * If there was an error condition, pass the info back to the user. 
      */
index e58a127cd70eace9693394f3135cc90602f648d0..7003aa5de4aee11d49de5dddf69ad6e579bc5ee6 100644 (file)
@@ -112,6 +112,22 @@ static int sd_open(struct inode * inode, struct file * filp)
     if(rscsi_disks[target].device->removable) {
        check_disk_change(inode->i_rdev);
        
+       /*
+        * If the drive is empty, just let the open fail.
+        */
+       if ( !rscsi_disks[target].ready ) {
+           return -ENXIO;
+       }
+
+       /*
+        * Similarily, if the device has the write protect tab set,
+        * have the open fail if the user expects to be able to write
+        * to the thing.
+        */
+       if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) ) { 
+           return -EROFS;
+       }
+
        if(!rscsi_disks[target].device->access_count)
            sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
     };
@@ -904,11 +920,20 @@ static int check_scsidisk_media_change(kdev_t full_dev){
                 * and we will figure it out later once the drive is
                 * available again.  */
        
+       rscsi_disks[target].ready = 0;
        rscsi_disks[target].device->changed = 1;
        return 1; /* This will force a flush, if called from
                   * check_disk_change */
     };
     
+    /* 
+     * for removable scsi disk ( FLOPTICAL ) we have to recognise the
+     * presence of disk in the drive. This is kept in the Scsi_Disk
+     * struct and tested at open !  Daniel Roche ( dan@lectra.fr ) 
+     */
+    
+    rscsi_disks[target].ready = 1;     /* FLOPTICAL */
+
     retval = rscsi_disks[target].device->changed;
     if(!flag) rscsi_disks[target].device->changed = 0;
     return retval;
@@ -945,7 +970,7 @@ static int sd_init_onedisk(int i)
     spintime = 0;
     
     /* Spin up drives, as required.  Only do this at boot time */
-    if (current->pid == 0){
+    if (!MODULE_FLAG){
        do{
            retries = 0;
            while(retries < 3)
@@ -953,18 +978,22 @@ static int sd_init_onedisk(int i)
                cmd[0] = TEST_UNIT_READY;
                cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
                memset ((void *) &cmd[2], 0, 8);
-               SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Mark as really busy again */
                SCpnt->cmd_len = 0;
                SCpnt->sense_buffer[0] = 0;
                SCpnt->sense_buffer[2] = 0;
-               
-               scsi_do_cmd (SCpnt,
-                            (void *) cmd, (void *) buffer,
-                            512, sd_init_done,  SD_TIMEOUT,
-                            MAX_RETRIES);
-               
-               while(SCpnt->request.rq_status != RQ_SCSI_DONE) barrier();
-               
+
+               {
+                   struct semaphore sem = MUTEX_LOCKED;
+                   /* Mark as really busy again */
+                   SCpnt->request.rq_status = RQ_SCSI_BUSY;
+                   SCpnt->request.sem = &sem;
+                   scsi_do_cmd (SCpnt,
+                                (void *) cmd, (void *) buffer,
+                                512, sd_init_done,  SD_TIMEOUT,
+                                MAX_RETRIES);
+                   down(&sem);
+               }
+
                the_result = SCpnt->result;
                retries++;
                if(   the_result == 0
@@ -984,22 +1013,24 @@ static int sd_init_onedisk(int i)
                    cmd[1] |= 1;  /* Return immediately */
                    memset ((void *) &cmd[2], 0, 8);
                    cmd[4] = 1; /* Start spin cycle */
-                   /* Mark as really busy again */
-                   SCpnt->request.rq_status = RQ_SCSI_BUSY; 
                    SCpnt->cmd_len = 0;
                    SCpnt->sense_buffer[0] = 0;
                    SCpnt->sense_buffer[2] = 0;
                    
-                   scsi_do_cmd (SCpnt,
-                                (void *) cmd, (void *) buffer,
-                                512, sd_init_done,  SD_TIMEOUT,
-                                MAX_RETRIES);
-                   
-                   while(SCpnt->request.rq_status != RQ_SCSI_DONE)
-                     barrier();
+                   {
+                       struct semaphore sem = MUTEX_LOCKED;
+                       /* Mark as really busy again */
+                       SCpnt->request.rq_status = RQ_SCSI_BUSY; 
+                       SCpnt->request.sem = &sem;
+                       scsi_do_cmd (SCpnt,
+                                    (void *) cmd, (void *) buffer,
+                                    512, sd_init_done,  SD_TIMEOUT,
+                                    MAX_RETRIES);
+                       down(&sem);
+                   }
                    
                    spintime = jiffies;
-               };
+               }
                
                time1 = jiffies;
                while(jiffies < time1 + HZ); /* Wait 1 second for next try */
@@ -1012,7 +1043,7 @@ static int sd_init_onedisk(int i)
            else
                printk( "ready\n" );
        }
-    };  /* current->pid == 0 */
+    };  /* !MODULE_FLAG */
     
     
     retries = 3;
@@ -1021,28 +1052,20 @@ static int sd_init_onedisk(int i)
        cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
        memset ((void *) &cmd[2], 0, 8);
        memset ((void *) buffer, 0, 8);
-       SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Mark as really busy again */
        SCpnt->cmd_len = 0;
        SCpnt->sense_buffer[0] = 0;
        SCpnt->sense_buffer[2] = 0;
-       
-       scsi_do_cmd (SCpnt,
-                    (void *) cmd, (void *) buffer,
-                    8, sd_init_done,  SD_TIMEOUT,
-                    MAX_RETRIES);
-       
-       if (current->pid == 0) {
-           while(SCpnt->request.rq_status != RQ_SCSI_DONE)
-             barrier();
-       } else {
-           if (SCpnt->request.rq_status != RQ_SCSI_DONE){
-               struct semaphore sem = MUTEX_LOCKED;
-               SCpnt->request.sem = &sem;
-               down(&sem);
-               /* Hmm.. Have to ask about this one.. */
-               while (SCpnt->request.rq_status != RQ_SCSI_DONE) 
-                 schedule();
-           }
+
+       {
+           struct semaphore sem = MUTEX_LOCKED;
+           /* Mark as really busy again */
+           SCpnt->request.rq_status = RQ_SCSI_BUSY;
+           SCpnt->request.sem = &sem;
+           scsi_do_cmd (SCpnt,
+                        (void *) cmd, (void *) buffer,
+                        8, sd_init_done,  SD_TIMEOUT,
+                        MAX_RETRIES);
+           down(&sem); /* sleep until it is ready */
        }
        
        the_result = SCpnt->result;
@@ -1100,6 +1123,11 @@ static int sd_init_onedisk(int i)
     }
     else
     {
+       /*
+        * FLOPTICAL , if read_capa is ok , drive is assumed to be ready 
+        */
+       rscsi_disks[i].ready = 1;
+
        rscsi_disks[i].capacity = (buffer[0] << 24) |
            (buffer[1] << 16) |
                (buffer[2] << 8) |
@@ -1144,6 +1172,57 @@ static int sd_init_onedisk(int i)
            rscsi_disks[i].capacity >>= 1;  /* Change into 512 byte sectors */
     }
     
+
+    /*
+     * Unless otherwise specified, this is not write protected.
+     */
+    rscsi_disks[i].write_prot = 0;
+    if ( rscsi_disks[i].device->removable && rscsi_disks[i].ready ) {
+       /* FLOPTICAL */
+
+       /* 
+        *      for removable scsi disk ( FLOPTICAL ) we have to recognise  
+        * the Write Protect Flag. This flag is kept in the Scsi_Disk struct
+        * and tested at open !
+        * Daniel Roche ( dan@lectra.fr )
+        */
+       
+       memset ((void *) &cmd[0], 0, 8);
+       cmd[0] = MODE_SENSE;
+       cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+       cmd[2] = 1;      /* page code 1 ?? */
+       cmd[4] = 12;
+       SCpnt->cmd_len = 0;
+       SCpnt->sense_buffer[0] = 0;
+       SCpnt->sense_buffer[2] = 0;
+
+       /* same code as READCAPA !! */
+       {
+           struct semaphore sem = MUTEX_LOCKED;
+           SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Mark as really busy again */
+           SCpnt->request.sem = &sem;
+           scsi_do_cmd (SCpnt,
+                        (void *) cmd, (void *) buffer,
+                        512, sd_init_done,  SD_TIMEOUT,
+                        MAX_RETRIES);
+           down(&sem);
+       }
+       
+       the_result = SCpnt->result;
+       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+       wake_up(&SCpnt->device->device_wait); 
+       
+       if ( the_result ) {
+           printk ("sd%c: test WP failed, assume Write Protected\n",i+'a');
+           rscsi_disks[i].write_prot = 1;
+       } else {
+           rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0);
+           printk ("sd%c: Write Protect is %s\n",i+'a',
+                   rscsi_disks[i].write_prot ? "on" : "off");
+       }
+       
+    }  /* check for write protect */
     rscsi_disks[i].ten = 1;
     rscsi_disks[i].remap = 1;
     scsi_free(buffer, 512);
index f0fcd714bd7f37745dc32f414584fb0766f79ef9..8e2031e679454beae11c61ebb41016a620296a78 100644 (file)
@@ -29,6 +29,8 @@ typedef struct scsi_disk {
     unsigned capacity;             /* size in blocks */
     unsigned sector_size;          /* size in bytes */
     Scsi_Device         *device;           
+    unsigned char ready;           /* flag ready for FLOPTICAL */
+    unsigned char write_prot;      /* flag write_protect for rmvable dev */
     unsigned char sector_bit_size;  /* sector_size = 2 to the  bit size power */
     unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
     unsigned ten:1;                /* support ten byte read / write */
index e3047dfab26ba40f279d6af846bb77fff762cd53..3992f44ad0a36c6ae484a81064ea19243e2c3ffd 100644 (file)
@@ -989,24 +989,17 @@ static void get_sectorsize(int i){
        SCpnt->cmd_len = 0;
        
        memset(buffer, 0, 8);
-       
-       scsi_do_cmd (SCpnt,
-                    (void *) cmd, (void *) buffer,
-                    512, sr_init_done,  SR_TIMEOUT,
-                    MAX_RETRIES);
-       
-       if (current->pid == 0)
-           while(SCpnt->request.rq_status != RQ_SCSI_DONE)
-               barrier();
-       else
-           if (SCpnt->request.rq_status != RQ_SCSI_DONE){
-               struct semaphore sem = MUTEX_LOCKED;
-               SCpnt->request.sem = &sem;
-               down(&sem);
-               /* Hmm.. Have to ask about this */
-               while (SCpnt->request.rq_status != RQ_SCSI_DONE)
-                   schedule();
-           };
+
+       /* Do the command and wait.. */
+       {
+           struct semaphore sem = MUTEX_LOCKED;
+           SCpnt->request.sem = &sem;
+           scsi_do_cmd (SCpnt,
+                        (void *) cmd, (void *) buffer,
+                        512, sr_init_done,  SR_TIMEOUT,
+                        MAX_RETRIES);
+           down(&sem);
+       }
        
        the_result = SCpnt->result;
        retries--;
index 297cae5a93012473f2656a4a1223c33191324636..1d7a325b65417414e10e91c2ce4dd879b7b1d676 100644 (file)
@@ -44,21 +44,16 @@ static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned
 {
     Scsi_Cmnd * SCpnt;
     int result;
-    
+
     SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
-    scsi_do_cmd(SCpnt,
-               (void *) sr_cmd, buffer, buflength, sr_ioctl_done, 
-               IOCTL_TIMEOUT, IOCTL_RETRIES);
-    
-    
-    if (SCpnt->request.rq_status != RQ_SCSI_DONE){
+    {
        struct semaphore sem = MUTEX_LOCKED;
        SCpnt->request.sem = &sem;
+       scsi_do_cmd(SCpnt,
+                   (void *) sr_cmd, buffer, buflength, sr_ioctl_done, 
+                   IOCTL_TIMEOUT, IOCTL_RETRIES);
        down(&sem);
-       /* Hmm.. Have to ask about this */
-       while (SCpnt->request.rq_status != RQ_SCSI_DONE)
-         schedule();
-    };
+    }
     
     result = SCpnt->result;
     
index d2f5ac8d4fa5e60b3fdfc673a8564aceca2f832d..9d32a17d1e85f58d9ed84544c36638b41beff2b3 100644 (file)
@@ -1171,6 +1171,9 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
                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);
@@ -1247,8 +1250,6 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
                }
            }
 #endif
-       if (snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster", sb_osp) < 0)
-         printk ("sb_dsp: Can't allocate IRQ\n");;
       }
     else
       printk ("SB: Too many DSP devices available\n");
index a97159fa60f60053506ce600f9823d89b887ee09..23c1f82f2c4af2872c1ff5ce72c640891ad0a0a0 100644 (file)
@@ -210,13 +210,28 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
        
        elf_phdata =  (struct elf_phdr *) 
                kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
-       if(!elf_phdata) return 0xffffffff;
+       if(!elf_phdata)
+         return 0xffffffff;
        
+       /*
+        * If the size of this structure has changed, then punt, since
+        * we will be doing the wrong thing.
+        */
+       if( interp_elf_ex->e_phentsize != 32 )
+         {
+           kfree(elf_phdata);
+           return 0xffffffff;
+         }
+
        retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
                           sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
        
        elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
-       if (elf_exec_fileno < 0) return 0xffffffff;
+       if (elf_exec_fileno < 0) {
+         kfree(elf_phdata);
+         return 0xffffffff;
+       }
+
        file = current->files->fd[elf_exec_fileno];
 
        eppnt = elf_phdata;
@@ -425,8 +440,18 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        
        for(i=0;i < elf_ex.e_phnum; i++){
                if(elf_ppnt->p_type == PT_INTERP) {
-                       /* This is the program interpreter used for shared libraries - 
-                          for now assume that this is an a.out format binary */
+                       if( elf_interpreter != NULL )
+                       {
+                               kfree (elf_phdata);
+                               kfree(elf_interpreter);
+                               MOD_DEC_USE_COUNT;
+                               return -EINVAL;
+                       }
+
+                       /* This is the program interpreter used for
+                        * shared libraries - for now assume that this
+                        * is an a.out format binary 
+                        */
                        
                        elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, 
                                                           GFP_KERNEL);
@@ -475,12 +500,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        /* Some simple consistency checks for the interpreter */
        if(elf_interpreter){
                interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-               if(retval < 0) {
-                       kfree(elf_interpreter);
-                       kfree(elf_phdata);
-                       MOD_DEC_USE_COUNT;
-                       return -ELIBACC;
-               }
+
                /* Now figure out which format our binary is */
                if((N_MAGIC(interp_ex) != OMAGIC) && 
                   (N_MAGIC(interp_ex) != ZMAGIC) &&
@@ -569,6 +589,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                  kfree(elf_interpreter);
                        
                  if(elf_entry == 0xffffffff) { 
+                   set_fs(old_fs);
                    printk("Unable to load interpreter\n");
                    kfree(elf_phdata);
                    send_sig(SIGSEGV, current, 0);
@@ -600,7 +621,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                        if(k > start_code) start_code = k;
                        k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
                        if(k > elf_bss) elf_bss = k;
-                       if((elf_ppnt->p_flags | PROT_WRITE) && end_code <  k)
+                       if((elf_ppnt->p_flags | PF_W) && end_code <  k)
                                end_code = k; 
                        if(end_data < k) end_data = k; 
                        k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
index 36c58b1a8350aa96882601e881b0d7c90e230502..f19737b4cfe21f36c4c563a3ec62cdade5662bde 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: aztcd.h,v 1.70 1995/08/19 16:16:45 root Exp root $
+/* $Id: aztcd.h,v 1.80 1995/10/11 19:39:18 root Exp root $
  *
  * Definitions for a AztechCD268 CD-ROM interface
  *     Copyright (C) 1994, 1995  Werner Zimmermann
@@ -58,6 +58,7 @@
 /*---------------------------------------------------------------------------*/
 /*-----nothing to be configured for normal applications below this line------*/
 
+
 /* Increase this if you get lots of timeouts; if you get kernel panic, replace
    STEN_LOW_WAIT by STEN_LOW in the source code */
 #define AZT_STATUS_DELAY       400       /*for timer wait, STEN_LOW_WAIT*/
index c3c700e929a0ca6c4fb403a6b32272fda332817f..f4e75908a1b9504411a89b71c71fd664c70c5c9b 100644 (file)
@@ -39,7 +39,7 @@
  * 19 - cyclades /dev/ttyC*
  * 20 - cyclades /dev/cub*     mitsumi (mcdx) cdrom
  * 21 - scsi generic
- * 22 - Z8530 driver           ide1
+ * 22 -                        ide1
  * 23 -                        mitsumi cdrom
  * 24 -                               sony535 cdrom
  * 25 -                        matsushita cdrom       minors 0..3
@@ -49,7 +49,7 @@
  * 29 -                        aztech/orchid/okano/wearnes cdrom
  * 32 -                        philips/lms cm206 cdrom
  * 33 -                        ide2
- * 34 -                        ide3
+ * 34 - z8530 driver           ide3
  */
 
 #define UNNAMED_MAJOR  0
@@ -79,7 +79,7 @@
 #define CYCLADESAUX_MAJOR 20
 #define MITSUMI_X_CDROM_MAJOR 20
 #define SCSI_GENERIC_MAJOR 21
-#define Z8530_MAJOR 22
+#define Z8530_MAJOR 34
 #define IDE1_MAJOR     22
 #define MITSUMI_CDROM_MAJOR 23
 #define CDU535_CDROM_MAJOR 24
index 2f31076a1dab4f14ecd2e66dc78ed964e5163453..9dfde32cf59501eb0686062282bc9ea9d760fea8 100644 (file)
@@ -4,33 +4,44 @@
  * Include file for the random number generator.
  */
 
-/*
- * We should always include the random number generator, since it's
- * relatively small, and it's most useful when application developers
- * can assume that all Linux systems have it.  (Ideally, it would be
- * best if we could assume that all Unix systems had it, but oh
- * well....)
- * 
- * Also, many kernel routines will have a use for good random numbers,
- * for example, for truely random TCP sequence numbers, which prevent
- * certain forms of TCP spoofing attacks.
- */
-#define CONFIG_RANDOM
+#ifndef _LINUX_RANDOM_H
+#define _LINUX_RANDOM_H
+
+/* ioctl()'s for the random number generator */
+
+#define RNDGETENTCNT   0x01080000
+#define RNDADDTOENTCNT 0x01080001
+#define RNDGETPOOL     0x01080002
+
+struct rand_pool_state {
+       int     entropy_count;
+       int     pool_size;
+       __u32   pool[0];
+};
 
 /* Exported functions */
 
-#ifdef CONFIG_RANDOM
+#ifdef __KERNEL__
+
 void rand_initialize(void);
+void rand_initialize_irq(int irq);
+void rand_initialize_blkdev(int irq);
 
 void add_keyboard_randomness(unsigned char scancode);
+void add_mouse_randomness(__u32 mouse_data);
 void add_interrupt_randomness(int irq);
+void add_blkdev_randomness(int major);
 
 void get_random_bytes(void *buf, int nbytes);
 int read_random(struct inode * inode, struct file * file,
                char * buf, int nbytes);
 int read_random_unlimited(struct inode * inode, struct file * file,
                          char * buf, int nbytes);
-#else
-#define add_keyboard_randomness(x)
-#define add_interrupt_randomness(x)
-#endif
+int write_random(struct inode * inode, struct file * file,
+                const char * buffer, int count);
+int random_ioctl(struct inode * inode, struct file * file,
+                unsigned int cmd, unsigned long arg);
+
+#endif /* __KERNEL___ */
+
+#endif /* _LINUX_RANDOM_H */
index d5a697681f4e4503f9ac324efe8008cdbe884490..223dd25972c1ad299959be4a54fdef9f4420e059 100644 (file)
@@ -31,7 +31,7 @@ struct rpc_wait {
        int                     *buf;
        int                     len;
        char                    gotit;
-       u32                     xid;
+       __u32                   xid;
 };
 
 struct rpc_sock {
index d6302e2e4adbeb484eebd8c0c8629acdf752ef6b..707616025e87b6f2111452882b4b91f699d43570 100644 (file)
@@ -1,46 +1,76 @@
-/* -- sjcd.h
- *
- * Definitions for a Sanyo CD-ROM interface
+/*
+ * Definitions for a Sanyo CD-ROM interface.
  *
  *   Copyright (C) 1995  Vadim V. Model
+ *                                       model@cecmow.enet.dec.com
+ *                                       vadim@rbrf.msk.su
+ *                                       vadim@ipsun.ras.ru
+ *                       Eric van der Maarel
+ *                                       maarel@marin.nl
+ *
+ *  This information is based on mcd.c from M. Harriss and sjcd102.lst from
+ *  E. Moenkeberg.
  *
- *   model@cecmow.enet.dec.com
- *   vadim@rbrf.msk.su
- *   vadim@ipsun.ras.ru
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef __SJCD_H__
 #define __SJCD_H__
 
 /*
- * Change this to set the I/O port address.
+ * Change this to set the I/O port address as default. More flexibility
+ * come with setup implementation.
  */
 #define SJCD_BASE_ADDR      0x340
 
 /*
- * Change this to set the irq.
+ * Change this to set the irq as default. Really SANYO do not use interrupts
+ * at all.
  */
-#define SJCD_INTR_NR        10
+#define SJCD_INTR_NR        0
 
 /*
- * Change this to set the dma channel.
+ * Change this to set the dma as default value. really SANYO does not use
+ * direct memory access at all.
  */
-#define SJCD_DMA            0
+#define SJCD_DMA_NR         0
 
 /*
- * port access macros
+ * Macros which allow us to find out the status of the drive.
  */
-#define SJCDPORT( x )       ( sjcd_port + ( x ) )
+#define SJCD_STATUS_AVAILABLE( x ) (((x)&0x02)==0)
+#define SJCD_DATA_AVAILABLE( x )   (((x)&0x01)==0)
 
-/* status bits */
+/*
+ * Port access macro. Three ports are available: S-data port (command port),
+ * status port (read only) and D-data port (read only).
+ */
+#define SJCDPORT( x )       ( sjcd_port + ( x ) )
+#define SJCD_STATUS_PORT    SJCDPORT( 1 )
+#define SJCD_S_DATA_PORT    SJCDPORT( 0 )
+#define SJCD_COMMAND_PORT   SJCDPORT( 0 )
+#define SJCD_D_DATA_PORT    SJCDPORT( 2 )
 
-#define SST_NOT_READY       0x10        /* no disk in the drive */
+/*
+ * Drive info bits. Drive info available as first (mandatory) byte of
+ * command completion status.
+ */
+#define SST_NOT_READY       0x10        /* no disk in the drive (???) */
 #define SST_MEDIA_CHANGED   0x20        /* disk is changed */
 #define SST_DOOR_OPENED     0x40        /* door is open */
 
-/* flag bits */
-
 /* commands */
 
 #define SCMD_EJECT_TRAY     0xD0        /* eject tray if not locked */
@@ -52,7 +82,7 @@
 #define SCMD_GET_STATUS     0x80
 #define SCMD_GET_VERSION    0xCC
 
-#define SCMD_DATA_READ      0xA0
+#define SCMD_DATA_READ      0xA0        /* are the same, depend on mode&args */
 #define SCMD_SEEK           0xA0
 #define SCMD_PLAY           0xA0
 
 
 #define SCMD_SET_MODE       0xC4
 #define SCMD_MODE_PLAY      0xE0
-#define SCMD_MODE_COOKED    0xF8
+#define SCMD_MODE_COOKED    (0xF8 & ~0x20)
 #define SCMD_MODE_RAW       0xF9
-#define SCMD_MODE_x20_BIT   0x20
+#define SCMD_MODE_x20_BIT   0x20        /* What is it for ? */
 
 #define SCMD_SET_VOLUME     0xAE
 #define SCMD_PAUSE          0xE0
 #define SCMD_STOP           0xE0
 
 #define SCMD_GET_DISK_INFO  0xAA
+
+/*
+ * Some standard arguments for SCMD_GET_DISK_INFO.
+ */
 #define SCMD_GET_1_TRACK    0xA0    /* get the first track information */
 #define SCMD_GET_L_TRACK    0xA1    /* get the last track information */
 #define SCMD_GET_D_SIZE     0xA2    /* get the whole disk information */
 
 /*
- * borrowed from hd.c
+ * Borrowed from hd.c. Allows to optimize multiple port read commands.
  */
 #define S_READ_DATA( port, buf, nr )      insb( port, buf, nr )
 
+/*
+ * We assume that there are no audio disks with TOC lenght more than this
+ * number (I personally have never seen disks with morethan 20 fragments).
+ */
 #define SJCD_MAX_TRACKS                100
 
 struct msf {
@@ -124,6 +162,8 @@ struct sjcd_toc {
   struct msf      disk_time;
 };
 
+#if defined( SJCD_GATHER_STAT )
+
 struct sjcd_stat {
   int ticks;
   int tticks[ 8 ];
@@ -137,3 +177,5 @@ struct sjcd_stat {
 };
 
 #endif
+
+#endif
index 48c61f250397bbf7308bd7ada96b289c6e0a4a1d..c6d79b3e3f87e41d1d25c794d9b95d40dcc210ec 100644 (file)
@@ -529,6 +529,8 @@ int get_module_list(char *buf)
                if (p - buf > 4096 - 100)
                        break;                  /* avoid overflowing buffer */
                q = mp->name;
+               if (*q == '\0' && mp->size == 0 && mp->ref == NULL)
+                       continue; /* don't list modules for kernel syms */
                i = 20;
                while (*q) {
                        *p++ = *q++;
index 6eb7153de541f0278e2e46e8bae0f8d0a3176882..d197ef35c1aee1de80df8c09613bb8cbe2e83352 100644 (file)
 #
 # 030995 (storner@osiris.ping.dk) - added support for tri-state answers,
 # for selecting modules to compile.
+#
+# 180995 Bernhard Kaindl (bkaindl@ping.at) - added dummy functions for
+# use with a config.in modified for make menuconfig.
+#
 
 #
 # Make sure we're really running bash.
 # Enable function cacheing.
 set -f -h
 
+#
+# Dummy functions for use with a config.in modified for menuconf
+#
+function mainmenu_option () {
+       :
+}
+function mainmenu_name () {
+       :
+}
+
 #
 # readln reads a line into $ans.
 #
diff --git a/scripts/Makefile b/scripts/Makefile
new file mode 100644 (file)
index 0000000..0c545bf
--- /dev/null
@@ -0,0 +1,28 @@
+HEADER=header.tk
+TAIL=tail.tk
+
+kconfig.tk: ../arch/${ARCH}/config.in tkparse ${HEADER} ${TAIL}
+       ./tkparse < ../arch/${ARCH}/config.in  > kconfig.tmp
+       cp ${HEADER} ./kconfig.tk
+       cat kconfig.tmp >> kconfig.tk
+       rm -f kconfig.tmp
+       cat ${TAIL} >> kconfig.tk
+       chmod 755 kconfig.tk
+
+
+tkparse: tkparse.o tkcond.o tkgen.o
+       ${HOSTCC} -o tkparse tkparse.o tkcond.o tkgen.o
+
+tkparse.o: tkparse.c tkparse.h
+       $(HOSTCC) $(HOSTCFLAGS) -c -o tkparse.o tkparse.c
+
+tkcond.o: tkcond.c tkparse.h
+       $(HOSTCC) $(HOSTCFLAGS) -c -o tkcond.o tkcond.c
+
+tkgen.o: tkgen.c tkparse.h
+       $(HOSTCC) $(HOSTCFLAGS) -c -o tkgen.o tkgen.c
+
+clean:
+       rm -f kconfig.tk *.o parse
+
+include $(TOPDIR)/Rules.make
diff --git a/scripts/header.tk b/scripts/header.tk
new file mode 100644 (file)
index 0000000..5131cbb
--- /dev/null
@@ -0,0 +1,337 @@
+#!/usr/bin/wish -f
+
+#
+# Used to determine size of canvas inserted for booleans. It holds the
+# place where the 'm' button goes in a tristate, and keeps the look and feel
+# consistent.
+#
+set modbutton_width 0
+set modbutton_height 0
+
+
+#
+# Define some macros we will need to parse the kmenu-config.dat file.
+#
+proc mainmenu_name { text } {
+       message .header.message -width 400 -relief raised -bg grey -text "$text"
+       pack .header.label .header.message -side left -padx 15
+        wm title . "$text"
+}
+
+proc menu_option { w menu_num text } {
+       button .f0.x$menu_num -text "$text" -width 50 -command "$w .$w \"$text\""
+       pack .f0.x$menu_num -anchor w -pady 1
+}
+
+#
+# Not used at the moment, but this runs a command in a subprocess and
+# displays the result in a window with a scrollbar.
+#
+proc do_cmd { w command } {
+       catch {destroy $w}
+       toplevel $w -class Dialog
+       frame $w.tb
+       text $w.tb.text -relief raised -bd 2 -yscrollcommand "$w.tb.scroll set"
+       scrollbar $w.tb.scroll -command "$w.tb.text yview"
+       pack $w.tb.scroll -side right -fill y
+       pack $w.tb.text -side left
+
+       set oldFocus [focus]
+       frame $w.back
+       button $w.back.ok -text "OK" -activebackground green -width 20 \
+               -command "destroy $w; focus $oldFocus" -state disabled
+       button $w.back.ccl -text "Cancel" -activebackground green -width 20 \
+               -command "destroy $w; focus $oldFocus"
+       pack $w.tb -side top
+       pack $w.back.ok $w.back.ccl -side left
+       pack $w.back -side bottom -pady 10
+
+       focus $w
+       wm geometry $w +30+35   
+
+       $w.tb.text delete 1.0 end
+       set f [open |$command]
+       while {![eof $f]} {
+               $w.tb.text insert end [read $f 256]
+       }
+       close $f
+       $w.back.ok configure -state normal
+}
+
+proc load_configfile { w title func } {
+       catch {destroy $w}
+       toplevel $w -class Dialog
+       global loadfile
+       frame $w.x
+       label $w.bm -bitmap questhead
+       pack  $w.bm -pady 10 -side top -padx 10
+       label $w.x.l -text "Enter filename:" -relief raised
+       entry $w.x.x -width 35 -relief sunken -borderwidth 2 \
+               -textvariable loadfile
+       pack $w.x.l $w.x.x -anchor w -side left
+       pack $w.x -side top -pady 10
+       wm title $w "$title" 
+
+       set oldFocus [focus]
+       frame $w.f
+       button $w.f.back -text "OK" -activebackground green -width 20 \
+               -command "destroy $w; focus $oldFocus;$func .fileio"
+       button $w.f.canc -text "Cancel" -activebackground red \
+               -width 20 -command "destroy $w; focus $oldFocus"
+       pack $w.f.back $w.f.canc -side left -pady 10 -padx 45
+       pack $w.f -pady 10 -side bottom -padx 10 -anchor w
+       focus $w
+       wm geometry $w +30+35   
+}
+
+proc read_config_file { w } {
+       global loadfile
+       if { [string length $loadfile] != 0 && [file readable $loadfile] == 1 } then {
+               read_config $loadfile
+       } else {
+               catch {destroy $w}
+               toplevel $w -class Dialog
+               message $w.m -width 400 -aspect 300 -text \
+                       "Unable to read file $loadfile" \
+                        -relief raised -fg black
+               label $w.bm -bitmap error
+               pack $w.bm $w.m -pady 10 -side top -padx 10
+               wm title $w "Oops" 
+
+               set oldFocus [focus]
+               frame $w.f
+               button $w.f.back -text "Bummer" -activebackground green \
+                       -width 10 -command "destroy $w; focus $oldFocus"
+               pack $w.f.back -side bottom -pady 10 -anchor s
+               pack $w.f -pady 10 -side top -padx 10 -anchor s
+               focus $w
+               wm geometry $w +30+35
+       }
+}
+
+proc write_config_file  { w } {
+       global loadfile
+       if { [string length $loadfile] != 0 && [file writable $loadfile] == 1 } then {
+               writeconfig $loadfile /dev/null
+       } else {
+               catch {destroy $w}
+               toplevel $w -class Dialog
+               message $w.m -width 400 -aspect 300 -text \
+                       "Unable to write file $loadfile" \
+                        -relief raised -fg black
+               label $w.bm -bitmap error
+               pack $w.bm $w.m -pady 10 -side top -padx 10
+               wm title $w "Oops" 
+
+               set oldFocus [focus]
+               frame $w.f
+               button $w.f.back -text "OK" -activebackground green \
+                       -width 10 -command "destroy $w; focus $oldFocus"
+               pack $w.f.back -side bottom -pady 10 -anchor s
+               pack $w.f -pady 10 -side top -padx 10 -anchor s
+               focus $w
+               wm geometry $w +30+35
+       }
+}
+
+proc read_config { filename } {
+       set file1 [open $filename r]
+       while { [gets $file1 line] >= 0} {
+               if [regexp {([0-9A-Z_]+)=([ynm])} $line foo var value] {
+                       if { $value == "y" } then { set cmd "global $var; set $var 1" }
+                       if { $value == "n" } then { set cmd "global $var; set $var 0" }
+                       if { $value == "m" } then { set cmd "global $var; set $var 2" }
+                       eval $cmd
+               }
+               if [regexp {# ([0-9A-Z_]+) is not set} $line foo var] {
+                       set cmd "global $var; set $var 0"
+                       eval $cmd
+               }
+       }
+       close $file1
+}
+proc write_comment { file1 file2 text } {
+       puts $file1 "#"
+       puts $file1 "# $text"
+       puts $file1 "#"
+       puts $file2 "/*"
+       puts $file2 " * $text"
+       puts $file2 " */"
+}
+
+proc write_variable { file1 file2 varname variable dep } {
+       if { $variable == 0 } \
+               then { puts $file1 "# $varname is not set"; \
+                      puts $file2 "#undef $varname"}
+       if { $variable == 2 || ($dep == 2 && $variable == 1) } \
+               then { puts $file1 "$varname=m"; \
+                      puts $file2 "#undef $varname"  }
+       if { $variable == 1 && $dep != 2 } \
+               then { puts $file1 "$varname=y"; \
+                      puts $file2 "#define $varname 1" }
+}
+
+proc bool {w mnum line text variable default} {
+       frame $w.x$line
+       global modbutton_width
+       global modbutton_height
+       radiobutton $w.x$line.y -text "y" -variable $variable -value 1 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       radiobutton $w.x$line.n -text "n"  -variable $variable -value 0 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       canvas $w.x$line.m -width $modbutton_width -relief raised \
+               -height $modbutton_height
+       button $w.x$line.help -text "Help" -relief raised \
+               -command "dohelp .dohelp $variable"
+       pack $w.x$line.y $w.x$line.m  -anchor w -side left
+       button $w.x$line.l -text "$text" -relief raised 
+       pack $w.x$line.n $w.x$line.help $w.x$line.l -anchor w -side left
+       pack $w.x$line -anchor w
+#
+# If we don't know the size yet, update the screen and calculate the size
+# of the 'm' button by measuring the size of the 'y' button.  The buttons
+# have fixed size anyways, so it should always be correct.
+#
+       if { $modbutton_width == 0 } then {
+               update
+               set modbutton_width [winfo width $w.x$line.y]
+               set modbutton_height [winfo height $w.x$line.y]
+               $w.x$line.m configure -height $modbutton_height \
+                       -width $modbutton_width
+       }
+}
+
+proc int { w mnum line text variable default } {
+       frame $w.x$line
+       button $w.x$line.help -text "Help" -relief raised \
+               -command "dohelp .dohelp $variable "
+       button $w.x$line.l -text "$text" -relief raised 
+       entry $w.x$line.x -width 15 -relief sunken -borderwidth 2 \
+               -textvariable $variable
+       pack $w.x$line.x $w.x$line.help $w.x$line.l -anchor w -side left
+       pack $w.x$line -anchor w
+}
+
+proc comment {w line text } {
+#nothing done for comments now.
+}
+
+proc do_make { w line option dir target target } {
+#nothing to do for now.
+}
+
+proc dohelp {w varname }  {
+       catch {destroy $w}
+       toplevel $w -class Dialog
+
+       set filefound 0
+       set found 0
+       if { [file readable Documentation/Configure.help] == 1} then {
+               set f [open Documentation/Configure.help r]
+               set filefound 1 
+               while {![eof $f]} {
+                       gets $f line
+                       set line1 [string trim $line]
+                       if { $line1 == $varname } then {
+                               set found 1
+                       } else {
+                               if { $found == 0 } continue 
+                       }
+                       if { [string length $line1 ] == 0 } break
+                       append message $line
+               }
+               close $f
+       }
+
+       if { $found == 0 } then {
+               if { $filefound == 0 } then {
+               message $w.m -width 400 -aspect 300 -text \
+                       "No help available - unable to open file Documentation/Configure.help"  -relief raised -fg black
+               } else {
+               message $w.m -width 400 -aspect 300 -text \
+                       "No help available for $varname"  -relief raised -fg black
+               }
+               label $w.bm -bitmap error
+               pack $w.bm $w.m -pady 10 -side top -padx 10
+               wm title $w "RTFM" 
+       } else {
+               message $w.m -width 400 -aspect 300 -text $message \
+                        -relief raised -fg black
+               label $w.bm -bitmap info
+               pack $w.bm $w.m -pady 10 -side top -padx 10
+               wm title $w "Configuration help" 
+       }
+       set oldFocus [focus]
+       frame $w.f
+       button $w.f.back -text "OK" -activebackground green \
+               -width 10 -command "destroy $w; focus $oldFocus"
+       pack $w.f.back -side bottom -pady 10 -anchor s
+       pack $w.f -pady 10 -side top -padx 10 -anchor s
+       focus $w
+       wm geometry $w +30+35
+}
+
+proc wrapup {w }  {
+       catch {destroy $w}
+       toplevel $w -class Dialog
+       message $w.m -width 400 -aspect 300 -text \
+               "The linux kernel is now hopefully configured for your setup. Check the top-level Makefile for additional configuration, and do a 'make dep ; make clean' if you want to be sure all the files are correctly re-made."  -relief raised -fg black
+       label $w.bm -bitmap info
+       pack $w.bm $w.m -pady 10 -side top -padx 10
+       wm title $w "Kernel build instructions" 
+
+       set oldFocus [focus]
+       frame $w.f
+       button $w.f.back -text "OK" -activebackground green \
+               -width 10 -command "exit"
+       pack $w.f.back -side bottom -pady 10 -anchor s
+       pack $w.f -pady 10 -side top -padx 10 -anchor s
+       focus $w
+       wm geometry $w +30+35
+
+}
+
+proc check_sound_config { num } {
+#nothing for now.
+}
+
+proc tristate {w mnum line text variable default} {
+       frame $w.x$line
+       radiobutton $w.x$line.y -text "y" -variable $variable -value 1 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       radiobutton $w.x$line.n -text "n"  -variable $variable -value 0 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       radiobutton $w.x$line.m -text "m"  -variable $variable -value 2 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       button $w.x$line.help -text "Help" -relief raised \
+               -command "dohelp .dohelp $variable"
+       button $w.x$line.l -text "$text" -relief raised 
+       pack $w.x$line.y $w.x$line.m $w.x$line.n $w.x$line.help $w.x$line.l -anchor w -side left
+       pack $w.x$line -anchor w
+}
+
+proc dep_tristate {w mnum line text variable default} {
+       frame $w.x$line
+       radiobutton $w.x$line.y -text "y" -variable $variable -value 1 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       radiobutton $w.x$line.n -text "n"  -variable $variable -value 0 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       radiobutton $w.x$line.m -text "m"  -variable $variable -value 2 \
+               -width 2 -command "update_menu$mnum .menu$mnum"
+       button $w.x$line.help -text "Help" -relief raised \
+               -command "dohelp .dohelp $variable"
+       button $w.x$line.l -text "$text" -relief raised 
+       pack $w.x$line.y $w.x$line.m $w.x$line.n $w.x$line.help $w.x$line.l -anchor w -side left
+       pack $w.x$line -anchor w
+}
+
+
+#
+# Next set up the particulars for the top level menu, and define a few
+# buttons which we will stick down at the bottom.
+#
+frame .header
+label .header.label 
+
+frame .f0 
+
diff --git a/scripts/tail.tk b/scripts/tail.tk
new file mode 100644 (file)
index 0000000..2981a99
--- /dev/null
@@ -0,0 +1,71 @@
+
+pack .header -side top -padx 10 -pady 10
+pack .f0 -side top -padx 15 -pady 10
+
+#
+# Misc buttons to save/restore state and so forth.
+# 
+frame .f0r_bot
+frame .f0l_bot
+
+#
+# Read the users settings from .config.  These wil override whatever is
+# in config.in.  Don't do this if the user specified a -D to force
+# the defaults.
+#
+if { [file readable .config] == 1} then {
+       if { $argc > 0 } then {
+               if { [lindex $argv 0] != "-D" } then {
+                       read_config .config
+               }
+       } else {
+               read_config .config
+       }
+}
+
+button .f0r_bot.save -text "Write Configuration" -width 25 -command {
+       writeconfig .config include/linux/autoconf.h; wrapup .wrap }
+
+button .f0r_bot.quit -text "Quit" -command { exit } -width 25 \
+       -activebackground red -activeforeground white
+
+button .f0l_bot.store -text "Store Configuration to file" -width 25 -command {
+       load_configfile .load "Store Configuration" write_config_file
+}
+
+button .f0l_bot.load -text "Load Configuration" -width 25 -command {
+       load_configfile .load "Load Configuration" read_config_file
+}
+
+pack  .f0r_bot.save .f0r_bot.quit -padx 25 -ipadx 10 -ipady 2 -anchor w
+
+pack  .f0l_bot.load .f0l_bot.store -padx 25 -ipadx 10 -ipady 2 -anchor w
+
+pack .f0r_bot .f0l_bot -side left -padx 15 -pady 10 -anchor w
+
+#
+# If we cannot write our config files, disable the write button.
+#
+if { [file exists .config] == 1 } then {
+               if { [file writable .config] == 0 } then {
+                       .f0r_bot.save configure -state disabled
+               }
+       } else {
+               if { [file writable .] == 0 } then {
+                       .f0r_bot.save configure -state disabled
+               }
+       }
+
+if { [file exists include/linux/autoconf.h] == 1 } then {
+               if { [file writable include/linux/autoconf.h] == 0 } then {
+                       .f0r_bot.save configure -state disabled
+               }
+       } else {
+               if { [file writable include/linux/] == 0 } then {
+                       .f0r_bot.save configure -state disabled
+               }
+       }
+
+if { [file writable .config] == 0 || [file writable include/linux/autoconf.h ] == 0 } then {
+       .f0r_bot.save configure -state disabled
+       }
diff --git a/scripts/tkcond.c b/scripts/tkcond.c
new file mode 100644 (file)
index 0000000..050ff05
--- /dev/null
@@ -0,0 +1,415 @@
+/* parser config.in
+ *
+ * Version 1.0
+ * Eric Youngdale
+ * 10/95
+ *
+ * The general idea here is that we want to parse a config.in file and 
+ * from this, we generate a wish script which gives us effectively the
+ * same functionality that the original config.in script provided.
+ *
+ * This task is split roughly into 3 parts.  The first parse is the parse
+ * of the input file itself.  The second part is where we analyze the 
+ * #ifdef clauses, and attach a linked list of tokens to each of the
+ * menu items.  In this way, each menu item has a complete list of
+ * dependencies that are used to enable/disable the options.
+ * The third part is to take the configuration database we have build,
+ * and build the actual wish script.
+ *
+ * This file contains the code to further process the conditions from
+ * the "ifdef" clauses.
+ *
+ * The conditions are assumed to be one of the folowing formats
+ *
+ * simple_condition:= "$VARIABLE" == y/n/m
+ * simple_condition:= "$VARIABLE != y/n/m
+ *
+ * simple_condition -a simple_condition
+ *
+ * If the input condition contains '(' or ')' it would screw us up, but for now
+ * this is not a problem.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "tkparse.h"
+
+
+/*
+ * Walk a condition chain and invert it so that the logical result is
+ * inverted.
+ */
+static int invert_condition(struct condition * cnd)
+{
+  /*
+   * This is simple.  Just walk through the list, and invert
+   * all of the operators.
+   */
+  for(;cnd; cnd = cnd->next)
+    {
+      switch(cnd->op)
+       {
+       case op_and:
+         cnd->op = op_or;
+         break;
+       case op_or:
+         cnd->op = op_and;
+         break;
+       case op_neq:
+         cnd->op = op_eq;
+         break;
+       case op_eq:
+         cnd->op = op_neq;
+         break;
+       }
+    }
+}
+
+/*
+ * Walk a condition chain, and free the memory associated with it.
+ */
+static int free_condition(struct condition * cnd)
+{
+  struct condition * next;
+  for(;cnd; cnd = next)
+    {
+      next = cnd->next;
+
+      if( cnd->variable.str != NULL )
+       free(cnd->variable.str);
+
+      free(cnd);
+    }
+}
+
+/*
+ * Walk the stack of conditions, and clone all of them with "&&" operators
+ * gluing them together.  The conditions from each level of the stack
+ * are wrapped in parenthesis so as to guarantee that the results
+ * are logically correct.
+ */
+struct condition * get_token_cond(struct condition ** cond, int depth)
+{
+  int i;
+  struct condition * newcond;
+  struct condition * tail;
+  struct condition * new;
+  struct condition * ocond;
+  struct kconfig * cfg;
+
+  newcond = tail = NULL;
+  for(i=0; i<depth; i++, cond++)
+    {
+      /*
+       * First insert the left parenthesis
+       */
+      new = (struct condition *) malloc(sizeof(struct condition));
+      memset(new, 0, sizeof(*new));
+      new->op = op_lparen;
+      if( tail == NULL )
+       {
+         newcond = tail = new;
+       }
+      else
+       {
+         tail->next = new;
+         tail = new;
+       }
+
+      /*
+       * Now duplicate the chain.
+       */
+      ocond = *cond;
+      for(;ocond != NULL; ocond = ocond->next)
+       {
+         new = (struct condition *) malloc(sizeof(struct condition));
+         memset(new, 0, sizeof(*new));
+         new->op = ocond->op;
+         if( ocond->variable.str != NULL )
+           {
+             if( ocond->op == op_variable )
+               {
+                 /*
+                  * Search for structure to insert here.
+                  */
+                 for(cfg = config;cfg != NULL; cfg = cfg->next)
+                   {
+                     if( cfg->tok != tok_bool && cfg->tok != tok_int
+                        && cfg->tok != tok_tristate 
+                        && cfg->tok != tok_dep_tristate)
+                       {
+                         continue;
+                       }
+                     if( strcmp(cfg->optionname, ocond->variable.str) == 0)
+                       {
+                         new->variable.cfg = cfg;
+                         new->op = op_kvariable;
+                         break;
+                       }
+                   }
+               }
+             else
+               {
+                 new->variable.str = strdup(ocond->variable.str);
+               }
+           }
+         tail->next = new;
+         tail = new;
+       }
+
+      /*
+       * Next insert the left parenthesis
+       */
+      new = (struct condition *) malloc(sizeof(struct condition));
+      memset(new, 0, sizeof(*new));
+      new->op = op_rparen;
+      tail->next = new;
+      tail = new;
+
+      /*
+       * Insert an and operator, if we have another condition.
+       */
+      if( i < depth - 1 )
+       {
+         new = (struct condition *) malloc(sizeof(struct condition));
+         memset(new, 0, sizeof(*new));
+         new->op = op_and;
+         tail->next = new;
+         tail = new;
+       }
+
+    }
+
+  return newcond;
+}
+
+/*
+ * Walk a single chain of conditions and clone it.  These are assumed
+ * to be created/processed by  get_token_cond in a previous pass.
+ */
+struct condition * get_token_cond_frag(struct condition * cond, 
+                                      struct condition ** last)
+{
+  int i;
+  struct condition * newcond;
+  struct condition * tail;
+  struct condition * new;
+  struct condition * ocond;
+  struct kconfig * cfg;
+
+  newcond = tail = NULL;
+
+  /*
+   * Now duplicate the chain.
+   */
+  for(ocond = cond;ocond != NULL; ocond = ocond->next)
+    {
+      new = (struct condition *) malloc(sizeof(struct condition));
+      memset(new, 0, sizeof(*new));
+      new->op = ocond->op;
+      new->variable.cfg = ocond->variable.cfg;
+      if( tail == NULL )
+       {
+         newcond = tail = new;
+       }
+      else
+       {
+         tail->next = new;
+         tail = new;
+       }
+    }
+
+  new = (struct condition *) malloc(sizeof(struct condition));
+  memset(new, 0, sizeof(*new));
+  new->op = op_and;
+  tail->next = new;
+  tail = new;
+  
+  *last = tail;
+  return newcond;
+}
+
+/*
+ * Walk through the if conditionals and maintain a chain.
+ */
+int fix_conditionals(struct kconfig * scfg)
+{
+  int depth = 0;
+  int i;
+  struct kconfig * cfg;
+  struct condition * conditions[25];
+  struct condition * cnd;
+  struct condition * cnd1;
+  struct condition * cnd2;
+  struct condition * cnd3;
+  struct condition * newcond;
+  struct condition * last;
+
+  /*
+   * Start by walking the chain.  Every time we see an ifdef, push
+   * the condition chain on the stack.  When we see an "else", we invert
+   * the condition at the top of the stack, and when we see an "endif"
+   * we free all of the memory for the condition at the top of the stack
+   * and remove the condition from the top of the stack.
+   *
+   * For any other type of token (i.e. a bool), we clone a new condition chain
+   * by anding together all of the conditions that are currently stored on
+   * the stack.  In this way, we have a correct representation of whatever
+   * conditions govern the usage of each option.
+   */
+  memset(conditions, 0, sizeof(conditions));
+  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
+    {
+      switch(cfg->tok)
+       {
+       case tok_if:
+         /*
+          * Push this condition on the stack, and nuke the token
+          * representing the ifdef, since we no longer need it.
+          */
+         conditions[depth] = cfg->cond;
+         depth++;
+         cfg->tok = tok_nop;
+         cfg->cond =  NULL;
+         break;
+       case tok_else:
+         /*
+          * For an else, we just invert the condition at the top of
+          * the stack.  This is done in place with no reallocation
+          * of memory taking place.
+          */
+         invert_condition(conditions[depth-1]);
+         cfg->tok = tok_nop;
+         break;
+       case tok_fi:
+         depth--;
+         free_condition(conditions[depth]);
+         conditions[depth] = NULL;
+         cfg->tok = tok_nop;
+         break;
+       case tok_comment:
+       case tok_menuoption:
+       case tok_bool:
+       case tok_tristate:
+       case tok_dep_tristate:
+       case tok_int:
+         /*
+          * We need to duplicate the chain of conditions and attach them to
+          * this token.
+          */
+         cfg->cond = get_token_cond(&conditions[0], depth);
+         break;
+       default:
+         break;
+       }
+    }
+  /*
+   * Now go through the list, and every time we see a kvariable, check
+   * to see whether it also has some dependencies.  If so, then
+   * append it to our list.  The reason we do this is that we might have
+   * option CONFIG_FOO which is only used if CONFIG_BAR is set.  It may
+   * turn out that in config.in that the default value for CONFIG_BAR is
+   * set to "y", but that CONFIG_BAR is not enabled because CONFIG_XYZZY
+   * is not set.  The current condition chain does not reflect this, but
+   * we can fix this by searching for the tokens that this option depends
+   * upon and cloning the conditions and merging them with the list.
+   */
+  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
+    {
+      /*
+       * Search for a token that has a condition list.
+       */
+      if(cfg->cond == NULL) continue;
+      for(cnd = cfg->cond; cnd; cnd=cnd->next)
+       {
+         /*
+          * Now search the condition list for a known configuration variable
+          * that has conditions of it's own.
+          */
+         if(cnd->op != op_kvariable) continue;
+         if(cnd->variable.cfg->cond == NULL) continue;
+
+         /*
+          * OK, we have some conditions to append to cfg.  Make  a clone
+          * of the conditions,
+          */
+         newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
+
+         /*
+          * Finally, we splice it into our list.
+          */
+         last->next = cfg->cond;
+         cfg->cond = newcond;
+
+       }
+    }
+
+  /*
+   * There is a strong possibility that we have duplicate conditions
+   * in here.  It would make the script more efficient and readable to
+   * remove these.  Here is where we assume here that there are no
+   * parenthesis in the input script.
+   */
+  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
+    {
+      /*
+       * Search for configuration options that have conditions.
+       */
+      if(cfg->cond == NULL) continue;
+      for(cnd = cfg->cond; cnd; cnd=cnd->next)
+       {
+         /*
+          * Search for a left parenthesis.
+          */
+         if(cnd->op != op_lparen) continue;
+         for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
+           {
+             /*
+              * Search after the previous left parenthesis, and try
+              * and find a second left parenthesis.
+              */
+             if(cnd1->op != op_lparen) continue;
+
+             /*
+              * Now compare the next 5 tokens to see if they are
+              * identical.  We are looking for two chains that
+              * are like: '(' $VARIABLE operator constant ')'.
+              */
+             cnd2 = cnd;
+             cnd3 = cnd1;
+             for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
+               {
+                 if(!cnd2 || !cnd3) break;
+                 if(cnd2->op != cnd3->op) break;
+                 if(i == 1 && (cnd2->op != op_kvariable 
+                    || cnd2->variable.cfg != cnd3->variable.cfg) ) break;
+                 if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
+                 if(i == 3 && cnd2->op != op_constant &&
+                    strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
+                   break;
+                 if(i==4 && cnd2->op != op_rparen) break;
+               }
+             /*
+              * If these match, and there is an and gluing these together,
+              * then we can nuke the second one.
+              */
+             if(i==5 && ((cnd3 && cnd3->op == op_and)
+                         ||(cnd2 && cnd2->op == op_and)))
+               {
+                 /*
+                  * We have a duplicate.  Nuke 5 ops.
+                  */
+                 cnd3 = cnd1;
+                 for(i=0; i<5; i++, cnd3=cnd3->next)
+                   {
+                     cnd3->op = op_nuked;
+                   }
+                 /*
+                  * Nuke the and that glues the conditions together.
+                  */
+                 if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
+                 else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
+               }
+           }
+       }
+    }
+}
diff --git a/scripts/tkgen.c b/scripts/tkgen.c
new file mode 100644 (file)
index 0000000..12b9dbc
--- /dev/null
@@ -0,0 +1,719 @@
+/* Generate tk script based upon config.in
+ *
+ * Version 1.0
+ * Eric Youngdale
+ * 10/95
+ */
+#include <stdio.h>
+#include "tkparse.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/*
+ * Generate portion of wish script for the beginning of a submenu.
+ * The guts get filled in with the various options.
+ */
+static start_proc(char * label, int menu_num, int flag)
+{
+  if( flag )
+    printf("menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label);
+  printf("proc menu%d {w title} {\n", menu_num);
+  printf("\tcatch {destroy $w}\n");
+  printf("\ttoplevel $w -class Dialog\n");
+  printf("\tmessage $w.m -width 400 -aspect 300 -background grey -text \\\n");
+  printf("\t\t\"$title\"  -relief raised -bg grey\n");
+  printf("\tpack $w.m -pady 10 -side top -padx 10\n");
+  printf("\twm title $w \"$title\" \n\n\n");
+}
+
+/*
+ * Each proc we create needs a global declaration for any global variables we
+ * use.  To minimize the size of the file, we set a flag each time we output
+ * a global declaration so we know whether we need to insert one for a
+ * given function or not.
+ */
+clear_globalflags(struct kconfig * cfg)
+{
+  for(; cfg != NULL; cfg = cfg->next)
+  {
+    cfg->flags &= ~GLOBAL_WRITTEN;
+  }
+}
+
+/*
+ * This function walks the chain of conditions that we got from cond.c,
+ * and creates a wish conditional to enable/disable a given widget.
+ */
+generate_if(struct kconfig * item,
+           struct condition * cond,
+           int menu_num,
+           int line_num)
+{
+  struct condition * ocond;
+
+  /*
+   * First write any global declarations we need for this conditional.
+   */
+  ocond = cond;
+  while(cond != NULL )
+    {
+      switch(cond->op){
+      case op_variable:
+       printf("\tglobal %s\n", cond->variable.str);
+       break;
+      case op_kvariable:
+       if(cond->variable.cfg->flags & GLOBAL_WRITTEN) break;
+       cond->variable.cfg->flags |= GLOBAL_WRITTEN;
+       printf("\tglobal %s\n", cond->variable.cfg->optionname);
+       break;
+      default:
+       break;
+      }
+      cond = cond->next;
+    }
+
+  /*
+   * Now generate the body of the conditional.
+   */
+  printf("\tif {");
+  cond = ocond;
+  while(cond != NULL )
+    {
+      switch(cond->op){
+      case op_bang:
+       printf(" ! ");
+       break;
+      case op_eq:
+       printf(" == ");
+       break;
+      case op_neq:
+       printf(" != ");
+       break;
+      case op_and:
+       printf(" && ");
+       break;
+      case op_or:
+       printf(" || ");
+       break;
+      case op_lparen:
+       printf("(");
+       break;
+      case op_rparen:
+       printf(")");
+       break;
+      case op_variable:
+       printf("$%s", cond->variable.str);
+       break;
+      case op_kvariable:
+       printf("$%s", cond->variable.cfg->optionname);
+       break;
+      case op_constant:
+       if( strcmp(cond->variable.str, "y") == 0 )
+         printf("1");
+       else if( strcmp(cond->variable.str, "n") == 0 )
+         printf("0");
+       else if( strcmp(cond->variable.str, "m") == 0 )
+         printf("2");
+       else
+         printf("'%s'", cond->variable);
+       break;
+      }
+      cond = cond->next;
+    }
+
+  /*
+   * Now we generate what we do depending upon the value of the conditional.
+   * Depending upon what the token type is, there are different things
+   * we must do to enable/disable the given widget - this code needs to
+   * be closely coordinated with the widget creation procedures in header.tk.
+   */
+  switch(item->tok)
+    {
+    case tok_menuoption:
+      printf("} then { .f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n",
+            menu_num, menu_num);
+      break;
+    case tok_int:
+      printf("} then { ");
+      printf(".menu%d.x%d.x configure -state normal; ", menu_num, line_num);
+      printf(".menu%d.x%d.l configure -state normal; ", menu_num, line_num);
+      printf("} else { ");
+      printf(".menu%d.x%d.x configure -state disabled;", menu_num, line_num );
+      printf(".menu%d.x%d.l configure -state disabled;", menu_num, line_num );
+      printf("}\n");
+      break;
+    case tok_bool:
+#ifdef BOOL_IS_BUTTON
+      /*
+       * If a bool is just a button, then use this definition.
+       */
+      printf("} then { .menu%d.x%d configure -state normal } else { .menu%d.x%d configure -state disabled }\n",
+            menu_num, line_num,
+            menu_num, line_num );
+#else
+      /*
+       * If a bool is a radiobutton, then use this instead.
+       */
+      printf("} then { ");
+      printf(".menu%d.x%d.y configure -state normal;",menu_num, line_num);
+      printf(".menu%d.x%d.n configure -state normal;",menu_num, line_num);
+      printf(".menu%d.x%d.l configure -state normal;",menu_num, line_num);
+      printf("} else { ");
+      printf(".menu%d.x%d.y configure -state disabled;",menu_num, line_num);
+      printf(".menu%d.x%d.n configure -state disabled;",menu_num, line_num);
+      printf(".menu%d.x%d.l configure -state disabled;",menu_num, line_num);
+      printf("}\n");
+#endif
+      break;
+    case tok_tristate:
+    case tok_dep_tristate:
+      printf("} then { ");
+      if( item->tok == tok_dep_tristate )
+       {
+         printf("if { $%s == 2 } then {", item->depend.str);
+         printf(".menu%d.x%d.y configure -state disabled;",menu_num, line_num);
+         printf("} else {");
+         printf(".menu%d.x%d.y configure -state normal;",menu_num, line_num);
+         printf("}; ");
+       }
+      else
+       {
+         printf(".menu%d.x%d.y configure -state normal;",menu_num, line_num);
+       }
+      
+      printf(".menu%d.x%d.n configure -state normal;",menu_num, line_num);
+      printf(".menu%d.x%d.m configure -state normal;",menu_num, line_num);
+      printf(".menu%d.x%d.l configure -state normal;",menu_num, line_num);
+      printf("} else { ");
+      printf(".menu%d.x%d.y configure -state disabled;",menu_num, line_num);
+      printf(".menu%d.x%d.n configure -state disabled;",menu_num, line_num);
+      printf(".menu%d.x%d.m configure -state disabled;",menu_num, line_num);
+      printf(".menu%d.x%d.l configure -state disabled;",menu_num, line_num);
+      printf("}\n");
+      break;
+    default:
+      break;
+    }
+}
+
+/*
+ * Similar to generate_if, except we come here when generating an
+ * output file.  Thus instead of enabling/disabling a widget, we
+ * need to decide whether to write out a given configuration variable
+ * to the output file.
+ */
+generate_if_for_outfile(struct kconfig * item,
+           struct condition * cond)
+{
+  struct condition * ocond;
+
+  /*
+   * First write any global declarations we need for this conditional.
+   */
+  ocond = cond;
+  for(; cond != NULL; cond = cond->next )
+    {
+      switch(cond->op){
+      case op_variable:
+       printf("\tglobal %s\n", cond->variable.str);
+       break;
+      case op_kvariable:
+       if(cond->variable.cfg->flags & GLOBAL_WRITTEN) break;
+       cond->variable.cfg->flags |= GLOBAL_WRITTEN;
+       printf("\tglobal %s\n", cond->variable.cfg->optionname);
+       break;
+      default:
+       break;
+      }
+    }
+
+  /*
+   * Now generate the body of the conditional.
+   */
+  printf("\tif {");
+  cond = ocond;
+  while(cond != NULL )
+    {
+      switch(cond->op){
+      case op_bang:
+       printf(" ! ");
+       break;
+      case op_eq:
+       printf(" == ");
+       break;
+      case op_neq:
+       printf(" != ");
+       break;
+      case op_and:
+       printf(" && ");
+       break;
+      case op_or:
+       printf(" || ");
+       break;
+      case op_lparen:
+       printf("(");
+       break;
+      case op_rparen:
+       printf(")");
+       break;
+      case op_variable:
+       printf("$%s", cond->variable.str);
+       break;
+      case op_kvariable:
+       printf("$%s", cond->variable.cfg->optionname);
+       break;
+      case op_constant:
+       if( strcmp(cond->variable.str, "y") == 0 )
+         printf("1");
+       else if( strcmp(cond->variable.str, "n") == 0 )
+         printf("0");
+       else if( strcmp(cond->variable.str, "m") == 0 )
+         printf("2");
+       else
+         printf("'%s'", cond->variable);
+       break;
+      }
+      cond = cond->next;
+    }
+
+  /*
+   * Now we generate what we do depending upon the value of the
+   * conditional.  Depending upon what the token type is, there are
+   * different things we must do write the value the given widget -
+   * this code needs to be closely coordinated with the widget
+   * creation procedures in header.tk.  
+   */
+  switch(item->tok)
+    {
+    case tok_comment:
+      printf("} then {write_comment $cfg $autocfg \"%s\"}\n", item->label);
+      break;
+    case tok_dep_tristate:
+      printf("} then { write_variable $cfg $autocfg %s $%s $%s } \n", 
+            item->optionname, item->optionname, item->depend.str);
+      break;
+    case tok_tristate:
+    case tok_bool:
+    case tok_int:
+      printf("} then { write_variable $cfg $autocfg %s $%s $notmod }\n", 
+            item->optionname, item->optionname);
+      break;
+    default:
+      break;
+    }
+}
+
+/*
+ * Generates a fragment of wish script that closes out a submenu procedure.
+ */
+static end_proc(int menu_num, int first, int last)
+{
+  struct kconfig * cfg;
+
+  printf("\n\n\n");
+  printf("\tset oldFocus [focus]\n");
+  printf("\tframe $w.f\n");
+
+  /*
+   * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
+   */
+  printf("\tbutton $w.f.prev -text \"Prev\" -activebackground green \\\n");
+      printf("\t\t-width 15 -command \" destroy $w; focus $oldFocus; menu%d .menu%d \\\"$title\\\"\"\n", menu_num-1, menu_num-1);
+  if(first == menu_num ) printf("\t$w.f.prev configure -state disabled\n");
+
+  printf("\tbutton $w.f.next -text \"Next\" -activebackground green \\\n");
+  printf("\t\t-width 15 -command \" destroy $w; focus $oldFocus;  menu%d .menu%d \\\"$title\\\"\"\n", menu_num+1, menu_num+1);
+  if(last == menu_num ) printf("\t$w.f.next configure -state disabled\n");
+
+  printf("\tbutton $w.f.back -text \"Main Menu\" -activebackground green \\\n");
+  printf("\t\t-width 15 -command \"destroy $w; focus $oldFocus; update_mainmenu $w\"\n");
+
+  printf("\tpack $w.f.back $w.f.next $w.f.prev -side left -pady 10 -padx 45\n");
+  printf("\tpack $w.f -pady 10 -side top -padx 10 -anchor w\n");
+  printf("\tfocus $w\n");
+  printf("\tupdate_menu%d $w\n", menu_num);
+  printf("\twm geometry $w +30+35\n");
+  printf("}\n\n\n");
+
+  /*
+   * Now we generate the companion procedure for the muen we just
+   * generated.  This procedure contains all of the code to
+   * disable/enable widgets based upon the settings of the other
+   * widgets, and will be called first when the window is mapped,
+   * and each time one of the buttons in the window are clicked.
+   */
+  printf("proc update_menu%d {w}  {\n", menu_num);
+
+  clear_globalflags(config);
+  for(cfg = config;cfg != NULL; cfg = cfg->next)
+    {
+      /*
+       * Skip items not for this menu, or ones having no conditions.
+       */
+      if (cfg->menu_number != menu_num ) continue;
+      if (cfg->tok == tok_menuoption) continue;
+      if (cfg->cond != NULL ) 
+       generate_if(cfg, cfg->cond, menu_num, cfg->menu_line);
+      else
+       {
+         /*
+          * If this token has no conditionals, check to see whether
+          * it is a tristate - if so, then generate the conditional
+          * to enable/disable the "y" button based upon the setting
+          * of the option it depends upon.
+          */
+         if(cfg->tok == tok_dep_tristate)
+           {
+             printf("\tif {$%s == 2 } then { .menu3.x5.y configure -state normal} else { .menu3.x5.y configure -state disabled}\n",cfg->depend.str,
+                    menu_num, cfg->menu_line,
+                    menu_num, cfg->menu_line);
+             
+           }
+       }
+
+    }
+
+
+  printf("}\n\n\n");
+}
+
+/*
+ * This function goes through and counts up the number of items in
+ * each submenu. If there are too many options, we need to split it
+ * into submenus.  This function just calculates how many submenus,
+ * and how many items go in each submenu.
+ */
+static int find_menu_size(struct kconfig *cfg,
+                         int *menu_max, 
+                         int *menu_maxlines)
+
+{
+  struct kconfig * pnt;
+  int tot;
+  int div;
+  
+  /*
+   * First count up the number of options in this menu.
+   */
+  tot = 0;
+  for(pnt = cfg->next; pnt; pnt = pnt->next)
+  {
+    if( pnt->tok == tok_menuoption) break;
+    switch (pnt->tok)
+      {
+      case tok_bool:
+      case tok_tristate:
+      case tok_dep_tristate:
+      case tok_int:
+       tot++;
+       break;
+      default:
+       break;
+      }
+  }
+
+  /*
+   * Now figure out how many items go on each page.
+   */
+  div = 1;
+  while(tot / div > 15) div++;
+  *menu_max = cfg->menu_number + div - 1;
+  *menu_maxlines = (tot + div -1) / div;
+}
+
+/*
+ * This is the top level function for generating the tk script.
+ */
+dump_tk_script(struct kconfig *scfg)
+{
+  int menu_num =0;
+  int menu_max =0;
+  int menu_min =0;
+  int menu_line = 0;
+  int menu_maxlines = 0;
+  struct kconfig * cfg;
+
+  /*
+   * Start by assigning menu numbers, and submenu numbers.
+   */
+  for(cfg = scfg;cfg != NULL; cfg = cfg->next)
+    {
+      switch (cfg->tok)
+       {
+       case tok_menuname:
+         break;
+       case tok_menuoption:
+         /*
+          * At the start of a new menu, calculate the number of items
+          * we will put into each submenu so we know when to bump the
+          * menu number. The submenus are really no different from a
+          * normal menu, but the top level buttons only access the first
+          * of the chain of menus, and the prev/next buttons are used
+          * access the submenus.
+          */
+         cfg->menu_number = ++menu_num;
+         find_menu_size(cfg, &menu_max, &menu_maxlines);
+         cfg->submenu_start = menu_num;
+         cfg->submenu_end = menu_max;
+         menu_line = 0;
+         break;
+       case tok_bool:
+       case tok_tristate:
+       case tok_dep_tristate:
+       case tok_int:
+         /*
+          * If we have overfilled the menu, then go to the next one.
+          */
+         if( menu_line == menu_maxlines )
+           {
+             menu_line = 0;
+             menu_num++;
+           }
+         cfg->menu_number = menu_num;
+         cfg->submenu_start = menu_min;
+         cfg->submenu_end = menu_max;
+         cfg->menu_line = menu_line++;
+         break;
+       default:
+         break;
+       };
+    }
+
+  /*
+   * Now start generating the actual wish script that we will use.
+   * We need to keep track of the menu numbers of the min/max menu
+   * for a range of submenus so that we can correctly limit the
+   * prev and next buttons so that they don't go over into some other
+   * category.
+   */
+  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    {
+      switch (cfg->tok)
+       {
+       case tok_menuname:
+         printf("mainmenu_name \"%s\"\n", cfg->label);
+         break;
+       case tok_menuoption:
+         /*
+          * We are at the start of a new menu. If we had one that
+          * we were working on before, close it out, and then generate
+          * the script to start the new one.
+          */
+         if( cfg->menu_number > 1 )
+           {
+             end_proc(menu_num, menu_min, menu_max);
+           }
+         start_proc(cfg->label, cfg->menu_number, TRUE);
+         menu_num = cfg->menu_number;
+         menu_max = cfg->submenu_end;
+         menu_min = cfg->submenu_start;
+         break;
+       case tok_bool:
+         /*
+          * If we reached the point where we need to switch over
+          * to the next submenu, then bump the menu number and generate
+          * the code to close out the old menu and start the new one.
+          */
+         if( cfg->menu_number != menu_num )
+           {
+             end_proc(menu_num, menu_min, menu_max);
+             start_proc(cfg->label, cfg->menu_number, FALSE);
+             menu_num = cfg->menu_number;
+           }
+         printf("\tbool $w %d %d \"%s\" %s %s\n",
+                cfg->menu_number,
+                cfg->menu_line,
+                cfg->label,
+                cfg->optionname,
+                cfg->dflt);
+         break;
+
+       case tok_tristate:
+         if( cfg->menu_number != menu_num )
+           {
+             end_proc(menu_num, menu_min, menu_max);
+             start_proc(cfg->label, cfg->menu_number, FALSE);
+             menu_num = cfg->menu_number;
+           }
+         printf("\ttristate $w %d %d \"%s\" %s %s\n",
+                cfg->menu_number,
+                cfg->menu_line,
+                cfg->label,
+                cfg->optionname,
+                cfg->dflt);
+         break;
+       case tok_dep_tristate:
+         if( cfg->menu_number != menu_num )
+           {
+             end_proc(menu_num, menu_min, menu_max);
+             start_proc(cfg->label, cfg->menu_number, FALSE);
+             menu_num = cfg->menu_number;
+           }
+         printf("\tdep_tristate $w %d %d \"%s\" %s %s\n",
+                cfg->menu_number,
+                cfg->menu_line,
+                cfg->label,
+                cfg->optionname,
+                cfg->dflt,
+                cfg->depend);
+         break;
+       case tok_int:
+         printf("\tint $w %d %d \"%s\" %s %s\n",
+                cfg->menu_number,
+                cfg->menu_line,
+                cfg->label,
+                cfg->optionname,
+                cfg->dflt);
+       default:
+         break;
+       }
+
+    }
+
+  /*
+   * Generate the code to close out the last menu.
+   */
+  end_proc(menu_num, menu_min, menu_max);
+
+  /*
+   * Generate the code for configuring the sound driver.  Right now this
+   * cannot be done from the X script, but we insert the menu anyways.
+   */
+  start_proc("Configure sound driver", ++menu_num, TRUE);
+#if 0
+  printf("\tdo_make -C drivers/sound config\n");
+  printf("\techo check_sound_config %d\n",menu_num);
+#endif
+  printf("\tlabel $w.m0 -bitmap error\n");
+  printf("\tmessage $w.m1 -width 400 -aspect 300 -text \"The sound drivers cannot as of yet be configured via the X-based interface\" -relief raised\n");
+  printf("\tpack $w.m0 $w.m1 -side top -pady 10\n");
+
+  /*
+   * Close out the last menu.
+   */
+  end_proc(menu_num, menu_num, menu_num);
+
+  /*
+   * The top level menu also needs an update function.  When we exit a
+   * submenu, we may need to disable one or more of the submenus on
+   * the top level menu, and this procedure will ensure that things are
+   * correct.
+   */
+  printf("proc update_mainmenu {w}  {\n");
+  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    {
+      switch (cfg->tok)
+       {
+       case tok_menuoption:
+         if (cfg->cond != NULL ) 
+           generate_if(cfg, cfg->cond, cfg->menu_number, cfg->menu_line);
+         break;
+       default:
+         break;
+       }
+    }
+
+  printf("}\n\n\n");
+
+  /*
+   * Now generate code to load the default settings into the variables.
+   * Note that the script in tail.tk will attempt to load .config,
+   * which may override these settings, but that's OK.
+   */
+  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    {
+      switch (cfg->tok)
+       {
+       case tok_int:
+           printf("set %s %s\n", cfg->optionname, cfg->dflt);
+           break;
+       case tok_bool:
+       case tok_tristate:
+       case tok_dep_tristate:
+         if( strcmp(cfg->dflt, "y") == 0 )
+           printf("set %s 1\n", cfg->optionname);
+         else if( strcmp(cfg->dflt, "n") == 0 )
+           printf("set %s 0\n", cfg->optionname);
+         else if( strcmp(cfg->dflt, "m") == 0 )
+           printf("set %s 2\n", cfg->optionname);
+         break;
+       default:
+         break;
+       }
+    }
+
+  /*
+   * Next generate a function that can be called from the main menu that will
+   * write all of the variables out.  This also serves double duty - we can
+   * save configuration to a file using this.
+   */
+  printf("proc writeconfig {file1 file2} {\n");
+  printf("\tset cfg [open $file1 w]\n");
+  printf("\tset autocfg [open $file2 w]\n");
+  printf("\tset notmod 1\n");
+  printf("\tset notset 0\n");
+  clear_globalflags(config);
+  printf("\tputs $cfg \"#\"\n");
+  printf("\tputs $cfg \"# Automatically generated make config: don't edit\"\n");
+  printf("\tputs $cfg \"#\"\n");
+
+  printf("\tputs $autocfg \"/*\"\n");
+  printf("\tputs $autocfg \" * Automatically generated C config: don't edit\"\n");
+  printf("\tputs $autocfg \" */\"\n");
+  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    {
+      switch (cfg->tok)
+       {
+       case tok_int:
+       case tok_bool:
+       case tok_tristate:
+       case tok_dep_tristate:
+         if(cfg->flags & GLOBAL_WRITTEN) break;
+         cfg->flags |= GLOBAL_WRITTEN;
+         printf("\tglobal %s\n", cfg->optionname);
+
+       case tok_comment:
+         if (cfg->cond != NULL ) 
+           generate_if_for_outfile(cfg, cfg->cond);
+         else
+           {
+             if(cfg->tok == tok_dep_tristate)
+               {
+                 printf("\tif {$%s == 2 } then { write_variable $cfg $autocfg %s $%s %s } else { write_variable $cfg $autocfg %s $notset $notmod }\n",
+                        cfg->optionname,
+                        cfg->optionname,
+                        cfg->depend.str,
+                        cfg->optionname);
+               }
+             else if(cfg->tok == tok_comment)
+               {
+                 printf("\twrite_comment $cfg $autocfg \"%s\"\n", cfg->label);
+               }
+             else
+               {
+                 printf("\twrite_variable $cfg $autocfg %s $%s $notmod\n",
+                        cfg->optionname,
+                        cfg->optionname);
+                        
+               }
+           }
+         break;
+       default:
+         break;
+       }
+    }
+  printf("\tclose $cfg\n");
+  printf("\tclose $autocfg\n");
+  printf("}\n\n\n");
+
+  /*
+   * That's it.  We are done.  The output of this file will have header.tk
+   * prepended and tail.tk appended to create an executable wish script.
+   */
+}
diff --git a/scripts/tkparse.c b/scripts/tkparse.c
new file mode 100644 (file)
index 0000000..59352f4
--- /dev/null
@@ -0,0 +1,529 @@
+/* parser config.in
+ *
+ * Version 1.0
+ * Eric Youngdale
+ * 10/95
+ *
+ * The general idea here is that we want to parse a config.in file and 
+ * from this, we generate a wish script which gives us effectively the
+ * same functionality that the original config.in script provided.
+ *
+ * This task is split roughly into 3 parts.  The first parse is the parse
+ * of the input file itself.  The second part is where we analyze the 
+ * #ifdef clauses, and attach a linked list of tokens to each of the
+ * menu items.  In this way, each menu item has a complete list of
+ * dependencies that are used to enable/disable the options.
+ * The third part is to take the configuration database we have build,
+ * and build the actual wish script.
+ *
+ * This file contains the code to do the first parse of config.in.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "tkparse.h"
+
+struct kconfig * config = NULL;
+struct kconfig * clast = NULL;
+struct kconfig * koption = NULL;
+static int lineno = 0;
+/*
+ * Simple function just to skip over spaces and tabs in config.in.
+ */
+static char * skip_whitespace(char * pnt)
+{
+  while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
+  return pnt;
+}
+
+/*
+ * This function parses a conditional from a config.in (i.e. from an ifdef)
+ * and generates a linked list of tokens that describes the conditional.
+ */
+static struct condition * parse_if(char * pnt)
+{
+  char * opnt;
+  struct condition *list;
+  struct condition *last;
+  struct condition *cpnt;
+  char varname[64];
+  char * pnt1;
+
+  opnt = pnt;
+
+  /*
+   * We need to find the various tokens, and build the linked list.
+   */
+  pnt = skip_whitespace(pnt);
+  if( *pnt != '[' ) return NULL;
+  pnt++;
+  pnt = skip_whitespace(pnt);
+
+  list = last = NULL;
+  while(*pnt && *pnt != ']') {
+
+    pnt = skip_whitespace(pnt);
+    if(*pnt== '\0' || *pnt == ']') break;
+
+    /*
+     * Allocate memory for the token we are about to parse, and insert
+     * it in the linked list.
+     */
+    cpnt = (struct condition *) malloc(sizeof(struct condition));
+    memset(cpnt, 0, sizeof(struct condition));
+    if( last == NULL )
+      {
+       list = last = cpnt;
+      }
+    else
+      {
+       last->next = cpnt;
+       last = cpnt;
+      }
+
+    /*
+     * Determine what type of operation this token represents.
+     */
+    if( *pnt == '-' && pnt[1] == 'a' )
+      {
+       cpnt->op = op_and;
+       pnt += 2;
+       continue;
+      }
+
+    if( *pnt == '!' && pnt[1] == '=' )
+      {
+       cpnt->op = op_neq;
+       pnt += 2;
+       continue;
+      }
+
+    if( *pnt == '=')
+      {
+       cpnt->op = op_eq;
+       pnt += 1;
+       continue;
+      }
+
+    if( *pnt == '!')
+      {
+       cpnt->op = op_bang;
+       pnt += 1;
+       continue;
+      }
+
+    if( *pnt != '"' ) goto error;  /* This cannot be right. */
+    pnt++;
+    if( *pnt == '$' )
+      {
+       cpnt->op = op_variable;
+       pnt1 = varname;
+       pnt++;
+       while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
+       *pnt1++ = '\0';
+       cpnt->variable = strdup(varname);
+       if( *pnt == '"' ) pnt++;
+       continue;
+      }
+
+    cpnt->op = op_constant;
+    pnt1 = varname;
+    while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
+    *pnt1++ = '\0';
+    cpnt->variable = strdup(varname);
+    if( *pnt == '"' ) pnt++;
+    continue;
+  }
+
+  return list;
+
+ error:
+  printf("Bad if clause at line %d:%s\n", lineno, opnt);
+  return NULL;
+}
+
+/*
+ * This function looks for a quoted string, from the input buffer, and
+ * returns a pointer to a copy of this string.  Any characters in
+ * the string that need to be "quoted" have a '\' character inserted
+ * in front - this way we can directly write these strings into
+ * wish scripts.
+ */
+static char * get_qstring(char *pnt, char ** labl)
+{
+  char quotechar;
+  char newlabel[1024];
+  char * pnt1;
+  char * pnt2;
+
+  while( *pnt && *pnt != '"' && *pnt != '\'') pnt++;
+  if (*pnt == '\0') return pnt;
+
+  quotechar = *pnt++;
+  pnt1 = newlabel;
+  while(*pnt && *pnt != quotechar && pnt[-1] != '\\')
+    {
+      /*
+       * Quote the character if we need to.
+       */
+      if( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']')
+       *pnt1++ = '\\';
+
+      *pnt1++ = *pnt++;
+    }
+  *pnt1++ = '\0';
+
+  pnt2 = (char *) malloc(strlen(newlabel) + 1);
+  strcpy(pnt2, newlabel);
+  *labl = pnt2;
+
+  /*
+   * Skip over last quote, and whitespace.
+   */
+  pnt++;
+  pnt = skip_whitespace(pnt);
+  return pnt;
+}
+
+/*
+ * This function grabs one text token from the input buffer
+ * and returns a pointer to a copy of just the identifier.
+ * This can be either a variable name (i.e. CONFIG_NET),
+ * or it could be the default value for the option.
+ */
+static char * get_string(char *pnt, char ** labl)
+{
+  char quotechar;
+  char newlabel[1024];
+  char * pnt1;
+  char * pnt2;
+
+  if (*pnt == '\0') return pnt;
+
+  pnt1 = newlabel;
+  while(*pnt && *pnt != ' ' && *pnt != '\t')
+    {
+      *pnt1++ = *pnt++;
+    }
+  *pnt1++ = '\0';
+
+  pnt2 = (char *) malloc(strlen(newlabel) + 1);
+  strcpy(pnt2, newlabel);
+  *labl = pnt2;
+
+  if( *pnt ) pnt++;
+  return pnt;
+}
+
+
+/*
+ * Top level parse function.  Input pointer is one complete line from config.in
+ * and the result is that we create a token that describes this line
+ * and insert it into our linked list.
+ */
+int parse(char * pnt) {
+  enum token tok;
+  struct kconfig * kcfg;
+  /*
+   * Ignore comments and leading whitespace.
+   */
+
+  pnt = skip_whitespace(pnt);
+  while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
+  if(! *pnt ) return;
+  if( *pnt == '#' ) return;
+
+  /*
+   * Now categorize the next token.
+   */
+  tok = tok_unknown;
+  if      (strncmp(pnt, "mainmenu_name", 13) == 0) 
+    {
+      tok = tok_menuname;
+      pnt += 13;
+    }
+  else if (strncmp(pnt, "mainmenu_option", 15) == 0) 
+    {
+      tok = tok_menuoption;
+      pnt += 15;
+    }
+  else if (strncmp(pnt, "comment", 7) == 0) 
+    {
+      tok = tok_comment;
+      pnt += 7;
+    }
+  else if (strncmp(pnt, "bool", 4) == 0) 
+    {
+      tok = tok_bool;
+      pnt += 4;
+    }
+  else if (strncmp(pnt, "tristate", 8) == 0) 
+    {
+      tok = tok_tristate;
+      pnt += 8;
+    }
+  else if (strncmp(pnt, "dep_tristate", 12) == 0) 
+    {
+      tok = tok_dep_tristate;
+      pnt += 12;
+    }
+  else if (strncmp(pnt, "int", 3) == 0) 
+    {
+      tok = tok_int;
+      pnt += 3;
+    }
+  else if (strncmp(pnt, "if", 2) == 0) 
+    {
+      tok = tok_if;
+      pnt += 2;
+    }
+  else if (strncmp(pnt, "else", 4) == 0) 
+    {
+      tok = tok_else;
+      pnt += 4;
+    }
+  else if (strncmp(pnt, "fi", 2) == 0) 
+    {
+      tok = tok_fi;
+      pnt += 2;
+    }
+
+  if( tok == tok_unknown)
+    {
+      printf("unknown command=%s\n", pnt);
+      return 1;
+    }
+
+  /*
+   * Allocate memory for this item, and attach it to the end of the linked
+   * list.
+   */
+  kcfg = (struct kconfig *) malloc(sizeof(struct kconfig));
+  memset(kcfg, 0, sizeof(struct kconfig));
+  kcfg->tok = tok;
+  if( clast != NULL )
+    {
+      clast->next = kcfg;
+      clast = kcfg;
+    }
+  else
+    {
+      clast = config = kcfg;
+    }
+
+  pnt = skip_whitespace(pnt);
+
+  /*
+   * Now parse the remaining parts of the option, and attach the results
+   * to the structure.
+   */
+  switch (tok)
+    {
+    case tok_menuname:
+      pnt = get_qstring(pnt, &kcfg->label);
+      break;
+    case tok_bool:
+    case tok_tristate:
+    case tok_int:
+      pnt = get_qstring(pnt, &kcfg->label);
+      pnt = get_string(pnt, &kcfg->optionname);
+      pnt = get_string(pnt, &kcfg->dflt);
+      break;
+    case tok_dep_tristate:
+      pnt = get_qstring(pnt, &kcfg->label);
+      pnt = get_string(pnt, &kcfg->optionname);
+      pnt = get_string(pnt, &kcfg->dflt);
+      pnt = skip_whitespace(pnt);
+      if( *pnt == '$') pnt++;
+      pnt = get_string(pnt, &kcfg->depend.str);
+      break;
+    case tok_comment:
+      pnt = get_qstring(pnt, &kcfg->label);
+      if( koption != NULL )
+       {
+         pnt = get_qstring(pnt, &kcfg->label);
+         koption->label = kcfg->label;
+         koption = NULL;
+       }
+      break;
+    case tok_menuoption:
+      if( strncmp(pnt, "next_comment", 12) == 0)
+       {
+         koption = kcfg;
+       }
+      else
+       {
+         pnt = get_qstring(pnt, &kcfg->label);
+       }
+      break;
+    case tok_else:
+    case tok_fi:
+      break;
+    case tok_if:
+      /*
+       * Conditionals are different.  For the first level parse, only
+       * tok_if items have a ->cond chain attached.
+       */
+      kcfg->cond = parse_if(pnt);
+      if(kcfg->cond == NULL )
+       {
+         exit(1);
+       }
+      break;
+    default:
+      exit(0);
+
+    }
+}
+
+/*
+ * Simple function to dump to the screen what the condition chain looks like.
+ */
+dump_if(struct condition * cond)
+{
+  printf(" ");
+  while(cond != NULL )
+    {
+      switch(cond->op){
+      case op_eq:
+       printf(" = ");
+       break;
+      case op_bang:
+       printf(" ! ");
+       break;
+      case op_neq:
+       printf(" != ");
+       break;
+      case op_and:
+       printf(" -a ");
+       break;
+      case op_lparen:
+       printf("(");
+       break;
+      case op_rparen:
+       printf(")");
+       break;
+      case op_variable:
+       printf("$%s", cond->variable);
+       break;
+      case op_constant:
+       printf("'%s'", cond->variable);
+       break;
+      }
+      cond = cond->next;
+    }
+
+  printf("\n");
+}
+
+char buffer[1024];
+
+main(int argc, char * argv[])
+{
+  char * pnt;
+  struct kconfig * cfg;
+  int    i;
+
+  /*
+   * Loop over every input line, and parse it into the tables.
+   */
+  while(1)
+    {
+      fgets(buffer, sizeof(buffer), stdin);
+      if(feof(stdin)) break;
+
+      /*
+       * Strip the trailing return character.
+       */
+      pnt = buffer + strlen(buffer) - 1;
+      if( *pnt == '\n') *pnt = 0;
+      lineno++;
+      parse(buffer);
+    }
+
+
+  /*
+   * Input file is now parsed.  Next we need to go through and attach
+   * the correct conditions to each of the actual menu items and kill
+   * the if/else/endif tokens from the list.  We also flag the menu items
+   * that have other things that depend upon it's setting.
+   */
+  fix_conditionals(config);
+
+  /*
+   * Finally, we generate the wish script.
+   */
+  dump_tk_script(config);
+
+#if 0
+  /*
+   * Now dump what we have so far.  This is only for debugging so that
+   * we can display what we think we have in the list.
+   */
+  for(cfg = config; cfg; cfg = cfg->next)
+    {
+
+      if(cfg->cond != NULL && cfg->tok != tok_if)
+       dump_if(cfg->cond);
+
+      switch(cfg->tok)
+       {
+       case tok_menuname:
+         printf("main_menuname ");
+         break;
+       case tok_bool:
+         printf("bool ");
+         break;
+       case tok_tristate:
+         printf("tristate ");
+         break;
+       case tok_dep_tristate:
+         printf("dep_tristate ");
+         break;
+       case tok_int:
+         printf("int ");
+         break;
+       case tok_comment:
+         printf("comment ");
+         break;
+       case tok_menuoption:
+         printf("menuoption ");
+         break;
+       case tok_else:
+         printf("else");
+         break;
+       case tok_fi:
+         printf("fi");
+         break;
+       case tok_if:
+         printf("if");
+         break;
+       default:
+       }
+
+      switch(cfg->tok)
+       {
+       case tok_menuoption:
+       case tok_comment:
+       case tok_menuname:
+         printf("%s\n", cfg->label);
+         break;
+       case tok_bool:
+       case tok_tristate:
+       case tok_dep_tristate:
+       case tok_int:
+         printf("%s %s %s\n", cfg->label, cfg->optionname, cfg->dflt);
+         break;
+       case tok_if:
+         dump_if(cfg->cond);
+         break;
+       case tok_nop:
+         break;
+       default:
+         printf("\n");
+       }
+    }
+#endif
+
+  return 0;
+
+}
diff --git a/scripts/tkparse.h b/scripts/tkparse.h
new file mode 100644 (file)
index 0000000..d1b758c
--- /dev/null
@@ -0,0 +1,64 @@
+
+enum token {
+  tok_menuname, 
+  tok_menuoption, 
+  tok_comment, 
+  tok_bool, 
+  tok_tristate, 
+  tok_dep_tristate,
+  tok_nop,
+  tok_if, 
+  tok_else, 
+  tok_fi, 
+  tok_int,
+  tok_unknown
+};
+
+enum operator {
+  op_eq,
+  op_neq,
+  op_and,
+  op_or,
+  op_bang,
+  op_lparen,
+  op_rparen,
+  op_variable,
+  op_kvariable,
+  op_constant,
+  op_nuked
+};
+
+union var
+{
+  char * str;
+  struct kconfig * cfg;
+};
+
+struct condition
+{
+  struct condition * next;
+  enum operator op;
+  union var variable;
+};
+
+#define GLOBAL_WRITTEN 1
+struct kconfig
+{
+  struct kconfig * next;
+  int flags;
+  enum token tok;
+  char   menu_number;
+  char   menu_line;
+  char   submenu_start;
+  char   submenu_end;
+  char * optionname;
+  char * dflt;
+  char * label;
+  union var depend;
+  struct condition * cond;
+};
+
+extern struct kconfig * config;
+extern struct kconfig * clast;
+extern struct kconfig * koption;
+