lines    added  deleted
linux/CREDITS                             :       7       -1       -1
linux/Documentation/Configure.help        :      54       24        2
linux/Documentation/filesystems/hpfs.txt  :     121       62       27
linux/Documentation/mtrr.txt              :      14        3        1
linux/MAINTAINERS                         :      33       18        8
linux/Makefile                            :      25       12        0
linux/arch/alpha/kernel/ptrace.c          :       7        1        1
linux/arch/alpha/lib/memcpy.c             :      26        0       20
linux/arch/arm/kernel/ptrace.c            :     154       77       11
linux/arch/i386/Makefile                  :      25        0       19
linux/arch/i386/boot/bootsect.S           :      13        7        0
linux/arch/i386/config.in                 :      14        2        2
linux/arch/i386/defconfig                 :      19        6        0
linux/arch/i386/kernel/mca.c              :      45       18        0
linux/arch/i386/kernel/ptrace.c           :     106       29       18
linux/arch/i386/kernel/setup.c            :      25        0       19
linux/arch/i386/kernel/signal.c           :      43       15        7
linux/arch/i386/mm/init.c                 :       7        1        0
linux/arch/i386/mm/ioremap.c              :      19        4        1
linux/arch/i386/vmlinux.lds               :      34        8        9
linux/arch/i386/vmlinux.lds.S             :      14        2        2
linux/arch/m68k/kernel/ptrace.c           :      69       69        0
linux/arch/mips/kernel/irixelf.c          :      25        0       19
linux/arch/mips/kernel/ptrace.c           :      42        4       11
linux/arch/mips/kernel/sysirix.c          :      25        0       19
linux/arch/ppc/chrpboot/Makefile          :      29        3        6
linux/arch/ppc/chrpboot/main.c            :      31        5        5
linux/arch/ppc/chrpboot/mknote.c          :      72       12       18
linux/arch/ppc/coffboot/zlib.c            :      43       43        0
linux/arch/ppc/common_defconfig           :      20        6        1
linux/arch/ppc/config.in                  :     157       62       14
linux/arch/ppc/defconfig                  :       7        1        0
linux/arch/ppc/kernel/chrp_pci.c          :     121       34       13
linux/arch/ppc/kernel/chrp_setup.c        :     106       74        5
linux/arch/ppc/kernel/head.S              :     145       61       26
linux/arch/ppc/kernel/idle.c              :      24        1        3
linux/arch/ppc/kernel/irq.c               :      14        2        1
linux/arch/ppc/kernel/misc.S              :      14        1        2
linux/arch/ppc/kernel/prom.c              :      11        4        0
linux/arch/ppc/kernel/ptrace.c            :      94       23        7
linux/arch/ppc/kernel/smp.c               :      25        0       19
linux/arch/ppc/kernel/syscalls.c          :      19        4        1
linux/arch/ppc/kernel/time.c              :      23        5        9
linux/arch/ppc/mm/init.c                  :      25        6        2
linux/arch/ppc/xmon/xmon.c                :      15        2        2
linux/arch/sparc/Makefile                 :       8        1        1
linux/arch/sparc/kernel/ebus.c            :      14        2        2
linux/arch/sparc/kernel/entry.S           :     161       75       17
linux/arch/sparc/kernel/head.S            :      59       49        1
linux/arch/sparc/kernel/pcic.c            :      45        9        3
linux/arch/sparc/kernel/ptrace.c          :     581      325       94
linux/arch/sparc/kernel/setup.c           :      26        0       20
linux/arch/sparc/kernel/sys_sunos.c       :      13        2        1
linux/arch/sparc64/Makefile               :      27        2        6
linux/arch/sparc64/defconfig              :      14        2        2
linux/arch/sparc64/kernel/binfmt_aout32.c :       8        2        0
linux/arch/sparc64/kernel/ioctl32.c       :      82       16       23
linux/arch/sparc64/kernel/ptrace.c        :      48       23        1
linux/arch/sparc64/kernel/signal.c        :      26        0       20
linux/arch/sparc64/kernel/sys_sparc.c     :     110        8       60
linux/arch/sparc64/kernel/sys_sparc32.c   :      45        1       34
linux/arch/sparc64/kernel/sys_sunos32.c   :     119       42       31
linux/arch/sparc64/kernel/systbls.S       :      27        2        6
linux/arch/sparc64/kernel/traps.c         :      14        2        2
linux/arch/sparc64/math-emu/sfp-util.h    :      25        9        4
linux/drivers/Makefile                    :      14        2        2
linux/drivers/block/cy82c693.c            :      15        9        0
linux/drivers/block/floppy.c              :       9        2        1
linux/drivers/block/ide-pmac.c            :      17        1        3
linux/drivers/block/ll_rw_blk.c           :      43        7       13
linux/drivers/block/ns87415.c             :      16        3        0
linux/drivers/block/piix.c                :      17        4        2
linux/drivers/block/rd.c                  :     252       88       52
linux/drivers/char/adbmouse.c             :       8        1        1
linux/drivers/char/bttv.c                 :       8        1        1
linux/drivers/char/bttv.h                 :      59       25        0
linux/drivers/char/misc.c                 :      47       19        1
linux/drivers/char/radio-cadet.c          :      19        5        1
linux/drivers/char/rtc.c                  :      35        7        8
linux/drivers/char/tuner.c                :     130       53       10
linux/drivers/char/tuner.h                :      10        3        1
linux/drivers/i2o/Config.in               :       7        1        0
linux/drivers/i2o/Makefile                :      12       12        0
linux/drivers/i2o/README                  :      75       75        0
linux/drivers/i2o/README.ioctl            :      78       78        0
linux/drivers/i2o/README.lan              :     398      398        0
linux/drivers/i2o/i2o_block.c             :      38       38        0
linux/drivers/i2o/i2o_config.c            :    1071     1071        0
linux/drivers/i2o/i2o_core.c              :     613      613        0
linux/drivers/i2o/i2o_lan.c               :    2053     2053        0
linux/drivers/i2o/i2o_lan.h               :     853      853        0
linux/drivers/i2o/i2o_pci.c               :     112      112        0
linux/drivers/i2o/i2o_proc.c              :     243      243        0
linux/drivers/i2o/i2o_proc.h              :    2382     2382        0
linux/drivers/i2o/i2o_scsi.c              :     141      141        0
linux/drivers/i2o/i2o_scsi.h              :     871      871        0
linux/drivers/macintosh/Makefile          :      48       48        0
linux/drivers/macintosh/adb.c             :       8        2        0
linux/drivers/macintosh/mac_keyb.c        :      34        4        3
linux/drivers/macintosh/macserial.c       :       7        0        1
linux/drivers/misc/BUGS-parport           :      52        8        8
linux/drivers/misc/Makefile               :       4        1        0
linux/drivers/misc/TODO-parport           :      10        4        0
linux/drivers/misc/parport_amiga.c        :       5        2        0
linux/drivers/misc/parport_arc.c          :      60       10       20
linux/drivers/misc/parport_atari.c        :      81       28       11
linux/drivers/misc/parport_ax.c           :      64       11       20
linux/drivers/misc/parport_init.c         :     111       26       37
linux/drivers/misc/parport_mfc3.c         :      50       12        5
linux/drivers/misc/parport_pc.c           :      53       10       16
linux/drivers/misc/parport_procfs.c       :     456      225       80
linux/drivers/misc/parport_share.c        :     726      321      296
linux/drivers/net/3c515.c                 :      90        9       40
linux/drivers/net/Config.in               :      23        3        0
linux/drivers/net/Makefile                :      20        7        0
linux/drivers/net/Space.c                 :      48       28        0
linux/drivers/net/cosa.c                  :      17        4        0
linux/drivers/net/cs89x0.c                :      35        8        1
linux/drivers/net/cycx_drv.c              :       8        1        1
linux/drivers/net/cycx_main.c             :     663      663        0
linux/drivers/net/cycx_x25.c              :     377      377        0
linux/drivers/net/irda/Config.in          :    1538     1538        0
linux/drivers/net/irda/Makefile           :       7        1        0
linux/drivers/net/irda/actisys.c          :      76       56        0
linux/drivers/net/irda/esi.c              :      39        3        8
linux/drivers/net/irda/girbil.c           :      37        3        7
linux/drivers/net/irda/irport.c           :      75       11       11
linux/drivers/net/irda/litelink.c         :     509      168       84
linux/drivers/net/irda/pc87108.c          :     110       15       18
linux/drivers/net/irda/smc-ircc.c         :     423      107      106
linux/drivers/net/irda/tekram.c           :     969      969        0
linux/drivers/net/irda/uircc.c            :      91       14       13
linux/drivers/net/irda/w83977af_ir.c      :      44        5        5
linux/drivers/net/myri_sbus.c             :      26        1        5
linux/drivers/net/ni52.c                  :       7        1        0
linux/drivers/net/ni52.h                  :       8        1        1
linux/drivers/net/ni65.c                  :       8        1        1
linux/drivers/net/ptifddi.c               :      36        6        2
linux/drivers/net/sdladrv.c               :       5        1        1
linux/drivers/net/sdlamain.c              :      33        1        5
linux/drivers/net/sk_mca.c                :      24        3        1
linux/drivers/net/sk_mca.h                :    1143     1143        0
linux/drivers/pci/oldproc.c               :     175      174        0
linux/drivers/sbus/char/Config.in         :      81       23        1
linux/drivers/sbus/char/aurora.c          :      10        6        0
linux/drivers/sbus/char/bpp.c             :      15        1        1
linux/drivers/sbus/char/pcikbd.c          :       8        1        1
linux/drivers/sbus/char/rtc.c             :     122       28       20
linux/drivers/sbus/char/su.c              :      36       10        3
linux/drivers/sbus/char/vfc_dev.c         :     611      181      195
linux/drivers/scsi/Config.in              :      19        2        3
linux/drivers/scsi/README.aic7xxx         :      12        2        4
linux/drivers/scsi/aic7xxx/aic7xxx.reg    :      63       17       12
linux/drivers/scsi/aic7xxx/aic7xxx.seq    :     145       78        0
linux/drivers/scsi/aic7xxx/scsi_message.h :     509      137      112
linux/drivers/scsi/aic7xxx.c              :      13        9        1
linux/drivers/scsi/aic7xxx_proc.c         :    3280     1316      669
linux/drivers/scsi/aic7xxx_reg.h          :     105       32       23
linux/drivers/scsi/aic7xxx_seq.c          :      91       42        0
linux/drivers/scsi/scsi.c                 :     986      344      315
linux/drivers/scsi/scsi.h                 :      18        3        2
linux/drivers/scsi/scsi_proc.c            :       7        1        0
linux/drivers/scsi/scsi_syms.c            :       8        1        1
linux/drivers/scsi/scsicam.c              :      22        2        3
linux/drivers/scsi/sd.c                   :      37        4        5
linux/drivers/scsi/sg.c                   :      28        4        4
linux/drivers/sound/dmasound.c            :    1160      407      270
linux/drivers/sound/sound_core.c          :      97       52        0
linux/drivers/usb/CREDITS                 :      31       17        1
linux/drivers/usb/Config.in               :       7        1        0
linux/drivers/usb/Makefile                :      12        5        1
linux/drivers/usb/README.ohci             :      31       16        0
linux/drivers/usb/acm.c                   :       9        6        0
linux/drivers/usb/audio.c                 :      34        6        6
linux/drivers/usb/cpia.c                  :      17        2        2
linux/drivers/usb/hub.c                   :      17        2        2
linux/drivers/usb/keyboard.c              :      39        6        6
linux/drivers/usb/keymap-mac.c            :      33        7        2
linux/drivers/usb/maps/mac.map            :      50       50        0
linux/drivers/usb/mkmap.adb               :     350      350        0
linux/drivers/usb/mouse.c                 :      88       88        0
linux/drivers/usb/ohci-debug.c            :      17        2        2
linux/drivers/usb/ohci.c                  :      83       21       17
linux/drivers/usb/ohci.h                  :     729      230      141
linux/drivers/usb/printer.c               :      53       14       12
linux/drivers/usb/stopusb                 :      35        6        5
linux/drivers/usb/uhci.c                  :       9        2        2
linux/drivers/usb/uhci.h                  :     362      150       49
linux/drivers/usb/usb-core.c              :      11        2        1
linux/drivers/usb/usb-debug.c             :      18        4        1
linux/drivers/usb/usb.c                   :      22       11        4
linux/drivers/usb/usb.h                   :     336      136       40
linux/drivers/usb/usb_scsi.c              :     151       66       20
linux/drivers/usb/usb_scsi.h              :    1098     1098        0
linux/drivers/usb/usb_scsi_debug.c        :     145      145        0
linux/drivers/usb/usb_scsi_dt.c           :     104      104        0
linux/drivers/video/atyfb.c               :       4        4        0
linux/drivers/video/igafb.c               :     192       40       21
linux/fs/Config.in                        :      88       32       12
linux/fs/adfs/super.c                     :      12        3        3
linux/fs/affs/super.c                     :      18        2        3
linux/fs/autofs/inode.c                   :       8        1        1
linux/fs/binfmt_aout.c                    :       8        1        1
linux/fs/binfmt_elf.c                     :      69        8       22
linux/fs/buffer.c                         :      53        6       14
linux/fs/coda/inode.c                     :       8        1        1
linux/fs/dcache.c                         :      17        2        2
linux/fs/devpts/inode.c                   :       8        1        1
linux/fs/efs/super.c                      :       8        1        1
linux/fs/ext2/super.c                     :       8        1        1
linux/fs/ext2/symlink.c                   :       8        1        1
linux/fs/fat/inode.c                      :       7        0        1
linux/fs/fcntl.c                          :       8        1        1
linux/fs/hfs/bnode.c                      :      74       31       22
linux/fs/hfs/btree.c                      :       8        2        0
linux/fs/hfs/catalog.c                    :       8        1        1
linux/fs/hfs/mdb.c                        :       8        2        0
linux/fs/hfs/super.c                      :      10        3        1
linux/fs/hpfs/alloc.c                     :       8        1        1
linux/fs/hpfs/hpfs_fn.h                   :      13        5        2
linux/fs/hpfs/namei.c                     :       8        1        1
linux/fs/hpfs/super.c                     :      32        6       11
linux/fs/isofs/inode.c                    :       8        1        1
linux/fs/minix/bitmap.c                   :       8        1        1
linux/fs/minix/inode.c                    :      35        4        4
linux/fs/minix/namei.c                    :       8        1        1
linux/fs/ncpfs/inode.c                    :      13        1        6
linux/fs/nfs/dir.c                        :       8        1        1
linux/fs/nfs/inode.c                      :     733      335      229
linux/fs/nfs/nfs2xdr.c                    :     101       22       10
linux/fs/nfs/proc.c                       :     297      104       98
linux/fs/nfs/read.c                       :      86        0       73
linux/fs/nfs/symlink.c                    :       7        1        0
linux/fs/nfs/write.c                      :     197      121       50
linux/fs/nfsd/export.c                    :      43       16        3
linux/fs/nfsd/nfsfh.c                     :      19        2        3
linux/fs/ntfs/fs.c                        :      26        3        3
linux/fs/pipe.c                           :       8        1        1
linux/fs/proc/Makefile                    :       8        1        1
linux/fs/proc/inode.c                     :       8        1        1
linux/fs/proc/link.c                      :       8        1        1
linux/fs/proc/root.c                      :       8        1        1
linux/fs/proc/sysvipc.c                   :      18        4        1
linux/fs/qnx4/inode.c                     :     138      138        0
linux/fs/romfs/inode.c                    :       8        1        1
linux/fs/smbfs/dir.c                      :       8        1        1
linux/fs/smbfs/inode.c                    :       8        1        1
linux/fs/super.c                          :       8        1        1
linux/fs/sysv/inode.c                     :      33       13       13
linux/fs/ufs/super.c                      :       8        1        1
linux/fs/umsdos/check.c                   :       8        1        1
linux/include/asm-alpha/softirq.h         :       8        1        1
linux/include/asm-alpha/spinlock.h        :      16       10        0
linux/include/asm-alpha/string.h          :     100       29       37
linux/include/asm-alpha/system.h          :       7        1        0
linux/include/asm-i386/bugs.h             :      11        5        0
linux/include/asm-i386/page.h             :      21       11        3
linux/include/asm-i386/page_offset.h      :      11        4        1
linux/include/asm-mips/namei.h            :       8        8        0
linux/include/asm-ppc/system.h            :       8        1        1
linux/include/asm-sparc/io.h              :      18        5        0
linux/include/asm-sparc/namei.h           :      21       10        1
linux/include/asm-sparc/pcic.h            :       8        1        1
linux/include/asm-sparc64/namei.h         :      52       16        2
linux/include/linux/cyclomx.h             :       8        1        1
linux/include/linux/cycx_cfm.h            :      91       91        0
linux/include/linux/cycx_drv.h            :      81       81        0
linux/include/linux/cycx_x25.h            :      66       66        0
linux/include/linux/dcache.h              :     103      103        0
linux/include/linux/file.h                :      57        7       10
linux/include/linux/fs.h                  :      19        4        4
linux/include/linux/i2o.h                 :     277       59       65
linux/include/linux/igmp.h                :     588      588        0
linux/include/linux/inet.h                :      20        1       13
linux/include/linux/inetdevice.h          :       7        1        0
linux/include/linux/mm.h                  :       8        1        1
linux/include/linux/netdevice.h           :      16        3        0
linux/include/linux/nfs.h                 :      29        9        0
linux/include/linux/nfs_fs.h              :      39        8        9
linux/include/linux/nfs_fs_i.h            :      37        2        7
linux/include/linux/pagemap.h             :      10        4        0
linux/include/linux/parport.h             :       7        1        0
linux/include/linux/pci.h                 :      60        7       10
linux/include/linux/pkt_sched.h           :      71       22        1
linux/include/linux/proc_fs.h             :       9        3        0
linux/include/linux/rtnetlink.h           :      46       11        1
linux/include/linux/sched.h               :     152       15      114
linux/include/linux/sysctl.h              :      79       21       24
linux/include/linux/wanrouter.h           :      43       31        1
linux/include/net/addrconf.h              :      49        9        2
linux/include/net/dst.h                   :      16        2        1
linux/include/net/if_inet6.h              :       9        3        0
linux/include/net/ip.h                    :      15        2        0
linux/include/net/irda/dongle.h           :      13        3        3
linux/include/net/irda/ircomm_common.h    :      27        4        4
linux/include/net/irda/irda_device.h      :      23        5        5
linux/include/net/irda/irlan_common.h     :      25        3        3
linux/include/net/irda/irlan_eth.h        :      36        7        2
linux/include/net/irda/irport.h           :      20        3        2
linux/include/net/irda/irqueue.h          :      25        4        3
linux/include/net/irda/irvtd.h            :      17        1        3
linux/include/net/irda/smc-ircc.h         :      18        4        1
linux/include/net/irda/smc_ircc.h         :     160      160        0
linux/include/net/neighbour.h             :     123        0      123
linux/include/net/pkt_cls.h               :      76       16       23
linux/include/net/pkt_sched.h             :      17        3        6
linux/include/net/route.h                 :     138       88        7
linux/include/net/tcp.h                   :      21        1        7
linux/include/net/udp.h                   :       8        1        1
linux/include/scsi/scsicam.h              :      15        7        1
linux/include/scsi/sg.h                   :       6        2        0
linux/ipc/msg.c                           :     272       87       90
linux/ipc/sem.c                           :      95       59        1
linux/ipc/shm.c                           :      90       56        0
linux/kernel/ksyms.c                      :      96       60        0
linux/kernel/signal.c                     :      16        2        1
linux/kernel/sys.c                        :      24        3        1
linux/mm/memory.c                         :       8        2        0
linux/mm/mmap.c                           :     120       18       31
linux/mm/mremap.c                         :     186      110       20
linux/mm/swapfile.c                       :      30        2        2
linux/net/core/dev.c                      :      16        2        1
linux/net/core/dev_mcast.c                :     497      104      131
linux/net/core/dst.c                      :     156       34       16
linux/net/core/neighbour.c                :      66       38        4
linux/net/core/rtnetlink.c                :     886      223      113
linux/net/decnet/dn_neigh.c               :      90        9       21
linux/net/ethernet/eth.c                  :      41       10        4
linux/net/ipv4/af_inet.c                  :       7        1        0
linux/net/ipv4/arp.c                      :      17        2        2
linux/net/ipv4/devinet.c                  :     264       38       46
linux/net/ipv4/fib_frontend.c             :      78       10       10
linux/net/ipv4/fib_hash.c                 :      22        1        3
linux/net/ipv4/fib_rules.c                :     207       17       21
linux/net/ipv4/icmp.c                     :     146       21       19
linux/net/ipv4/igmp.c                     :      39        6        6
linux/net/ipv4/ip_input.c                 :     333       81       19
linux/net/ipv4/ip_masq_vdolive.c          :      32        3        7
linux/net/ipv4/ip_options.c               :       8        1        1
linux/net/ipv4/ipconfig.c                 :       8        1        1
linux/net/ipv4/ipmr.c                     :      24        3        3
linux/net/ipv4/route.c                    :      36        6        3
linux/net/ipv4/tcp_input.c                :      28        4        3
linux/net/ipv4/tcp_ipv4.c                 :       8        1        1
linux/net/ipv4/udp.c                      :       8        1        1
linux/net/ipv4/utils.c                    :     114       51       19
linux/net/ipv6/addrconf.c                 :      20        6        1
linux/net/ipv6/af_inet6.c                 :     102       13       16
linux/net/ipv6/ip6_fw.c                   :      17        2        2
linux/net/ipv6/ip6_output.c               :      17        2        2
linux/net/ipv6/mcast.c                    :      31        4       13
linux/net/ipv6/ndisc.c                    :     378       76       22
linux/net/ipv6/raw.c                      :     163       29       23
linux/net/ipv6/reassembly.c               :      26        1       12
linux/net/ipv6/route.c                    :       8        1        1
linux/net/ipv6/tcp_ipv6.c                 :      46       12        3
linux/net/ipv6/udp.c                      :       8        1        1
linux/net/irda/Config.in                  :      27        1       13
linux/net/irda/af_irda.c                  :      54       20       23
linux/net/irda/discovery.c                :      72       12        8
linux/net/irda/ircomm/ircomm_common.c     :      41        8        6
linux/net/irda/ircomm/irvtd_driver.c      :     168       32       27
linux/net/irda/irda_device.c              :     374      114       43
linux/net/irda/irlan/irlan_client.c       :     207       66       30
linux/net/irda/irlan/irlan_client_event.c :      30        8        2
linux/net/irda/irlan/irlan_common.c       :       8        1        1
linux/net/irda/irlan/irlan_eth.c          :     293       93       34
linux/net/irda/irlan/irlan_filter.c       :     208       50       56
linux/net/irda/irlap.c                    :      16        2        1
linux/net/irda/irlap_event.c              :    1069      273      273
linux/net/irda/irlap_frame.c              :     264       31       64
linux/net/irda/irlmp.c                    :      44        2       15
linux/net/irda/irlmp_frame.c              :      45        8       10
linux/net/irda/irmod.c                    :      31        6        6
linux/net/irda/irttp.c                    :      17        2        2
linux/net/irda/wrapper.c                  :     244       37       49
linux/net/netrom/nr_route.c               :      52       10        6
linux/net/netsyms.c                       :      31        4        4
linux/net/packet/af_packet.c              :      17        1        3
linux/net/rose/rose_route.c               :      85       16       13
linux/net/sched/cls_api.c                 :      31        4        4
linux/net/sched/cls_fw.c                  :     118       33        8
linux/net/sched/cls_route.c               :      83       14        9
linux/net/sched/cls_rsvp.h                :     125       23       16
linux/net/sched/cls_u32.c                 :      72       12        8
linux/net/sched/estimator.c               :      70       12        7
linux/net/sched/police.c                  :      65       19        7
linux/net/sched/sch_api.c                 :      96       22        3
linux/net/sched/sch_cbq.c                 :     234       68       19
linux/net/sched/sch_csz.c                 :     155       41       15
linux/net/sched/sch_generic.c             :      34        4        4
linux/net/sched/sch_prio.c                :     450      213       71
linux/net/sched/sch_sfq.c                 :      44        9        4
linux/net/sched/sch_tbf.c                 :      17        2        2
linux/net/sched/sch_teql.c                :      17        2        2
linux/net/socket.c                        :      79       27       11
linux/net/sunrpc/xprt.c                   :       8        1        1
linux/net/wanrouter/wanmain.c             :     139       64       13
linux/net/x25/af_x25.c                    :      56        9        6
-- 
Thomas Koenig, Thomas...@ciw.uni-karlsruhe.de, ig...@dkauni2.bitnet.
The joy of engineering is to find a straight line on a double
logarithmic diagram.
#!/bin/sh
# This is a shell archive
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
# existing files will NOT be overwritten unless -c is specified
#
# This is part 01 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
#
if test -r _shar_seq_.tmp; then
        echo 'Must unpack archives in sequence!'
        echo Please unpack part `cat _shar_seq_.tmp` next
        exit 1
fi
# ============= patch-2.3.6 ==============
if test -f 'patch-2.3.6' -a X"$1" != X"-c"; then
        echo 'x - skipping patch-2.3.6 (File already exists)'
        rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting patch-2.3.6 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'patch-2.3.6' &&
diff -u --recursive --new-file v2.3.5/linux/CREDITS linux/CREDITS
--- v2.3.5/linux/CREDITS	Mon May 31 22:28:04 1999
+++ linux/CREDITS	Tue Jun  8 10:27:18 1999
@@ -16,6 +16,14 @@
X S: (ask for current address)
X S: Finland
X 
+N: Dragos Acostachioaie
+E: dra...@iname.com
+W: http://www.arbornet.org/~dragos
+D: /proc/sysvipc
+S: C. Negri 6, bl. D3
+S: Iasi 6600
+S: Romania
+
X N: Dave Airlie
X E: air...@linux.ie
X W: http://www.csn.ul.ie/~airlied
@@ -821,7 +829,7 @@
X S: Germany
X 
X N: Michael Hipp
-E: mh...@student.uni-tuebingen.de
+E: hi...@informatik.uni-tuebingen.de
X D: drivers for the racal ni5210 & ni6510 Ethernet-boards
X S: Talstr. 1
X S: D - 72072 Tuebingen
@@ -1349,8 +1357,11 @@
X 
X N: Arnaldo Carvalho de Melo
X E: ac...@conectiva.com.br
+W: http://www.conectiva.com.br/~acme
X D: wanrouter hacking
-D: cyclades 2X sync card driver (still in early devel stage)
+D: Cyclom 2X synchronous card driver
+D: i18n for minicom, net-tools, util-linux, fetchmail, etc
+S: Conectiva Informatica LTDA
X S: R. Prof. Rubens Elke Braga, 558 - Parolin
X S: 80220-320 Curitiba - Parana
X S: Brazil
@@ -1929,6 +1940,17 @@
X S: 1050 Woodduck Avenue
X S: Santa Clara, California 95051
X S: USA
+
+N: Marcelo W. Tosatti
+E: mar...@conectiva.com.br
+W: http://lie-br.conectiva.com.br/~marcelo/
+D: Miscellaneous kernel hacker
+D: Cyclom 2X driver hacker
+D: linuxconf apache & proftpd module maintainer
+S: Conectiva Informatica LTDA
+S: R. Prof. Rubens Elke Braga, 558 - Parolin
+S: 80220-320 Curitiba - Parana
+S: Brazil
X 
X N: Stefan Traby
X E: ste...@quant-x.com
diff -u --recursive --new-file v2.3.5/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.5/linux/Documentation/Configure.help	Mon May 31 22:28:04 1999
+++ linux/Documentation/Configure.help	Wed Jun  9 16:59:15 1999
@@ -3958,34 +3958,49 @@
X   say M here and read Documentation/modules.txt. The module will be
X   called aic7xxx.o.
X 
-Override driver defaults for commands per LUN
-CONFIG_OVERRIDE_CMDS
-  Say Y here if you want to override the default maximum number of
-  commands that a single device on the aic7xxx controller is allowed
-  to have active at one time. This option only affects tagged queueing
-  capable devices. The driver uses a value of 24 by default.
-  If you say Y here, you can adjust the number of commands per LUN
-  with the following configuration option.
+Enable or Disable Tagged Command Queueing by default
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+  This option causes the aic7xxx driver to attempt to use tagged command
+  queueing on any devices that claim to support it.  If this is set to yes,
+  you can still turn off TCQ on troublesome devices with the use of the
+  tag_info boot parameter.  See /usr/src/linux/drivers/scsi/README.aic7xxx
+  for more information on that and other aic7xxx setup commands.  If this
+  option is turned off, you may still enable TCQ on known good devices by
+  use of the tag_info boot parameter.
X   
-  If unsure, say N.
-
-Maximum number of commands per LUN
-CONFIG_AIC7XXX_CMDS_PER_LUN
-  Specify the maximum number of commands you would like to allocate
-  per LUN (a LUN is a Logical Unit Number -- some physical SCSI
-  devices, e.g. CD jukeboxes, act logically as several separate units,
-  each of which gets its own number).
+  If you are unsure about your devices then it is safest to say N here.
+  
+  However, TCQ can increase performance on some hard drives by as much
+  as 50% or more, so I would recommend that if you say N here, that you
+  at least read the README.aic7xxx file so you will know how to enable
+  this option manually should your drives prove to be safe in regards
+  to TCQ.
+
+  Conversely, certain drives are known to lock up or cause bus resets when
+  TCQ is enabled on them.  If you have a Western Digital Enterprise SCSI
+  drive for instance, then don't even bother to enable TCQ on it as the
+  drive will become unreliable, and it will actually reduce performance.
+
+Default number of TCQ commands per device
+CONFIG_AIC7XXX_CMDS_PER_DEVICE
+  Specify the number of commands you would like to allocate per SCSI
+  device when Tagged Command Queueing (TCQ) is enabled on that device.
X 
-  Reasonable figures are in the range of 14 to 32 commands per device,
+  Reasonable figures are in the range of 8 to 24 commands per device,
X   but depending on hardware could be increased or decreased from that
X   figure. If the number is too high for any particular device, the
X   driver will automatically compensate usually after only 10 minutes
-  of uptime and will issue a message to alert you to the fact that the
-  number of commands for that device has been reduced. It will not
-  hinder performance if some of your devices eventually have their
-  commands per LUN reduced, but is a waste of memory if all of your
-  devices end up reducing this number down to a more reasonable
-  figure. Default: 24
+  of uptime. It will not hinder performance if some of your devices
+  eventually have their command depth reduced, but is a waste of memory
+  if all of your devices end up reducing this number down to a more
+  reasonable figure.
+  
+  NOTE: Certain very broken drives are known to lock up when given more
+  commands than they like to deal with.  Quantum Fireball drives are the
+  most common in this category.  For the Quantum Fireball drives I would
+  suggest no more than 8 commands per device.
+
+  Default: 8
X 
X Collect statistics to report in /proc
X CONFIG_AIC7XXX_PROC_STATS
@@ -6369,6 +6384,20 @@
X   module, say M here and read Documentation/modules.txt as well as
X   Documentation/networking/net-modules.txt.
X 
+SKnet MCA support
+CONFIG_SKMC
+  This are Micro Channel ethernet adapters.  You need to set CONFIG_MCA
+  to use this driver.  It's both available as an in-kernel driver and
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). If you want to compile it as a module,
+  say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt. If you plan to use more than
+  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
+  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.  Supported
+  cards are the SKnet Junior MC2 and the SKnet MC2(+).  Distinguishing
+  both cards is done automatically.  Note that using multiple boards
+  of different type hasn't been tested with this driver.
+
X EISA, VLB, PCI and on board controllers
X CONFIG_NET_EISA
X   This is another class of network cards which attach directly to the
@@ -8936,8 +8965,8 @@
X 
X Zilog serial support
X CONFIG_SUN_ZS
-  This driver does not exist at this point, so you might as well 
-  say N.
+  If you are asked this question, something is wrong with config scripts.
+  Zilog serial driver is always enabled in sparc architecture.
X 
X Double Talk PC internal speech card support
X CONFIG_DTLK
@@ -10338,8 +10367,14 @@
X   inserted in and removed from the running kernel whenever you want),
X   say M and read Documentation/modules.txt. If unsure, say Y.
X 
-#Mostek real time clock support
-#CONFIG_SUN_MOSTEK_RTC
+Mostek real time clock support
+CONFIG_SUN_MOSTEK_RTC
+  The Mostek RTC chip is used on all knows Sun computers except
+  some JavaStation-s. For a JavaStation you need to say Y both here
+  and to CONFIG_RTC.
+
+  Say Y here unless you are building a special purpose kernel.
+
X #
X #Siemens SAB82532 serial support
X #CONFIG_SAB82532
diff -u --recursive --new-file v2.3.5/linux/Documentation/filesystems/hpfs.txt linux/Documentation/filesystems/hpfs.txt
--- v2.3.5/linux/Documentation/filesystems/hpfs.txt	Mon May 17 09:55:20 1999
+++ linux/Documentation/filesystems/hpfs.txt	Fri Jun  4 01:06:29 1999
@@ -1,4 +1,4 @@
-Read/Write HPFS 1.99b
+Read/Write HPFS 2.00
X 1998-1999, Mikulas Patocka
X 
X email: mik...@artax.karlin.mff.cuni.cz
@@ -267,6 +267,8 @@
X 	file
X      Now it tries to truncate the file if there's not enough space when deleting
X      Removed a lot of redundat code
+2.00 Fixed a bug in rename (it was there since 1.96)
+     Better anti-fragmentation strategy
X 
X 
X  vim: set textwidth=80:
diff -u --recursive --new-file v2.3.5/linux/Documentation/mtrr.txt linux/Documentation/mtrr.txt
--- v2.3.5/linux/Documentation/mtrr.txt	Mon May 17 09:55:20 1999
+++ linux/Documentation/mtrr.txt	Thu Jun  3 08:17:28 1999
@@ -1,15 +1,25 @@
X MTRR (Memory Type Range Register) control
-16 May 1999
+3 Jun 1999
X Richard Gooch
X <rgo...@atnf.csiro.au>
X 
-  On Intel Pentium Pro/Pentium II systems the Memory Type Range
-  Registers (MTRRs) may be used to control processor access to memory
-  ranges. This is most useful when you have a video (VGA) card on a
-  PCI or AGP bus. Enabling write-combining allows bus write transfers
-  to be combined into a larger transfer before bursting over the
-  PCI/AGP bus. This can increase performance of image write operations
-  2.5 times or more.
+  On Intel P6 family processors (Pentium Pro, Pentium II and later)
+  the Memory Type Range Registers (MTRRs) may be used to control
+  processor access to memory ranges. This is most useful when you have
+  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
+  allows bus write transfers to be combined into a larger transfer
+  before bursting over the PCI/AGP bus. This can increase performance
+  of image write operations 2.5 times or more.
+
+  The Cyrix 6x86, 6x86MX and M II processors have Address Range
+  Registers (ARRs) which provide a similar functionality to MTRRs. For
+  these, the ARRs are used to emulate the MTRRs.
+
+  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
+  MTRRs. These are supported.
+  
+  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
+  are supported.
X 
X   The CONFIG_MTRR option creates a /proc/mtrr file which may be used
X   to manipulate your MTRRs. Typically the X server should use
diff -u --recursive --new-file v2.3.5/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.5/linux/MAINTAINERS	Mon May 17 09:55:20 1999
+++ linux/MAINTAINERS	Thu Jun  3 08:26:42 1999
@@ -192,6 +192,13 @@
X M:	j...@acm.org
X S:	Maintained
X 
+CYCLADES 2X SYNC CARD DRIVER
+P:	Arnaldo Carvalho de Melo
+M:	ac...@conectiva.com.br
+W:	http://www.conectiva.com.br/~acme
+L:	cycsyn...@bazar.conectiva.com.br
+S:	Maintained
+
X CYCLADES ASYNC MUX DRIVER
X P:	Ivan Passos
X M:	Ivan Passos <iv...@cyclades.com>
@@ -390,6 +397,11 @@
X M:	Paul.R...@rustcorp.com.au
X W:	http://www.rustcorp.com/linux/ipchains
X S:	Supported
+
+IP MASQUERADING:
+P:	Juanjo Ciarlante
+M:	jjci...@raiz.uncu.edu.ar
+S:	Maintained
X 
X IPX/SPX NETWORK LAYER
X P:	Jay Schulist
diff -u --recursive --new-file v2.3.5/linux/Makefile linux/Makefile
--- v2.3.5/linux/Makefile	Wed Jun  2 14:44:39 1999
+++ linux/Makefile	Wed Jun  2 14:40:19 1999
@@ -1,6 +1,6 @@
X VERSION = 2
X PATCHLEVEL = 3
-SUBLEVEL = 5
+SUBLEVEL = 6
X EXTRAVERSION =
X 
X ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.5/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.3.5/linux/arch/alpha/kernel/ptrace.c	Mon May 31 22:28:04 1999
+++ linux/arch/alpha/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -246,26 +246,6 @@
X 	flush_tlb();
X }
X 
-static struct vm_area_struct *
-find_extend_vma(struct task_struct * tsk, unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm,addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/alpha/lib/memcpy.c linux/arch/alpha/lib/memcpy.c
--- v2.3.5/linux/arch/alpha/lib/memcpy.c	Tue Apr  7 08:05:05 1998
+++ linux/arch/alpha/lib/memcpy.c	Mon Jun  7 11:37:13 1999
@@ -21,30 +21,44 @@
X  * This should be done in one go with ldq_u*2/mask/stq_u. Do it
X  * with a macro so that we can fix it up later..
X  */
-#define ALIGN_DEST_TO8(d,s,n) \
+#define ALIGN_DEST_TO8_UP(d,s,n) \
X 	while (d & 7) { \
X 		if (n <= 0) return; \
X 		n--; \
X 		*(char *) d = *(char *) s; \
X 		d++; s++; \
X 	}
+#define ALIGN_DEST_TO8_DN(d,s,n) \
+	while (d & 7) { \
+		if (n <= 0) return; \
+		n--; \
+		d--; s--; \
+		*(char *) d = *(char *) s; \
+	}
X 
X /*
X  * This should similarly be done with ldq_u*2/mask/stq. The destination
X  * is aligned, but we don't fill in a full quad-word
X  */
-#define DO_REST(d,s,n) \
+#define DO_REST_UP(d,s,n) \
X 	while (n > 0) { \
X 		n--; \
X 		*(char *) d = *(char *) s; \
X 		d++; s++; \
X 	}
+#define DO_REST_DN(d,s,n) \
+	while (n > 0) { \
+		n--; \
+		d--; s--; \
+		*(char *) d = *(char *) s; \
+	}
X 
X /*
X  * This should be done with ldq/mask/stq. The source and destination are
X  * aligned, but we don't fill in a full quad-word
X  */
-#define DO_REST_ALIGNED(d,s,n) DO_REST(d,s,n)
+#define DO_REST_ALIGNED_UP(d,s,n) DO_REST_UP(d,s,n)
+#define DO_REST_ALIGNED_DN(d,s,n) DO_REST_DN(d,s,n)
X 
X /*
X  * This does unaligned memory copies. We want to avoid storing to
@@ -53,9 +67,10 @@
X  *
X  * Note the ordering to try to avoid load (and address generation) latencies.
X  */
-static inline void __memcpy_unaligned(unsigned long d, unsigned long s, long n)
+static inline void __memcpy_unaligned_up (unsigned long d, unsigned long s,
+					  long n)
X {
-	ALIGN_DEST_TO8(d,s,n);
+	ALIGN_DEST_TO8_UP(d,s,n);
X 	n -= 8;			/* to avoid compare against 8 in the loop */
X 	if (n >= 0) {
X 		unsigned long low_word, high_word;
@@ -77,7 +92,17 @@
X 		} while (n >= 0);
X 	}
X 	n += 8;
-	DO_REST(d,s,n);
+	DO_REST_UP(d,s,n);
+}
+
+static inline void __memcpy_unaligned_dn (unsigned long d, unsigned long s,
+					  long n)
+{
+	/* I don't understand AXP assembler well enough for this. -Tim */
+	s += n;
+	d += n;
+	while (n--)
+		* (char *) --d = * (char *) --s;
X }
X 
X /*
@@ -88,9 +113,10 @@
X  *
X  * Note the ordering to try to avoid load (and address generation) latencies.
X  */
-static inline void __memcpy_aligned(unsigned long d, unsigned long s, long n)
+static inline void __memcpy_aligned_up (unsigned long d, unsigned long s,
+					long n)
X {
-	ALIGN_DEST_TO8(d,s,n);
+	ALIGN_DEST_TO8_UP(d,s,n);
X 	n -= 8;
X 	while (n >= 0) {
X 		unsigned long tmp;
@@ -101,18 +127,58 @@
X 		d += 8;
X 	}
X 	n += 8;
-	DO_REST_ALIGNED(d,s,n);
+	DO_REST_ALIGNED_UP(d,s,n);
+}
+static inline void __memcpy_aligned_dn (unsigned long d, unsigned long s,
+					long n)
+{
+	s += n;
+	d += n;
+	ALIGN_DEST_TO8_DN(d,s,n);
+	n -= 8;
+	while (n >= 0) {
+		unsigned long tmp;
+		s -= 8;
+		__asm__("ldq %0,%1":"=r" (tmp):"m" (*(unsigned long *) s));
+		n -= 8;
+		d -= 8;
+		*(unsigned long *) d = tmp;
+	}
+	n += 8;
+	DO_REST_ALIGNED_DN(d,s,n);
X }
X 
X void * memcpy(void * dest, const void *src, size_t n)
X {
X 	if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) {
-		__memcpy_aligned((unsigned long) dest, (unsigned long) src, n);
+		__memcpy_aligned_up ((unsigned long) dest, (unsigned long) src,
+				     n);
X 		return dest;
X 	}
-	__memcpy_unaligned((unsigned long) dest, (unsigned long) src, n);
+	__memcpy_unaligned_up ((unsigned long) dest, (unsigned long) src, n);
X 	return dest;
X }
X 
X /* For backward modules compatibility, define __memcpy.  */
X asm("__memcpy = memcpy; .globl __memcpy");
+
+void *memmove (void *dest, const void *src, size_t n)
+{
+	if (dest <= src) {
+		if (!(((unsigned long) dest ^ (unsigned long) src) & 7))
+			__memcpy_aligned_up ((unsigned long) dest,
+					     (unsigned long) src, n);
+		else
+			__memcpy_unaligned_up ((unsigned long) dest,
+					       (unsigned long) src, n);
+	}
+	else {
+		if (!(((unsigned long) dest ^ (unsigned long) src) & 7))
+			__memcpy_aligned_dn ((unsigned long) dest,
+					     (unsigned long) src, n);
+		else
+			__memcpy_unaligned_dn ((unsigned long) dest,
+					       (unsigned long) src, n);
+	}
+	return dest;
+}
diff -u --recursive --new-file v2.3.5/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
--- v2.3.5/linux/arch/arm/kernel/ptrace.c	Mon May 31 22:28:04 1999
+++ linux/arch/arm/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -164,25 +164,6 @@
X 	flush_tlb();
X }
X 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm,addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.3.5/linux/arch/i386/Makefile	Mon May 17 09:55:20 1999
+++ linux/arch/i386/Makefile	Mon Jun  7 17:02:23 1999
@@ -67,6 +67,13 @@
X 
X MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
X 
+vmlinux: arch/i386/vmlinux.lds
+
+arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE
+	gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds
+
+FORCE: ;
+
X zImage: vmlinux
X 	@$(MAKEBOOT) zImage
X 
diff -u --recursive --new-file v2.3.5/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S
--- v2.3.5/linux/arch/i386/boot/bootsect.S	Wed Jun 24 14:30:08 1998
+++ linux/arch/i386/boot/bootsect.S	Tue Jun  8 10:47:57 1999
@@ -58,12 +58,12 @@
X 	mov	ds,ax
X 	mov	ax,#INITSEG
X 	mov	es,ax
-	mov	cx,#256
+	mov	cx,#128
X 	sub	si,si
X 	sub	di,di
X 	cld
X 	rep
-	movsw
+	movsd
X 	jmpi	go,INITSEG
X 
X ! ax and es already contain INITSEG
diff -u --recursive --new-file v2.3.5/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.5/linux/arch/i386/config.in	Fri May 14 18:55:11 1999
+++ linux/arch/i386/config.in	Mon Jun  7 17:02:23 1999
@@ -33,6 +33,10 @@
X   define_bool CONFIG_X86_GOOD_APIC y
X fi
X 
+choice 'Maximum Physical Memory' \
+	"1GB		CONFIG_1GB \
+	 2GB		CONFIG_2GB" 1GB
+
X bool 'Math emulation' CONFIG_MATH_EMULATION
X bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
X bool 'Symmetric multi-processing support' CONFIG_SMP
@@ -113,6 +117,8 @@
X fi
X 
X endmenu
+
+source drivers/i2o/Config.in
X 
X source drivers/pnp/Config.in
X 
diff -u --recursive --new-file v2.3.5/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.5/linux/arch/i386/defconfig	Wed Jun  2 14:44:39 1999
+++ linux/arch/i386/defconfig	Mon Jun  7 22:12:01 1999
@@ -21,6 +21,8 @@
X CONFIG_X86_POPAD_OK=y
X CONFIG_X86_TSC=y
X CONFIG_X86_GOOD_APIC=y
+CONFIG_1GB=y
+# CONFIG_2GB is not set
X # CONFIG_MATH_EMULATION is not set
X # CONFIG_MTRR is not set
X CONFIG_SMP=y
@@ -58,6 +60,16 @@
X # CONFIG_APM is not set
X 
X #
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
X # Plug and Play support
X #
X # CONFIG_PNP is not set
@@ -243,6 +255,11 @@
X # CONFIG_HAMRADIO is not set
X 
X #
+# IrDA subsystem support
+#
+# CONFIG_IRDA is not set
+
+#
X # ISDN subsystem
X #
X # CONFIG_ISDN is not set
@@ -308,6 +325,7 @@
X # CONFIG_USB_AUDIO is not set
X # CONFIG_USB_ACM is not set
X # CONFIG_USB_PRINTER is not set
+# CONFIG_USB_SCSI is not set
X 
X #
X # Filesystems
diff -u --recursive --new-file v2.3.5/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.3.5/linux/arch/i386/kernel/mca.c	Mon May 10 13:00:10 1999
+++ linux/arch/i386/kernel/mca.c	Mon Jun  7 16:17:59 1999
@@ -112,21 +112,25 @@
X static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *);
X 
X static struct file_operations proc_mca_operations = {
-	NULL,			/* array_lseek */
-	proc_mca_read,		/* array_read */
-	NULL,			/* array_write */
-	NULL,			/* array_readdir */
-	NULL,			/* array_poll */
-	NULL,			/* array_ioctl */
+	NULL,			/* llseek */
+	proc_mca_read,		/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	NULL,			/* ioctl */
X 	NULL,			/* mmap */
-	NULL,			/* no special open code */
+	NULL,			/* open */
X 	NULL,			/* flush */
-	NULL,			/* no special release code */
-	NULL			/* can't fsync */
+	NULL,			/* release */
+	NULL,			/* fsync */
+	NULL,			/* fascync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
X };
X 
X static struct inode_operations proc_mca_inode_operations = {
-	&proc_mca_operations,	/* default base directory file-ops */
+	&proc_mca_operations,	/* default file-ops */
X 	NULL,			/* create */
X 	NULL,			/* lookup */
X 	NULL,			/* link */
@@ -142,7 +146,10 @@
X 	NULL,			/* writepage */
X 	NULL,			/* bmap */
X 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL			/* revalidate */
X };
X #endif
X 
@@ -220,18 +227,19 @@
X 	if(!MCA_bus)
X 		return;
X 	printk("Micro Channel bus detected.\n");
-	save_flags(flags);
-	cli();
X 
X 	/* Allocate MCA_info structure (at address divisible by 8) */
X 
-	mca_info = kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
+	mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
X 
X 	if(mca_info == NULL) {
X 		printk("Failed to allocate memory for mca_info!");
-		restore_flags(flags);
X 		return;
X 	}
+	memset(mca_info, 0, sizeof(struct MCA_info));
+
+	save_flags(flags);
+	cli();
X 
X 	/* Make sure adapter setup is off */
X 
@@ -705,12 +713,15 @@
X 		mca_info->slot[i].dev = 0;
X 
X 		if(!mca_isadapter(i)) continue;
-		node = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+
+		node = (struct proc_dir_entry *)kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
X 
X 		if(node == NULL) {
X 			printk("Failed to allocate memory for MCA proc-entries!");
X 			return;
X 		}
+		memset(node, 0, sizeof(struct proc_dir_entry));
+
X 		if(i < MCA_MAX_SLOT_NR) {
X 			node->low_ino = PROC_MCA_SLOT + i;
X 			node->namelen = sprintf(mca_info->slot[i].procname,
@@ -854,7 +865,7 @@
X 	type = inode->i_ino;
X 	pid = type >> 16;
X 	type &= 0x0000ffff;
-	start = 0;
+	start = NULL;
X 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
X 	length = mca_fill((char *) page, pid, type,
X 			  &start, ppos, count);
@@ -862,7 +873,7 @@
X 		free_page(page);
X 		return length;
X 	}
-	if(start != 0) {
+	if(start != NULL) {
X 		/* We have had block-adjusting processing! */
X 
X 		copy_to_user(buf, start, length);
diff -u --recursive --new-file v2.3.5/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.3.5/linux/arch/i386/kernel/ptrace.c	Wed Mar 24 13:18:46 1999
+++ linux/arch/i386/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -172,25 +172,6 @@
X 	flush_tlb();
X }
X 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm,addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.5/linux/arch/i386/kernel/setup.c	Sat May 15 23:46:03 1999
+++ linux/arch/i386/kernel/setup.c	Tue Jun  8 10:42:46 1999
@@ -12,6 +12,8 @@
X  * 
X  *  Force Centaur C6 processors to report MTRR capability.
X  *      Bart Hartgers <ba...@etpmod.phys.tue.nl>, May 199.
+ *
+ *  Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
X  */
X 
X /*
@@ -688,7 +690,7 @@
X 	    NULL, NULL, NULL, NULL }},
X 	{ X86_VENDOR_INTEL,	6,
X 	  { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
-	    NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL,
+            NULL, "Pentium II (Deschutes)", "Mobile Pentium II", NULL,
X 	    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
X 	{ X86_VENDOR_AMD,	4,
X 	  { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
@@ -794,13 +796,19 @@
X 			if (c->x86_model <= 16)
X 				p = cpu_models[i].model_names[c->x86_model];
X 
-			/* Names for the Pentium II processors */
+			/* Names for the Pentium II Celeron processors 
+                           detectable only by also checking the cache size */
X 			if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
-			    && (cpu_models[i].x86 == 6) 
-			    && (c->x86_model == 5)
-			    && (c->x86_cache_size == 0)) {
-				p = "Celeron (Covington)";
-			}
+			    && (cpu_models[i].x86 == 6)){ 
+				if(c->x86_model == 6 && c->x86_cache_size == 128) {
+                            		p = "Celeron (Mendocino)"; 
+                          	}
+			  	else { 
+                            	if (c->x86_model == 5 && c->x86_cache_size == 0) {
+				  	p = "Celeron (Covington)";
+			    	}
+                        }
+                    }
X 		}
X 			
X 	}
diff -u --recursive --new-file v2.3.5/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.3.5/linux/arch/i386/kernel/signal.c	Tue Dec  1 11:28:24 1998
+++ linux/arch/i386/kernel/signal.c	Mon Jun  7 16:14:06 1999
@@ -698,6 +698,7 @@
X 			default:
X 				lock_kernel();
X 				sigaddset(¤t->signal, signr);
+				recalc_sigpending(current);
X 				current->flags |= PF_SIGNALED;
X 				do_exit(exit_code);
X 				/* NOTREACHED */
diff -u --recursive --new-file v2.3.5/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.3.5/linux/arch/i386/mm/init.c	Thu Jan 21 11:28:40 1999
+++ linux/arch/i386/mm/init.c	Tue Jun  8 10:49:48 1999
@@ -390,6 +390,7 @@
X 	int datapages = 0;
X 	int initpages = 0;
X 	unsigned long tmp;
+	unsigned long endbase;
X 
X 	end_mem &= PAGE_MASK;
X 	high_memory = (void *) end_mem;
@@ -417,8 +418,10 @@
X 	 * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000.
X 	 * They seem to have done something stupid with the floppy
X 	 * controller as well..
+	 * The amount of available base memory is in WORD 40:13.
X 	 */
-	while (start_low_mem < 0x9f000+PAGE_OFFSET) {
+	endbase = PAGE_OFFSET + ((*(unsigned short *)__va(0x413) * 1024) & PAGE_MASK);
+	while (start_low_mem < endbase) {
X 		clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
X 		start_low_mem += PAGE_SIZE;
X 	}
diff -u --recursive --new-file v2.3.5/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c
--- v2.3.5/linux/arch/i386/mm/ioremap.c	Fri Nov 27 15:03:14 1998
+++ linux/arch/i386/mm/ioremap.c	Thu Jun  3 14:17:51 1999
@@ -93,12 +93,17 @@
X {
X 	void * addr;
X 	struct vm_struct * area;
-	unsigned long offset;
+	unsigned long offset, last_addr;
+
+	/* Don't allow wraparound or zero size */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr)
+		return NULL;
X 
X 	/*
X 	 * Don't remap the low PCI/ISA area, it's always mapped..
X 	 */
-	if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000)
+	if (phys_addr >= 0xA0000 && last_addr < 0x100000)
X 		return phys_to_virt(phys_addr);
X 
X 	/*
@@ -112,13 +117,7 @@
X 	 */
X 	offset = phys_addr & ~PAGE_MASK;
X 	phys_addr &= PAGE_MASK;
-	size = PAGE_ALIGN(size + offset);
-
-	/*
-	 * Don't allow mappings that wrap..
-	 */
-	if (!size || size > phys_addr + size)
-		return NULL;
+	size = PAGE_ALIGN(last_addr) - phys_addr;
X 
X 	/*
X 	 * Ok, go for it..
diff -u --recursive --new-file v2.3.5/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.3.5/linux/arch/i386/vmlinux.lds	Sun Dec 27 22:45:13 1998
+++ linux/arch/i386/vmlinux.lds	Tue Jun  8 23:03:37 1999
@@ -1,12 +1,12 @@
X /* ld script to make i386 Linux kernel
- * Written by Martin Mares <m...@atrey.karlin.mff.cuni.cz>
+ * Written by Martin Mares <m...@atrey.karlin.mff.cuni.cz>;
X  */
X OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
X OUTPUT_ARCH(i386)
X ENTRY(_start)
X SECTIONS
X {
-  . = 0xC0000000 + 0x100000;
+  . = 0xC0000000  + 0x100000;
X   _text = .;			/* Text and read-only data */
X   .text : {
X 	*(.text)
diff -u --recursive --new-file v2.3.5/linux/arch/i386/vmlinux.lds.S linux/arch/i386/vmlinux.lds.S
--- v2.3.5/linux/arch/i386/vmlinux.lds.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/vmlinux.lds.S	Mon Jun  7 17:02:23 1999
@@ -0,0 +1,69 @@
+/* ld script to make i386 Linux kernel
+ * Written by Martin Mares <m...@atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+  . = PAGE_OFFSET_RAW + 0x100000;
+  _text = .;			/* Text and read-only data */
+  .text : {
+	*(.text)
+	*(.fixup)
+	*(.gnu.warning)
+	} = 0x9090
+  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  _etext = .;			/* End of text section */
+
+  .data : {			/* Data */
+	*(.data)
+	CONSTRUCTORS
+	}
+
+  _edata = .;			/* End of data section */
+
+  . = ALIGN(8192);		/* init_task */
+  .data.init_task : { *(.data.init_task) }
+
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.idt) }
+
+
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+	}
+  _end = . ;
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -u --recursive --new-file v2.3.5/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.3.5/linux/arch/m68k/kernel/ptrace.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -196,25 +196,6 @@
X 	flush_tlb_all();
X }
X 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm, addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.3.5/linux/arch/mips/kernel/irixelf.c	Wed Nov 11 11:49:59 1998
+++ linux/arch/mips/kernel/irixelf.c	Thu Jun  3 23:15:29 1999
@@ -132,9 +132,7 @@
X 	end = PAGE_ALIGN(end);
X 	if (end <= start) 
X 		return;
-	do_mmap(NULL, start, end - start,
-		PROT_READ | PROT_WRITE | PROT_EXEC,
-		MAP_FIXED | MAP_PRIVATE, 0);
+	do_brk(start, end - start);
X }
X 
X 
@@ -394,9 +392,7 @@
X 
X 	/* Map the last of the bss segment */
X 	if (last_bss > len) {
-		do_mmap(NULL, len, (last_bss - len),
-			PROT_READ|PROT_WRITE|PROT_EXEC,
-			MAP_FIXED|MAP_PRIVATE, 0);
+		do_brk(len, (last_bss - len));
X 	}
X 	kfree(elf_phdata);
X 
@@ -589,8 +585,7 @@
X 	unsigned long v;
X 	struct prda *pp;
X 
-	v =  do_mmap (NULL, PRDA_ADDRESS, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
-		      MAP_FIXED | MAP_PRIVATE, 0);
+	v =  do_brk (PRDA_ADDRESS, PAGE_SIZE);
X 	
X 	if (v < 0)
X 		return;
@@ -931,9 +926,7 @@
X 	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
X 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
X 	if (bss > len)
-	  do_mmap(NULL, len, bss-len,
-		  PROT_READ|PROT_WRITE|PROT_EXEC,
-		  MAP_FIXED|MAP_PRIVATE, 0);
+	  do_brk(len, bss-len);
X 	kfree(elf_phdata);
X 	return 0;
X }
diff -u --recursive --new-file v2.3.5/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.3.5/linux/arch/mips/kernel/ptrace.c	Mon May 31 22:28:04 1999
+++ linux/arch/mips/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -143,25 +143,6 @@
X 	flush_tlb_page(vma, addr);
X }
X 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm, addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.3.5/linux/arch/mips/kernel/sysirix.c	Sat May  8 11:14:01 1999
+++ linux/arch/mips/kernel/sysirix.c	Thu Jun  3 23:15:29 1999
@@ -571,7 +571,7 @@
X 	 * Check against existing mmap mappings.
X 	 */
X 	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) {
-		return -ENOMEM;
+		ret = -ENOMEM;
X 		goto out;
X 	}
X 
@@ -579,7 +579,7 @@
X 	 * Check if we have enough memory..
X 	 */
X 	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) {
-		return -ENOMEM;
+		ret = -ENOMEM;
X 		goto out;
X 	}
X 
@@ -587,10 +587,7 @@
X 	 * Ok, looks good - let it rip.
X 	 */
X 	mm->brk = brk;
-	do_mmap(NULL, oldbrk, newbrk-oldbrk,
-		PROT_READ|PROT_WRITE|PROT_EXEC,
-		MAP_FIXED|MAP_PRIVATE, 0);
-
+	do_brk(oldbrk, newbrk-oldbrk);
X 	ret = 0;
X 
X out:
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile
--- v2.3.5/linux/arch/ppc/chrpboot/Makefile	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/chrpboot/Makefile	Mon Jun  7 12:11:51 1999
@@ -17,7 +17,7 @@
X 	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
X 
X CFLAGS	= -O -fno-builtin -DSTDC_HEADERS -I$(TOPDIR)/include
-LD_ARGS = -T ../vmlinux.lds -Ttext 0x00800000
+LD_ARGS = -Ttext 0x00400000
X OBJCOPY = $(CROSS_COMPILE)objcopy
X 
X OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o # initrd.o
@@ -65,9 +65,10 @@
X initrd.o: ramdisk.image.gz piggyback
X 	./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o
X 
-zImage: $(OBJS) no_initrd.o
+zImage: $(OBJS) no_initrd.o mknote
X 	$(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS)
-	objcopy zImage zImage
+	./mknote > note
+	$(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
X 
X zImage.initrd: $(OBJS) initrd.o
X 	$(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS)
@@ -92,8 +93,7 @@
X 
X 
X clean:
-	rm -f piggyback
-	rm -f $(OBJS) zImage
+	rm -f piggyback note mknote $(OBJS) zImage
X 
X fastdep:
X 	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c
--- v2.3.5/linux/arch/ppc/chrpboot/main.c	Wed Sep 30 10:14:16 1998
+++ linux/arch/ppc/chrpboot/main.c	Mon Jun  7 12:11:51 1999
@@ -17,9 +17,9 @@
X #define get_32be(x)	(*(unsigned *)(x))
X 
X #define RAM_START	0x00000000
-#define RAM_END		0x00800000	/* only 8M mapped with BATs */
+#define RAM_END		(8<<20)
X 
-#define RAM_FREE	0x00540000	/* after image of chrpboot */
+#define RAM_FREE	(6<<20)		/* after image of chrpboot */
X #define PROG_START	0x00010000
X 
X char *avail_ram;
@@ -38,16 +38,16 @@
X     void *dst;
X     unsigned char *im;
X     unsigned initrd_start, initrd_size;
+    extern char _start;
X     
-    printf("chrpboot starting\n\r");
-    /* setup_bats(); */
+    printf("chrpboot starting: loaded at 0x%x\n\r", &_start);
X 
X     if (initrd_len) {
X 	initrd_size = initrd_len;
X 	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
X 	a1 = initrd_start;
X 	a2 = initrd_size;
-	printf("initial ramdisk at %x (%u bytes)\n\r", initrd_start,
+	printf("initial ramdisk at 0x%x (%u bytes)\n\r", initrd_start,
X 	       initrd_size);
X 	memcpy((char *)initrd_start, initrd_data, initrd_size);
X 	end_avail = (char *)initrd_start;
@@ -58,25 +58,19 @@
X     dst = (void *) PROG_START;
X 
X     if (im[0] == 0x1f && im[1] == 0x8b) {
-	void *cp = (void *) RAM_FREE;
-	avail_ram = (void *) (RAM_FREE + ((len + 7) & -8));
-	memcpy(cp, im, len);
-	printf("gunzipping... ");
-	gunzip(dst, 0x400000, cp, &len);
-	printf("done\n\r");
-
+	avail_ram = (char *)RAM_FREE;
+	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+	gunzip(dst, 0x400000, im, &len);
+	printf("done %u bytes\n\r", len);
X     } else {
X 	memmove(dst, im, len);
X     }
X 
X     flush_cache(dst, len);
-
-    sa = PROG_START+12;
+    
+    sa = *(unsigned long *)PROG_START+PROG_START;
X     printf("start address = 0x%x\n\r", sa);
X 
-#if 0
-    pause();
-#endif
X     (*(void (*)())sa)(a1, a2, prom, 0, 0);
X 
X     printf("returned?\n\r");
@@ -150,7 +144,7 @@
X     s.avail_out = dstlen;
X     r = inflate(&s, Z_FINISH);
X     if (r != Z_OK && r != Z_STREAM_END) {
-	printf("inflate returned %d\n\r", r);
+	printf("inflate returned %d msg: %s\n\r", r, s.msg);
X 	exit();
X     }
X     *lenp = s.next_out - (unsigned char *) dst;
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/chrpboot/mknote.c linux/arch/ppc/chrpboot/mknote.c
--- v2.3.5/linux/arch/ppc/chrpboot/mknote.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/chrpboot/mknote.c	Mon Jun  7 12:11:51 1999
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Cort Dougan 1999.
+ *
+ * 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.
+ *
+ * Generate a note section as per the CHRP specification.
+ *
+ */
+
+#include <stdio.h>
+
+#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
+
+int main(void)
+{
+/* header */
+	/* namesz */
+	PL(strlen("PowerPC")+1);
+	/* descrsz */
+	PL(6*4);
+	/* type */
+	PL(0x1275);
+	/* name */
+	printf("PowerPC"); printf("%c", 0);
+	
+/* descriptor */
+	/* real-mode */
+	PL(0xffffffff);
+	/* real-base */
+	PL(0x00c00000);
+	/* real-size */
+	PL(0xffffffff);
+	/* virt-base */
+	PL(0xffffffff);
+	/* virt-size */
+	PL(0xffffffff);
+	/* load-base */
+	PL(0x4000);
+	return 0;
+}
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/coffboot/zlib.c linux/arch/ppc/coffboot/zlib.c
--- v2.3.5/linux/arch/ppc/coffboot/zlib.c	Wed Sep 30 10:14:16 1998
+++ linux/arch/ppc/coffboot/zlib.c	Mon Jun  7 12:11:51 1999
@@ -11,7 +11,7 @@
X  * - added Z_PACKET_FLUSH (see zlib.h for details)
X  * - added inflateIncomp
X  *
- * $Id: zlib.c,v 1.2 1998/09/03 17:40:53 cort Exp $
+ * $Id: zlib.c,v 1.3 1999/05/27 22:22:54 cort Exp $
X  */
X 
X /*+++++*/
@@ -649,6 +649,11 @@
X /*   load local pointers */
X #define LOAD {LOADIN LOADOUT}
X 
+/*
+ * The IBM 150 firmware munges the data right after _etext[].  This
+ * protects it. -- Cort
+ */
+local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0};
X /* And'ing with mask[n] masks the lower n bits */
X local uInt inflate_mask[] = {
X     0x0000,
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.3.5/linux/arch/ppc/common_defconfig	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/common_defconfig	Mon Jun  7 12:11:51 1999
@@ -9,14 +9,13 @@
X CONFIG_6xx=y
X # CONFIG_PPC64 is not set
X # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
X # CONFIG_PREP is not set
X # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
X # CONFIG_APUS is not set
X # CONFIG_MBX is not set
X # CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
X CONFIG_6xx=y
X 
X #
@@ -51,6 +50,7 @@
X # CONFIG_TOTALMP is not set
X CONFIG_BOOTX_TEXT=y
X # CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
X 
X #
X # Plug and Play support
@@ -60,7 +60,7 @@
X #
X # Block devices
X #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
X CONFIG_BLK_DEV_IDE=y
X 
X #
@@ -77,7 +77,7 @@
X # CONFIG_BLK_DEV_CMD640 is not set
X # CONFIG_BLK_DEV_RZ1000 is not set
X # CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_SL82C105=y
X CONFIG_BLK_DEV_IDE_PMAC=y
X CONFIG_BLK_DEV_IDEDMA_PMAC=y
X CONFIG_BLK_DEV_IDEDMA=y
@@ -117,7 +117,7 @@
X # CONFIG_NET_IPGRE is not set
X # CONFIG_IP_MROUTE is not set
X CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
X 
X #
X # (it is safe to leave these untouched)
@@ -199,7 +199,14 @@
X # CONFIG_SCSI_SYM53C416 is not set
X # CONFIG_SCSI_NCR53C7xx is not set
X # CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
X # CONFIG_SCSI_PAS16 is not set
X # CONFIG_SCSI_PCI2000 is not set
X # CONFIG_SCSI_PCI2220I is not set
@@ -237,7 +244,7 @@
X # CONFIG_ACENIC is not set
X # CONFIG_NET_ISA is not set
X CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
X # CONFIG_AC3200 is not set
X # CONFIG_APRICOT is not set
X # CONFIG_CS89x0 is not set
@@ -297,12 +304,16 @@
X CONFIG_FB_CONTROL=y
X CONFIG_FB_PLATINUM=y
X CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
X CONFIG_FB_IMSTT=y
X CONFIG_FB_CT65550=y
X # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+# CONFIG_FB_MATROX_MILLENIUM is not set
+CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G100 is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
X # CONFIG_FB_VIRTUAL is not set
X # CONFIG_FBCON_ADVANCED is not set
X CONFIG_FBCON_CFB8=y
@@ -324,12 +335,22 @@
X #
X CONFIG_VT=y
X CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
X # CONFIG_SERIAL_EXTENDED is not set
X # CONFIG_SERIAL_NONSTANDARD is not set
X CONFIG_UNIX98_PTYS=y
X CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
X # CONFIG_QIC02_TAPE is not set
X # CONFIG_WATCHDOG is not set
X CONFIG_NVRAM=y
@@ -448,7 +469,34 @@
X # CONFIG_SOUND_SONICVIBES is not set
X # CONFIG_SOUND_MSNDCLAS is not set
X # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+CONFIG_SOUND_CS4232=m
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
X 
X #
X # Kernel hacking
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.5/linux/arch/ppc/config.in	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/config.in	Tue Jun  8 10:52:26 1999
@@ -176,6 +176,7 @@
X endmenu
X 
X source drivers/char/Config.in
+source drivers/usb/Config.in
X source fs/Config.in
X 
X mainmenu_option next_comment
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.5/linux/arch/ppc/defconfig	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/defconfig	Mon Jun  7 12:11:51 1999
@@ -9,14 +9,13 @@
X CONFIG_6xx=y
X # CONFIG_PPC64 is not set
X # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
X # CONFIG_PREP is not set
X # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
X # CONFIG_APUS is not set
X # CONFIG_MBX is not set
X # CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
X CONFIG_6xx=y
X 
X #
@@ -51,6 +50,7 @@
X # CONFIG_TOTALMP is not set
X CONFIG_BOOTX_TEXT=y
X # CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
X 
X #
X # Plug and Play support
@@ -60,7 +60,7 @@
X #
X # Block devices
X #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
X CONFIG_BLK_DEV_IDE=y
X 
X #
@@ -77,7 +77,7 @@
X # CONFIG_BLK_DEV_CMD640 is not set
X # CONFIG_BLK_DEV_RZ1000 is not set
X # CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_SL82C105=y
X CONFIG_BLK_DEV_IDE_PMAC=y
X CONFIG_BLK_DEV_IDEDMA_PMAC=y
X CONFIG_BLK_DEV_IDEDMA=y
@@ -117,7 +117,7 @@
X # CONFIG_NET_IPGRE is not set
X # CONFIG_IP_MROUTE is not set
X CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
X 
X #
X # (it is safe to leave these untouched)
@@ -199,7 +199,14 @@
X # CONFIG_SCSI_SYM53C416 is not set
X # CONFIG_SCSI_NCR53C7xx is not set
X # CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
X # CONFIG_SCSI_PAS16 is not set
X # CONFIG_SCSI_PCI2000 is not set
X # CONFIG_SCSI_PCI2220I is not set
@@ -237,7 +244,7 @@
X # CONFIG_ACENIC is not set
X # CONFIG_NET_ISA is not set
X CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
X # CONFIG_AC3200 is not set
X # CONFIG_APRICOT is not set
X # CONFIG_CS89x0 is not set
@@ -297,12 +304,16 @@
X CONFIG_FB_CONTROL=y
X CONFIG_FB_PLATINUM=y
X CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
X CONFIG_FB_IMSTT=y
X CONFIG_FB_CT65550=y
X # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+# CONFIG_FB_MATROX_MILLENIUM is not set
+CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G100 is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
X # CONFIG_FB_VIRTUAL is not set
X # CONFIG_FBCON_ADVANCED is not set
X CONFIG_FBCON_CFB8=y
@@ -324,12 +335,22 @@
X #
X CONFIG_VT=y
X CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
X # CONFIG_SERIAL_EXTENDED is not set
X # CONFIG_SERIAL_NONSTANDARD is not set
X CONFIG_UNIX98_PTYS=y
X CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
X # CONFIG_QIC02_TAPE is not set
X # CONFIG_WATCHDOG is not set
X CONFIG_NVRAM=y
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.3.5/linux/arch/ppc/kernel/chrp_pci.c	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Mon Jun  7 12:11:51 1999
@@ -167,6 +167,62 @@
X 	return PCIBIOS_SUCCESSFUL;
X }
X 
+
+int rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned char *val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 1 ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned short *val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 2 ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+				     unsigned char offset, unsigned int *val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "read-pci-config", 2, 2, (ulong *)&val, addr, 4 ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+				     unsigned char offset, unsigned char val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "write-pci-config", 3, 1, NULL, addr, 1, (ulong)val ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+				     unsigned char offset, unsigned short val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "write-pci-config", 3, 1, NULL, addr, 2, (ulong)val ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int rtas_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+				      unsigned char offset, unsigned int val)
+{
+	unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
+	if ( call_rtas( "write-pci-config", 3, 1, NULL, addr, 4, (ulong)val ) != 0 )
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
X     /*
X      *  Temporary fixes for PCI devices. These should be replaced by OF query
X      *  code -- Geert
@@ -256,6 +312,7 @@
X 
X decl_config_access_method(grackle);
X decl_config_access_method(indirect);
+decl_config_access_method(rtas);
X 
X void __init
X chrp_setup_pci_ptrs(void)
@@ -276,7 +333,7 @@
X 		{
X 			/* find out how many pythons */
X 			while ( (py = py->next) ) python_busnr++;
-                        set_config_access_method(python);
+			set_config_access_method(python);
X 			/*
X 			 * We base these values on the machine type but should
X 			 * try to read them from the python controller itself.
@@ -297,10 +354,22 @@
X                 }
X                 else
X                 {
-			pci_dram_offset = 0;
-			isa_mem_base = 0xf7000000;
-			isa_io_base = 0xf8000000;
-			set_config_access_method(gg2);
+			if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) )
+			{
+				pci_dram_offset = 0;
+				isa_mem_base = 0x80000000;
+				isa_io_base = 0xfe000000;
+				pci_config_address = (unsigned int *)0xfec00000;
+				pci_config_data = (unsigned char *)0xfee00000;
+				set_config_access_method(indirect);
+			}
+			else
+			{
+				pci_dram_offset = 0;
+				isa_mem_base = 0xf7000000;
+				isa_io_base = 0xf8000000;
+				set_config_access_method(gg2);
+			}
X                 }
X         }
X 	
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.3.5/linux/arch/ppc/kernel/chrp_setup.c	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Jun  7 12:11:51 1999
@@ -32,6 +32,7 @@
X #include <linux/console.h>
X #include <linux/pci.h>
X #include <linux/openpic.h>
+#include <linux/version.h>
X 
X #include <asm/mmu.h>
X #include <asm/processor.h>
@@ -65,6 +66,7 @@
X 
X unsigned long chrp_get_rtc_time(void);
X int chrp_set_rtc_time(unsigned long nowtime);
+unsigned long rtas_event_scan_rate = 0, rtas_event_scan_ct = 0;
X void chrp_calibrate_decr(void);
X void chrp_time_init(void);
X 
@@ -235,6 +237,7 @@
X 	   chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
X {
X 	extern char cmd_line[];
+	struct device_node *device;
X 
X 	/* init to some ~sane value until calibrate_delay() runs */
X 	loops_per_sec = 50000000;
@@ -274,57 +277,73 @@
X 			find_path_device("/"), "platform-open-pic", NULL);
X 		OpenPIC = ioremap((unsigned long)OpenPIC, sizeof(struct OpenPIC));
X 	}
-	
+
X 	/*
X 	 *  Fix the Super I/O configuration
X 	 */
-	sio_init();
+	/*sio_init();*/
X #ifdef CONFIG_DUMMY_CONSOLE
X 	conswitchp = &dummy_con;
X #endif
-	/* my starmax 6000 needs this but the longtrail shouldn't do it -- Cort */
-	if ( !strncmp("MOT", get_property(find_path_device("/"),
-					  "model", NULL),3) )
-		*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+
+	/* Get the event scan rate for the rtas so we know how
+	 * often it expects a heartbeat. -- Cort
+	 */
+	if ( rtas_data )
+	{
+		struct property *p;
+		device = find_devices("rtas");
+		for ( p = device->properties;
+		      strncmp(p->name, "rtas-event-scan-rate", 20) && p ;
+		      p = p->next )
+			/* nothing */ ;
+		if ( p && *(unsigned long *)p->value )
+		{
+			rtas_event_scan_rate = (HZ/(*(unsigned long *)p->value)*30)-1;
+			rtas_event_scan_ct = 1;
+			printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
+			       *(unsigned long *)p->value, rtas_event_scan_rate );
+		}
+	}
X }
X 
X void
+chrp_event_scan(void)
+{
+	unsigned char log[1024];
+	if ( rtas_event_scan_rate && (rtas_event_scan_ct-- <= 0) )
+	{
+		call_rtas( "event-scan", 4, 1, NULL, 0x0, 1, __pa(log), 1024 );
+		rtas_event_scan_ct = rtas_event_scan_rate;
+	}
+}
+	
+void
X chrp_restart(char *cmd)
X {
-#if 0
-	extern unsigned int rtas_entry, rtas_data, rtas_size;
X 	printk("RTAS system-reboot returned %d\n",
X 	       call_rtas("system-reboot", 0, 1, NULL));
-	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
-	       rtas_entry,rtas_data,rtas_size);
X 	for (;;);
-#else
-	printk("System Halted\n");
-	while(1);
-#endif
X }
X 
X void
X chrp_power_off(void)
X {
-	/* RTAS doesn't seem to work on Longtrail.
-	   For now, do it the same way as the PReP. */
-#if 0
-	extern unsigned int rtas_entry, rtas_data, rtas_size;
+	/* allow power on only with power button press */
+#define	PWR_FIELD(x) (0x8000000000000000 >> ((x)-96))
X 	printk("RTAS power-off returned %d\n",
-	       call_rtas("power-off", 2, 1, NULL, 0, 0));
-	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
-	       rtas_entry,rtas_data,rtas_size);
+	       call_rtas("power-off", 2, 1, NULL,
+			 ((PWR_FIELD(96)|PWR_FIELD(97))>>32)&0xffffffff,
+			 (PWR_FIELD(96)|PWR_FIELD(97))&0xffffffff));
+#undef PWR_FIELD	
X 	for (;;);
-#else
-	chrp_restart(NULL);
-#endif
X }
X 
X void
X chrp_halt(void)
X {
-	chrp_restart(NULL);
+	chrp_power_off();
X }
X 
X u_int
@@ -653,5 +672,21 @@
X         ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
X 
X         ppc_ide_md.io_base = _IO_BASE;
-#endif		
+#endif
+	/*
+	 * Print the banner, then scroll down so boot progress
+	 * can be printed.  -- Cort 
+	 */
+	chrp_progress("Linux/PPC "UTS_RELEASE"\n");
+}
+
+void chrp_progress(char *s)
+{
+	extern unsigned int rtas_data;
+	
+	if ( (_machine != _MACH_chrp) || !rtas_data )
+		return;
+	call_rtas( "display-character", 1, 1, NULL, '\r' );
+	while ( *s )
+		call_rtas( "display-character", 1, 1, NULL, *s++ );
X }
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.5/linux/arch/ppc/kernel/head.S	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/kernel/head.S	Mon Jun  7 12:11:51 1999
@@ -1,7 +1,7 @@
X /*
X  *  arch/ppc/kernel/head.S
X  *
- *  $Id: head.S,v 1.131 1999/05/14 22:37:21 cort Exp $
+ *  $Id: head.S,v 1.133 1999/05/20 05:13:08 cort Exp $
X  *
X  *  PowerPC version 
X  *    Copyright (C) 1995-1996 Gary Thomas (g...@linuxppc.org)
@@ -2615,7 +2615,6 @@
X  */
X 	.globl	enter_rtas
X enter_rtas:
-	stwu	r1,-16(r1)
X 	mflr	r0
X 	stw	r0,20(r1)
X 	lis	r4,rtas_data@ha
@@ -2636,7 +2635,6 @@
X 	andi.	r9,r9,MSR_ME|MSR_RI
X 	sync			/* disable interrupts so SRR0/1 */
X 	mtmsr	r0		/* don't get trashed */
-	li	r6,0	
X 	mtlr	r6
X 	mtspr	SPRG2,r7
X 	mtspr	SRR0,r8
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.3.5/linux/arch/ppc/kernel/idle.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/idle.c	Mon Jun  7 12:11:51 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: idle.c,v 1.61 1999/03/18 04:15:45 cort Exp $
+ * $Id: idle.c,v 1.62 1999/05/24 05:43:18 cort Exp $
X  *
X  * Idle daemon for PowerPC.  Idle daemon will handle any action
X  * that needs to be taken when the system becomes idle.
@@ -50,6 +50,7 @@
X 	/* endless loop with no priority at all */
X 	current->priority = 0;
X 	current->counter = -100;
+	init_idle();	
X 	for (;;)
X 	{
X 		__sti();
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.5/linux/arch/ppc/kernel/irq.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/irq.c	Mon Jun  7 12:11:51 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
+ * $Id: irq.c,v 1.106 1999/05/25 21:16:04 cort Exp $
X  *
X  *  arch/ppc/kernel/irq.c
X  *
@@ -65,7 +65,6 @@
X void enable_irq(unsigned int irq_nr);
X void disable_irq(unsigned int irq_nr);
X 
-/* Fixme - Need to figure out a way to get rid of this - Corey */
X volatile unsigned char *chrp_int_ack_special;
X 
X #ifdef CONFIG_APUS
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.5/linux/arch/ppc/kernel/misc.S	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/kernel/misc.S	Mon Jun  7 12:11:51 1999
@@ -866,7 +866,11 @@
X 	.long sys_getresuid	/* 165 */
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 01'
echo 'File patch-2.3.6 is continued in part 02'
echo 02 > _shar_seq_.tmp
exit 0
#!/bin/sh
# this is part 02 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 02; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
X 	.long sys_query_module
X 	.long sys_poll
+#ifdef CONFIG_NFS	
X 	.long sys_nfsservctl
+#else
+	.long sys_ni_syscall
+#endif		
X 	.long sys_setresgid
X 	.long sys_getresgid	/* 170 */
X 	.long sys_prctl
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.5/linux/arch/ppc/kernel/prom.c	Tue May 11 08:24:32 1999
+++ linux/arch/ppc/kernel/prom.c	Mon Jun  7 12:11:51 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $
+ * $Id: prom.c,v 1.60 1999/05/25 01:42:41 cort Exp $
X  *
X  * Procedures for interfacing to the Open Firmware PROM on
X  * Power Macintosh computers.
@@ -24,6 +24,7 @@
X #include <asm/io.h>
X #include <asm/smp.h>
X #include <asm/bootx.h>
+#include <asm/system.h>
X 
X /*
X  * Properties whose value is longer than this get excluded from our
@@ -412,6 +413,9 @@
X 	mem = copy_device_tree(mem, mem + (1<<20));
X 	prom_print(RELOC("done\n"));
X 
+
+	RELOC(klimit) = (char *) (mem - offset);
+	
X 	prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
X 	if (prom_rtas != (void *) -1) {
X 		RELOC(rtas_size) = 0;
@@ -421,9 +425,19 @@
X 		if (RELOC(rtas_size) == 0) {
X 			RELOC(rtas_data) = 0;
X 		} else {
-			mem = (mem + 4095) & -4096; /* round to page bdry */
+			/*
+			 * We do _not_ want the rtas_data inside the klimit
+			 * boundry since it'll be squashed when we do the
+			 * relocate of the kernel on chrp right after prom_init()
+			 * in head.S.  So, we just pick a spot in memory.
+			 * -- Cort
+			 */
+#if 0
+			mem = (mem + 4095) & -4096;
X 			RELOC(rtas_data) = mem + KERNELBASE;
X 			mem += RELOC(rtas_size);
+#endif
+			RELOC(rtas_data) = (6<<20) + KERNELBASE;
X 		}
X 		prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
X 		{
@@ -448,7 +462,7 @@
X 		else
X 			prom_print(RELOC(" done\n"));
X 	}
-	RELOC(klimit) = (char *) (mem - offset);
+
X #ifdef CONFIG_SMP
X 	/*
X 	 * With CHRP SMP we need to use the OF to start the other
@@ -1289,7 +1303,7 @@
X 	  unsigned long *outputs, ...)
X {
X 	va_list list;
-	int i;
+	int i, s;
X 	struct device_node *rtas;
X 	int *tokp;
X 	union {
@@ -1305,16 +1319,19 @@
X 		printk(KERN_ERR "No RTAS service called %s\n", service);
X 		return -1;
X 	}
-	u.words[0] = __pa(*tokp);
+	u.words[0] = *tokp;
X 	u.words[1] = nargs;
X 	u.words[2] = nret;
X 	va_start(list, outputs);
X 	for (i = 0; i < nargs; ++i)
X 		u.words[i+3] = va_arg(list, unsigned long);
X 	va_end(list);
+	
+	s = _disable_interrupts();
X 	spin_lock(&rtas_lock);
X 	enter_rtas((void *)__pa(&u));
X 	spin_unlock(&rtas_lock);
+	_enable_interrupts(s);
X 	if (nret > 1 && outputs != NULL)
X 		for (i = 0; i < nret-1; ++i)
X 			outputs[i] = u.words[i+nargs+4];
@@ -1326,8 +1343,7 @@
X abort()
X {
X #ifdef CONFIG_XMON
-	extern void xmon(void *);
-	xmon(0);
+	xmon(NULL);
X #endif
X 	prom_exit();
X }
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.3.5/linux/arch/ppc/kernel/ptrace.c	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -190,25 +190,6 @@
X 	flush_tlb_all();
X }
X 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm,addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.5/linux/arch/ppc/kernel/smp.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/smp.c	Mon Jun  7 12:11:51 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $
+ * $Id: smp.c,v 1.52 1999/05/23 22:43:51 cort Exp $
X  *
X  * Smp support for ppc.
X  *
@@ -388,9 +388,12 @@
X 
X void __init smp_callin(void)
X {
+	int i;
+	
X 	printk("SMP %d: smp_callin()\n",current->processor);
X         smp_store_cpu_info(current->processor);
X 	set_dec(decrementer_count);
+	
X #if 0
X 	current->mm->mmap->vm_page_prot = PAGE_SHARED;
X 	current->mm->mmap->vm_start = PAGE_OFFSET;
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.3.5/linux/arch/ppc/kernel/syscalls.c	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/kernel/syscalls.c	Mon Jun  7 12:11:51 1999
@@ -182,18 +182,14 @@
X 	int fd[2];
X 	int error;
X 
-	error = verify_area(VERIFY_WRITE, fildes, 8);
-	if (error)
-		return error;
X 	lock_kernel();
X 	error = do_pipe(fd);
X 	unlock_kernel();
-	if (error)
-		return error;
-	if (__put_user(fd[0],0+fildes)
-	    || __put_user(fd[1],1+fildes))
-		return -EFAULT;	/* should we close the fds? */
-	return 0;
+	if (!error) {
+		if (copy_to_user(fildes, fd, 2*sizeof(int)))
+			error = -EFAULT;
+	}
+	return error;
X }
X 
X asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.3.5/linux/arch/ppc/kernel/time.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/time.c	Mon Jun  7 12:11:51 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: time.c,v 1.47 1999/03/18 05:11:11 cort Exp $
+ * $Id: time.c,v 1.48 1999/05/22 19:35:57 cort Exp $
X  * Common time routines among all ppc machines.
X  *
X  * Written by Cort Dougan (co...@cs.nmt.edu) to merge
@@ -126,13 +126,17 @@
X 	smp_local_timer_interrupt(regs);
X #endif		
X 
-	/* Fixme - make this more generic - Corey */
X #ifdef CONFIG_APUS
X 	{
X 		extern void apus_heartbeat (void);
X 		apus_heartbeat ();
X 	}
X #endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
+	if ( _machine == _MACH_chrp )
+		chrp_event_scan();
+#endif	
+
X 	hardirq_exit(cpu);
X }
X 
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.5/linux/arch/ppc/mm/init.c	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/mm/init.c	Mon Jun  7 12:11:51 1999
@@ -1,5 +1,5 @@
X /*
- *  $Id: init.c,v 1.165 1999/05/14 22:37:29 cort Exp $
+ *  $Id: init.c,v 1.166 1999/05/22 18:18:30 cort Exp $
X  *
X  *  PowerPC version 
X  *    Copyright (C) 1995-1996 Gary Thomas (g...@linuxppc.org)
@@ -402,7 +402,7 @@
X 	for (i = 0; i < size; i += PAGE_SIZE)
X 		map_page(&init_task, v+i, p+i, flags);
X out:	
-	return (void *) (v + (p & ~PAGE_MASK));
+	return (void *) (v + (addr & ~PAGE_MASK));
X }
X 
X void iounmap(void *addr)
diff -u --recursive --new-file v2.3.5/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c
--- v2.3.5/linux/arch/ppc/xmon/xmon.c	Mon May 31 22:28:04 1999
+++ linux/arch/ppc/xmon/xmon.c	Mon Jun  7 12:11:51 1999
@@ -999,7 +999,7 @@
X 	int c;
X 
X 	c = inchar();
-	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
+	if ((isxdigit(c) && (c != 'f') && (c != 'd')) || (c == '\n'))
X 		termch = c;
X 	scanhex(&adrs);
X 	if( termch != '\n')
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.3.5/linux/arch/sparc/Makefile	Sun Oct  4 10:22:42 1998
+++ linux/arch/sparc/Makefile	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.39 1998/09/16 12:31:31 jj Exp $
+# $Id: Makefile,v 1.41 1999/06/04 13:29:05 jj Exp $
X # sparc/Makefile
X #
X # Makefile for the architecture dependent flags and dependencies on the
@@ -15,7 +15,7 @@
X # Uncomment the first CFLAGS if you are doing kgdb source level
X # debugging of the kernel to get the proper debugging information.
X 
-IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
+IS_EGCS := $(shell if $(CC) -c -m32 -o _tmp.o arch/sparc/math-emu/fnegs.c >/dev/null 2>&1; then echo y; else echo n; fi; rm -f _tmp.o)
X NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
X 
X ifeq ($(NEW_GAS),y)
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/kernel/ebus.c linux/arch/sparc/kernel/ebus.c
--- v2.3.5/linux/arch/sparc/kernel/ebus.c	Tue Oct 27 09:52:20 1998
+++ linux/arch/sparc/kernel/ebus.c	Wed Jun  9 14:44:25 1999
@@ -1,9 +1,10 @@
-/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $
+/* $Id: ebus.c,v 1.3 1999/06/03 15:02:09 davem Exp $
X  * ebus.c: PCI to EBus bridge device.
X  *
X  * Copyright (C) 1997  Eddie C. Dost  (e...@skynet.be)
X  *
X  * Adopted for sparc by V. Roganov and G. Raiko.
+ * Fixes for different platforms by Pete Zaitcev.
X  */
X 
X #include <linux/config.h>
@@ -25,9 +26,9 @@
X #undef DEBUG_FILL_EBUS_DEV
X 
X #ifdef PROM_DEBUG
-#define dprintf prom_printf
+#define dprintk prom_printf
X #else
-#define dprintf printk
+#define dprintk printk
X #endif
X 
X struct linux_ebus *ebus_chain = 0;
@@ -48,6 +49,9 @@
X extern int envctrl_init(void);
X #endif
X 
+/* We are together with pcic.c under CONFIG_PCI. */
+extern unsigned int pcic_pin_to_irq(unsigned int, char *name);
+
X static inline unsigned long ebus_alloc(size_t size)
X {
X 	return (unsigned long)kmalloc(size, GFP_ATOMIC);
@@ -66,6 +70,7 @@
X 	strcpy(dev->prom_name, lbuf);
X 
X 	len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+	if (len == -1) len = 0;
X 	dev->num_addrs = len / sizeof(regs[0]);
X 
X 	for (i = 0; i < dev->num_addrs; i++) {
@@ -77,22 +82,36 @@
X 		dev->base_address[i] = dev->parent->base_address[regs[i]];
X 	}
X 
+	/*
+	 * Houston, we have a problem...
+	 * Sometimes PROM supplies absolutely meaningless properties.
+	 * Still, we take what it gives since we have nothing better.
+	 * Children of ebus may be wired on any input pin of PCIC.
+	 */
X 	len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
X 	if ((len == -1) || (len == 0)) {
X 		dev->num_irqs = 0;
-		/*
-		 * Oh, well, some PROMs don't export interrupts
-		 * property to children of EBus devices...
-		 *
-		 * Be smart about PS/2 keyboard and mouse.
-		 */
-		if (!strcmp(dev->parent->prom_name, "8042")) {
+		dev->irqs[0] = 0;
+		if (dev->parent->num_irqs != 0) {
X 			dev->num_irqs = 1;
X 			dev->irqs[0] = dev->parent->irqs[0];
+/* P3 remove */ printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]);
X 		}
X 	} else {
X 		dev->num_irqs = len / sizeof(irqs[0]);
-		printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]);
+		if (irqs[0] == 0 || irqs[0] >= 8) {
+			/*
+			 * XXX Zero is a valid pin number...
+			 * This works as long as Ebus is not wired to INTA#.
+			 */
+			printk("EBUS: %s got bad irq %d from PROM\n",
+			    dev->prom_name, irqs[0]);
+			dev->num_irqs = 0;
+			dev->irqs[0] = 0;
+		} else {
+			dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
+/* P3 remove */ printk("EBUS: dev %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]);
+		}
X 	}
X 
X #ifdef DEBUG_FILL_EBUS_DEV
@@ -131,7 +150,30 @@
X 	dev->num_addrs = len / sizeof(struct linux_prom_registers);
X 
X 	for (i = 0; i < dev->num_addrs; i++) {
-		n = (regs[i].which_io - 0x10) >> 2;
+		/*
+		 * XXX Collect JE-1 PROM
+		 * 
+		 * Example - JS-E with 3.11:
+		 *  /ebus
+		 *      regs 
+		 *        0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,
+		 *        0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,
+		 *        0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,
+		 *      ranges
+		 *        0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,
+		 *        0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,
+		 *  /ebus/8042
+		 *      regs
+		 *        0x00000001, 0x00300060, 0x00000008,
+		 *        0x00000001, 0x00300060, 0x00000008,
+		 */
+		n = regs[i].which_io;
+		if (n >= 4) {
+			/* XXX This is copied from old JE-1 by Gleb. */
+			n = (regs[i].which_io - 0x10) >> 2;
+		} else {
+			;
+		}
X 
X 		dev->base_address[i] = dev->bus->self->base_address[n];
X 		dev->base_address[i] += regs[i].phys_addr;
@@ -141,8 +183,14 @@
X 		       (unsigned long)sparc_alloc_io (dev->base_address[i], 0,
X 						      regs[i].reg_size,
X 						      dev->prom_name, 0, 0);
+#if 0
+/*
+ * This release_region() screwes those who do sparc_alloc_io().
+ * Change drivers which do check_region(). See drivers/block/floppy.c.
+ */
X 		    /* Some drivers call 'check_region', so we release it */
X                     release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE);
+#endif
X 
X 		    if (dev->base_address[i] == 0 ) {
X 			panic("ebus: unable sparc_alloc_io for dev %s",
@@ -154,12 +202,22 @@
X 	len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
X 	if ((len == -1) || (len == 0)) {
X 		dev->num_irqs = 0;
+		if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
+			 dev->num_irqs = 1;
+/* P3 remove */ printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]);
+		}
X 	} else {
-		dev->num_irqs = len / sizeof(irqs[0]);
-
-#define IRQ_8042 7
-		if (irqs[0] == 4) dev->irqs[0] = IRQ_8042;
-		printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]);
+		dev->num_irqs = 1;  /* dev->num_irqs = len / sizeof(irqs[0]); */
+		if (irqs[0] == 0 || irqs[0] >= 8) {
+			/* See above for the parent. XXX */
+			printk("EBUS: %s got bad irq %d from PROM\n",
+			    dev->prom_name, irqs[0]);
+			dev->num_irqs = 0;
+			dev->irqs[0] = 0;
+		} else {
+			dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
+/* P3 remove */ printk("EBUS: child %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]);
+		}
X 	}
X 
X #ifdef DEBUG_FILL_EBUS_DEV
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v2.3.5/linux/arch/sparc/kernel/entry.S	Tue May 11 08:24:31 1999
+++ linux/arch/sparc/kernel/entry.S	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $
+/* $Id: entry.S,v 1.160 1999/06/03 15:02:11 davem Exp $
X  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
X  *
X  * Copyright (C) 1995 David S. Miller (da...@caip.rutgers.edu)
@@ -1888,5 +1888,53 @@
X 	LOAD_CURRENT(g6, o0)
X 	retl
X 	 nop
+
+#ifdef CONFIG_PCI
+#include <asm/pcic.h>
+
+	.align	4
+	.globl	linux_trap_ipi15_pcic
+linux_trap_ipi15_pcic:
+	rd	%wim, %l3
+	SAVE_ALL
+
+	/*
+	 * First deactivate NMI
+	 * or we cannot drop ET, cannot get window spill traps.
+	 * The busy loop is necessary because the PIO error
+	 * sometimes does not go away quickly and we trap again.
+	 */
+	sethi	%hi(C_LABEL(pcic_regs)), %o1
+	ld	[%o1 + %lo(C_LABEL(pcic_regs))], %o2
+
+	! Get pending status for printouts later.
+	ld	[%o2 + PCI_SYS_INT_PENDING], %o0
+
+	mov	PCI_SYS_INT_PENDING_CLEAR_ALL, %o1
+	stb	%o1, [%o2 + PCI_SYS_INT_PENDING_CLEAR]
+1:
+	ld	[%o2 + PCI_SYS_INT_PENDING], %o1
+	andcc	%o1, ((PCI_SYS_INT_PENDING_PIO|PCI_SYS_INT_PENDING_PCI)>>24), %g0
+	bne	1b
+	 nop
+
+	or	%l0, PSR_PIL, %l4
+	wr	%l4, 0x0, %psr
+	WRITE_PAUSE
+	wr	%l4, PSR_ET, %psr
+	WRITE_PAUSE
+
+	call	C_LABEL(pcic_nmi)
+	 add	%sp, REGWIN_SZ, %o1	! struct pt_regs *regs
+	RESTORE_ALL
+
+	.globl	C_LABEL(pcic_nmi_trap_patch)
+C_LABEL(pcic_nmi_trap_patch):
+	sethi	%hi(linux_trap_ipi15_pcic), %l3
+	jmpl	%l3 + %lo(linux_trap_ipi15_pcic), %g0
+	 rd	%psr, %l0
+	.word	0
+
+#endif /* CONFIG_PCI */
X 
X /* End of entry.S */
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v2.3.5/linux/arch/sparc/kernel/head.S	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/kernel/head.S	Wed Jun  9 14:44:25 1999
@@ -1,11 +1,13 @@
-/* $Id: head.S,v 1.95 1999/04/13 07:40:34 anton Exp $
+/* $Id: head.S,v 1.96 1999/06/03 15:02:15 davem Exp $
X  * head.S: The initial boot code for the Sparc port of Linux.
X  *
X  * Copyright (C) 1995 David S. Miller (da...@caip.rutgers.edu)
- * Copyright (C) 1995 Peter Zaitcev   (Zai...@ipmce.su)
+ * Copyright (C) 1995,1999 Pete Zaitcev   (zai...@metabyte.com)
X  * Copyright (C) 1996 Miguel de Icaza (mig...@nuclecu.unam.mx)
X  * Copyright (C) 1997 Jakub Jelinek   (j...@sunsite.mff.cuni.cz)
X  * Copyright (C) 1997 Michael A. Griffith (gr...@acm.org)
+ *
+ * CompactPCI platform by Eric Brower, 1999.
X  */
X 
X #include <linux/version.h>
@@ -116,10 +118,10 @@
X t_irq12:TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip         */
X t_irq13:TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */
X t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
+	.globl	t_nmi
X #ifndef __SMP__
X t_nmi:	NMI_TRAP                            /* Level 15 (NMI)                */
X #else
-	.globl	t_nmi
X t_nmi:	TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
X #endif
X t_racc:	TRAP_ENTRY(0x20, do_reg_access)     /* General Register Access Error */
@@ -842,6 +844,8 @@
X 		be	1f
X 		 cmp	%l1, 'm'
X 		be	1f
+		 cmp	%l1, 's'
+		be	1f
X 		 cmp	%l1, 'd'
X 		be	1f
X 		 cmp	%l1, 'e'
@@ -853,6 +857,8 @@
X 1:		set	C_LABEL(cputypval), %l1
X 		ldub	[%l1 + 0x4], %l1
X 		cmp	%l1, 'm'		! Test for sun4d, sun4e ?
+		be	sun4m_init
+		 cmp	%l1, 's'		! Treat sun4s as sun4m
X 		be	sun4m_init
X 		 cmp	%l1, 'd'		! Let us see how the beast will die
X 		be	sun4d_init
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- v2.3.5/linux/arch/sparc/kernel/pcic.c	Tue Mar 16 21:52:05 1999
+++ linux/arch/sparc/kernel/pcic.c	Wed Jun  9 14:44:25 1999
@@ -1,10 +1,13 @@
-/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $
+/* $Id: pcic.c,v 1.6 1999/06/03 15:02:18 davem Exp $
X  * pcic.c: Sparc/PCI controller support
X  *
X  * Copyright (C) 1998 V. Roganov and G. Raiko
X  *
X  * Code is derived from Ultra/PCI PSYCHO controller support, see that
X  * for author info.
+ *
+ * Support for diverse IIep based platforms by Pete Zaitcev.
+ * CP-1200 by Eric Brower.
X  */
X 
X #include <linux/config.h>
@@ -16,6 +19,7 @@
X 
X #include <asm/ebus.h>
X #include <asm/sbus.h> /* for sanity check... */
+#include <asm/swift.h> /* for cache flushing. */
X 
X #include <asm/io.h>
X 
@@ -69,9 +73,99 @@
X 
X #else
X 
+unsigned int pcic_pin_to_irq(unsigned int pin, char *name);
+
+/*
+ * I studied different documents and many live PROMs both from 2.30
+ * family and 3.xx versions. I came to the amazing conclusion: there is
+ * absolutely no way to route interrupts in IIep systems relying on
+ * information which PROM presents. We must hardcode interrupt routing
+ * schematics. And this actually sucks.   -- zaitcev 1999/05/12
+ *
+ * To find irq for a device we determine which routing map
+ * is in effect or, in other words, on which machine we are running.
+ * We use PROM name for this although other techniques may be used
+ * in special cases (Gleb reports a PROMless IIep based system).
+ * Once we know the map we take device configuration address and
+ * find PCIC pin number where INT line goes. Then we may either program
+ * preferred irq into the PCIC or supply the preexisting irq to the device.
+ *
+ * XXX Entries for JE-1 are completely bogus. Gleb, Vladimir, please fill them.
+ */
+struct pcic_ca2irq {
+	unsigned char busno;		/* PCI bus number */
+	unsigned char devfn;		/* Configuration address */
+	unsigned char pin;		/* PCIC external interrupt pin */
+	unsigned char irq;		/* Preferred IRQ (mappable in PCIC) */
+	unsigned int force;		/* Enforce preferred IRQ */
+};
+
+struct pcic_sn2list {
+	char *sysname;
+	struct pcic_ca2irq *intmap;
+	int mapdim;
+};
+
+/*
+ * XXX JE-1 is a little known beast.
+ * One rumor has the map this way: pin 0 - parallel, audio;
+ * pin 1 - Ethernet; pin 2 - su; pin 3 - PS/2 kbd and mouse.
+ * All other comparable systems tie serial and keyboard together,
+ * so we do not code this rumor just yet.
+ */
+static struct pcic_ca2irq pcic_i_je1[] = {
+	{ 0, 0x01, 1,  6, 1 },		/* Happy Meal */
+};
+
+/* XXX JS-E entry is incomplete - PCI Slot 2 address (pin 7)? */
+static struct pcic_ca2irq pcic_i_jse[] = {
+	{ 0, 0x00, 0, 13, 0 },		/* Ebus - serial and keyboard */
+	{ 0, 0x01, 1,  6, 0 },		/* hme */
+	{ 0, 0x08, 2,  9, 0 },		/* VGA - we hope not used :) */
+	{ 0, 0x18, 6,  8, 0 },		/* PCI INTA# in Slot 1 */
+	{ 0, 0x38, 4,  9, 0 },		/* All ISA devices. Read 8259. */
+	{ 0, 0x80, 5, 11, 0 },		/* EIDE */
+	/* {0,0x88, 0,0,0} - unknown device... PMU? Probably no interrupt. */
+	{ 0, 0xA0, 4,  9, 0 },		/* USB */
+	/*
+	 * Some pins belong to non-PCI devices, we hardcode them in drivers.
+	 * sun4m timers - irq 10, 14
+	 * PC style RTC - pin 7, irq 4 ?
+	 * Smart card, Parallel - pin 4 shared with USB, ISA
+	 * audio - pin 3, irq 5 ?
+	 */
+};
+
+/* SPARCengine-6 was the original release name of CP1200.
+ * The documentation differs between the two versions
+ */
+static struct pcic_ca2irq pcic_i_se6[] = {
+	{ 0, 0x08, 0,  2, 0 },		/* SCSI	*/
+	{ 0, 0x01, 1,  6, 0 },		/* HME	*/
+	{ 0, 0x00, 3, 13, 0 },		/* EBus	*/
+};
+
+/*
+ * Several entries in this list may point to the same routing map
+ * as several PROMs may be installed on the same physical board.
+ */
+#define SN2L_INIT(name, map)	\
+  { name, map, sizeof(map)/sizeof(struct pcic_ca2irq) }
+
+static struct pcic_sn2list pcic_known_sysnames[] = {
+	SN2L_INIT("JE-1-name", pcic_i_je1),  /* XXX Gleb, put name here, pls */
+	SN2L_INIT("SUNW,JS-E", pcic_i_jse),	/* PROLL JavaStation-E */
+	SN2L_INIT("SUNW,SPARCengine-6", pcic_i_se6), /* SPARCengine-6/CP-1200 */
+	{ NULL, NULL, 0 }
+};
+
X static struct linux_pcic PCIC;
X static struct linux_pcic *pcic = NULL;
X 
+unsigned int pcic_regs;
+volatile int pcic_speculative;
+volatile int pcic_trapped;
+
X static void pci_do_gettimeofday(struct timeval *tv);
X static void pci_do_settimeofday(struct timeval *tv);
X 
@@ -149,6 +243,37 @@
X 	pbm->prom_node = node;
X 	prom_getstring(node, "name", namebuf, sizeof(namebuf));
X 	strcpy(pbm->prom_name, namebuf);
+
+	{
+		extern volatile int t_nmi[1];
+		extern int pcic_nmi_trap_patch[1];
+
+		t_nmi[0] = pcic_nmi_trap_patch[0];
+		t_nmi[1] = pcic_nmi_trap_patch[1];
+		t_nmi[2] = pcic_nmi_trap_patch[2];
+		t_nmi[3] = pcic_nmi_trap_patch[3];
+		swift_flush_dcache();
+		pcic_regs = pcic->pcic_regs;
+	}
+
+	prom_getstring(prom_root_node, "name", namebuf, sizeof(namebuf));
+	{
+		struct pcic_sn2list *p;
+
+		for (p = pcic_known_sysnames; p->sysname != NULL; p++) {
+			if (strcmp(namebuf, p->sysname) == 0)
+				break;
+		}
+		pcic->pcic_imap = p->intmap;
+		pcic->pcic_imdim = p->mapdim;
+	}
+	if (pcic->pcic_imap == NULL) {
+		/*
+		 * We do not panic here for the sake of embedded systems.
+		 */
+		printk("PCIC: System %s is unknown, cannot route interrupts\n",
+		    namebuf);
+	}
X }
X 
X __initfunc(void pcibios_init(void))
@@ -166,20 +291,15 @@
X 	       pcic->pcic_regs, pcic->pcic_io);
X 
X 	/*
-	 * FIXME:
X 	 *      Switch off IOTLB translation.
-	 *      It'll be great to use IOMMU to handle HME's rings
-	 *      but we couldn't. Thus, we have to flush CPU cache
-	 *      in HME.
X 	 */
X 	writeb(PCI_DVMA_CONTROL_IOTLB_DISABLE, 
X 	       pcic->pcic_regs+PCI_DVMA_CONTROL);
X 
X 	/*
-	 * FIXME:
X 	 *      Increase mapped size for PCI memory space (DMA access).
X 	 *      Should be done in that order (size first, address second).
-	 *      Why we couldn't set up 4GB and forget about it ?
+	 *      Why we couldn't set up 4GB and forget about it? XXX
X 	 */
X 	writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0);
X 	writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY, 
@@ -204,7 +324,7 @@
X 		if(err != 0 && err != -1) {
X 			unsigned long devfn = (regs[0].which_io >> 8) & 0xff;
X 			if(devfn == pdev->devfn)
-				return node; /* Match */
+				return node;
X 		}
X 		node = prom_getsibling(node);
X 	}
@@ -216,9 +336,9 @@
X 	return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC);
X }
X 
-
-static void pcic_map_pci_device (struct pci_dev *dev) {
-	int node, pcinode;
+static void pcic_map_pci_device (struct pci_dev *dev, int node) {
+	struct linux_prom_pci_assigned_addresses addrs[6];
+	int addrlen;
X 	int i, j;
X 
X 	/* Is any valid address present ? */
@@ -227,74 +347,132 @@
X 		if (dev->base_address[j]) i++;
X 	if (!i) return; /* nothing to do */
X 
+	if (node == 0 || node == -1) {
+		printk("PCIC: no prom node for device ID (%x,%x)\n",
+		    dev->device, dev->vendor);
+		return;
+	}
+
X 	/*
X 	 * find related address and get it's window length
X 	 */
-	pcinode = prom_getchild(prom_root_node);
-	pcinode = prom_searchsiblings(pcinode, "pci");
-	if (!pcinode)
-		panic("PCIC: failed to locate 'pci' node");
-
-
-	for (node = prom_getchild(pcinode); node;
-	     node = prom_getsibling(node)) {
-		struct linux_prom_pci_assigned_addresses addrs[6];
-		int addrlen = prom_getproperty(node,"assigned-addresses",
+	addrlen = prom_getproperty(node,"assigned-addresses",
X 					       (char*)addrs, sizeof(addrs));
-		if (addrlen == -1)
-			continue;
+	if (addrlen == -1) {
+		printk("PCIC: no \"assigned-addresses\" for device (%x,%x)\n",
+		    dev->device, dev->vendor);
+		return;
+	}
X 
-		addrlen /= sizeof(struct linux_prom_pci_assigned_addresses);
-		for (i = 0; i < addrlen; i++ )
-		    for (j = 0; j < 6; j++) {
-			if (!dev->base_address[j] || !addrs[i].phys_lo)
-				continue;
-			if (addrs[i].phys_lo == dev->base_address[j]) {
-			    unsigned long address = dev->base_address[j];
-			    int length  = addrs[i].size_lo;
-			    char namebuf[128] = { 0, };
-			    unsigned long mapaddr, addrflags;
-	    
-			    prom_getstring(node, "name",
-					   namebuf,  sizeof(namebuf));
-
-			    /* FIXME:
-			     *      failure in allocation too large space
-			     */
-			    if (length > 0x200000) {
+	addrlen /= sizeof(struct linux_prom_pci_assigned_addresses);
+	for (i = 0; i < addrlen; i++ )
+	    for (j = 0; j < 6; j++) {
+		if (!dev->base_address[j] || !addrs[i].phys_lo)
+			continue;
+		if (addrs[i].phys_lo == dev->base_address[j]) {
+			unsigned long address = dev->base_address[j];
+			int length  = addrs[i].size_lo;
+			char namebuf[128] = { 0, };
+			unsigned long mapaddr, addrflags;
+
+			prom_getstring(node, "name", namebuf, sizeof(namebuf));
+
+			/*
+			 *      failure in allocation too large space
+			 */
+			if (length > 0x200000) {
X 				length = 0x200000;
X 				prom_printf("PCIC: map window for device '%s' "
X 					    "reduced to 2MB !\n", namebuf);
-			    }
+			}
X 
-			    /*
-			     *  Be careful with MEM/IO address flags
-			     */
-			    if ((address & PCI_BASE_ADDRESS_SPACE) ==
+			/*
+			 *  Be careful with MEM/IO address flags
+			 */
+			if ((address & PCI_BASE_ADDRESS_SPACE) ==
X 				 PCI_BASE_ADDRESS_SPACE_IO) {
X 				mapaddr = address & PCI_BASE_ADDRESS_IO_MASK;
-			    } else {
+			} else {
X 				mapaddr = address & PCI_BASE_ADDRESS_MEM_MASK;
-			    }
-			    addrflags = address ^ mapaddr;
+			}
+			addrflags = address ^ mapaddr;
X 
-			    dev->base_address[j] =
+			dev->base_address[j] =
X 				(unsigned long)sparc_alloc_io(address, 0, 
X 							      length,
X 							      namebuf, 0, 0);
-			    if ( dev->base_address[j] == 0 )
+			if ( dev->base_address[j] == 0 )
X 				panic("PCIC: failed make mapping for "
X 				      "pci device '%s' with address %lx\n",
X 				       namebuf, address);
X 
-			    dev->base_address[j] ^= addrflags;
-			    return;
-			}
+			dev->base_address[j] ^= addrflags;
+			return;
X 		}
+	    }
+
+	printk("PCIC: unable to match addresses for device (%x,%x)\n",
+	    dev->device, dev->vendor);
+}
+
+static void pcic_fill_irq(struct pci_dev *dev, int node) {
+	struct pcic_ca2irq *p;
+	int i, ivec;
+	char namebuf[64];  /* P3 remove */
+
+	if (node == -1) {
+		strcpy(namebuf, "???");
+	} else {
+		prom_getstring(node, "name", namebuf, sizeof(namebuf)); /* P3 remove */
X 	}
X 
-	panic("PCIC: unable to locate prom node for pci device (%x,%x) \n",
-	      dev->device, dev->vendor);
+	if ((p = pcic->pcic_imap) == 0) {
+		dev->irq = 0;
+		return;
+	}
+	for (i = 0; i < pcic->pcic_imdim; i++) {
+		if (p->busno == dev->bus->number && p->devfn == dev->devfn)
+			break;
+		p++;
+	}
+	if (i >= pcic->pcic_imdim) {
+		printk("PCIC: device %s devfn %02x:%02x not found in %d\n",
+		    namebuf, dev->bus->number, dev->devfn, pcic->pcic_imdim);
+		dev->irq = 0;
+		return;
+	}
+
+	i = p->pin;
+	if (i >= 0 && i < 4) {
+		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);
+		dev->irq = ivec >> (i << 2) & 0xF;
+	} else if (i >= 4 && i < 8) {
+		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);
+		dev->irq = ivec >> ((i-4) << 2) & 0xF;
+	} else {					/* Corrupted map */
+		printk("PCIC: BAD PIN %d\n", i); for (;;) {}
+	}
+/* P3 remove later */ printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq);
+
+	/*
+	 * dev->irq=0 means PROM did not bothered to program the upper
+	 * half of PCIC. This happens on JS-E with PROM 3.11, for instance.
+	 */
+	if (dev->irq == 0 || p->force) {
+		if (p->irq == 0 || p->irq >= 15) {	/* Corrupted map */
+			printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {}
+		}
+		printk("PCIC: setting irq %x for device (%x,%x)\n",
+		    p->irq, dev->device, dev->vendor);
+		dev->irq = p->irq;
+
+		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);
+		ivec &= ~(0xF << ((p->pin - 4) << 2));
+		ivec |= p->irq << ((p->pin - 4) << 2);
+		writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_HI);
+	}
+
+	return;
X }
X 
X /*
@@ -317,9 +495,10 @@
X 		writeb((pcic->pcic_io_phys>>24) & PCI_SIBAR_ADDRESS_MASK,
X 		       pcic->pcic_regs+PCI_SIBAR);
X 		writeb(PCI_ISIZE_16M, pcic->pcic_regs+PCI_ISIZE);
+
X 	}
X 	if(paddr < pcic->pcic_mapped_io ||
-	   paddr > pcic->pcic_mapped_io + PCI_SPACE_SIZE)
+	   paddr >= pcic->pcic_mapped_io + 0x10000)
X 		return 0;
X 	offset = paddr - pcic->pcic_mapped_io;
X 	*addr = pcic->pcic_io_phys + offset;
@@ -334,6 +513,9 @@
X   struct pci_dev *dev;
X   int i, has_io, has_mem;
X   unsigned short cmd;
+	struct linux_pbm_info* pbm = &pcic->pbm;
+	int node;
+	struct pcidev_cookie *pcp;
X 
X 	if(pcic == NULL) {
X 		prom_printf("PCI: Error, PCIC not found.\n");
@@ -359,47 +541,61 @@
X 		}
X 		pci_read_config_word(dev, PCI_COMMAND, &cmd);
X 		if (has_io && !(cmd & PCI_COMMAND_IO)) {
-			printk("PCI: Enabling I/O for device %02x:%02x\n",
+			printk("PCIC: Enabling I/O for device %02x:%02x\n",
X 				dev->bus->number, dev->devfn);
X 			cmd |= PCI_COMMAND_IO;
X 			pci_write_config_word(dev, PCI_COMMAND, cmd);
X 		}
X 		if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
-			printk("PCI: Enabling memory for device %02x:%02x\n",
+			printk("PCIC: Enabling memory for device %02x:%02x\n",
X 				dev->bus->number, dev->devfn);
X 			cmd |= PCI_COMMAND_MEMORY;
X 			pci_write_config_word(dev, PCI_COMMAND, cmd);
X 		}    
X 
+		node = pdev_to_pnode(pbm, dev);
+		if(node == 0)
+			node = -1;
+
X 		/* cookies */
-		{
-			struct pcidev_cookie *pcp;
-			struct linux_pbm_info* pbm = &pcic->pbm;
-			int node = pdev_to_pnode(pbm, dev);
-
-			if(node == 0)
-				node = -1;
-			pcp = pci_devcookie_alloc();
-			pcp->pbm = pbm;
-			pcp->prom_node = node;
-			dev->sysdata = pcp;
-		}
+		pcp = pci_devcookie_alloc();
+		pcp->pbm = pbm;
+		pcp->prom_node = node;
+		dev->sysdata = pcp;
X 
X 		/* memory mapping */
-		if (!(dev->vendor == PCI_VENDOR_ID_SUN &&
-		      dev->device == PCI_DEVICE_ID_SUN_EBUS)) {
-			pcic_map_pci_device(dev);
-		}
+		if ((dev->class>>16) != PCI_BASE_CLASS_BRIDGE)
+			pcic_map_pci_device(dev, node);
X 
-		/* irq */
-#define SETIRQ(vend,devid,irqn) \
-	if (dev->vendor==vend && dev->device==devid) dev->irq = irqn;
-
-		SETIRQ(PCI_VENDOR_ID_SUN,PCI_DEVICE_ID_SUN_HAPPYMEAL,3);
+		pcic_fill_irq(dev, node);
X 	}
+
X 	ebus_init();
X }
X 
+/*
+ * pcic_pin_to_irq() is exported to ebus.c.
+ */
+unsigned int
+pcic_pin_to_irq(unsigned int pin, char *name)
+{
+	unsigned int irq;
+	unsigned int ivec;
+
+	if (pin < 4) {
+		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);
+		irq = ivec >> (pin << 2) & 0xF;
+	} else if (pin < 8) {
+		ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);
+		irq = ivec >> ((pin-4) << 2) & 0xF;
+	} else {					/* Corrupted map */
+		printk("PCIC: BAD PIN %d FOR %s\n", pin, name);
+		for (;;) {}	/* XXX Cannot panic properly in case of PROLL */
+	}
+/* P3 remove later */ printk("PCIC: dev %s pin %d ivec 0x%x irq %x\n", name, pin, ivec, irq);
+	return irq;
+}
+
X /* Makes compiler happy */
X static volatile int pcic_timer_dummy;
X 
@@ -539,26 +735,38 @@
X 			       unsigned char where, unsigned int *value)
X {
X 	unsigned long flags;
-	if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
-	if (bus != 0 || 
-	    (device_fn != 0 && device_fn != 1 && device_fn != 0x80)) {
-		*value = 0xffffffff;
-		return PCIBIOS_SUCCESSFUL;
-	}
X 
-	/* FIXME: IGA haven't got high config memory addresses !!! */
-	if (device_fn == 0x80 && where > PCI_INTERRUPT_LINE) {
-		*value = 0xffffffff;
-		return PCIBIOS_SUCCESSFUL;
-	}
+	if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
X 
X 	save_and_cli(flags);
+#if 0
+	pcic_speculative = 1;
+	pcic_trapped = 0;
+#endif
X 	writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr);
+#if 0
+	nop();
+	if (pcic_trapped) {
+		restore_flags(flags);
+		*value = ~0;
+		return PCIBIOS_SUCCESSFUL;
+	}
+#endif
+	pcic_speculative = 2;
+	pcic_trapped = 0;
X 	*value = readl(pcic->pcic_config_space_data + (where&4));
+	nop();
+	if (pcic_trapped) {
+		pcic_speculative = 0;
+		restore_flags(flags);
+		*value = ~0;
+		return PCIBIOS_SUCCESSFUL;
+	}
+	pcic_speculative = 0;
X 	restore_flags(flags);
X 	return PCIBIOS_SUCCESSFUL;
X }
-    
+
X int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
X 			       unsigned char where, unsigned char value)
X {
@@ -586,8 +794,8 @@
X 				unsigned char where, unsigned int value)
X {
X 	unsigned long flags;
-	if ((where&3) || bus != 0 || (devfn != 0 && devfn != 1 && devfn != 0x80))
-		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
X 
X 	save_and_cli(flags);
X 	writel(CONFIG_CMD(bus,devfn,where),pcic->pcic_config_space_addr);
@@ -599,6 +807,29 @@
X __initfunc(char *pcibios_setup(char *str))
X {
X 	return str;
+}
+
+/*
+ * NMI
+ */
+void pcic_nmi(unsigned int pend, struct pt_regs *regs)
+{
+
+	pend = flip_dword(pend);
+
+	if (!pcic_speculative || (pend & PCI_SYS_INT_PENDING_PIO) == 0) {
+		/*
+		 * XXX On CP-1200 PCI #SERR may happen, we do not know
+		 * what to do about it yet.
+		 */
+		printk("Aiee, NMI pend 0x%x pc 0x%x spec %d, hanging\n",
+		    pend, (int)regs->pc, pcic_speculative);
+		for (;;) { }
+	}
+	pcic_speculative = 0;
+	pcic_trapped = 1;
+	regs->pc = regs->npc;
+	regs->npc += 4;
X }
X 
X /*
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.3.5/linux/arch/sparc/kernel/ptrace.c	Mon May 31 22:28:04 1999
+++ linux/arch/sparc/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -134,26 +134,6 @@
X 	flush_tlb_page(vma, addr);
X }
X 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
- unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm,addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.3.5/linux/arch/sparc/kernel/setup.c	Mon May 31 22:28:04 1999
+++ linux/arch/sparc/kernel/setup.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.106 1999/05/28 16:03:18 anton Exp $
+/*  $Id: setup.c,v 1.107 1999/06/03 15:02:20 davem Exp $
X  *  linux/arch/sparc/kernel/setup.c
X  *
X  *  Copyright (C) 1995  David S. Miller (da...@caip.rutgers.edu)
@@ -313,6 +313,7 @@
X 	if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
X 	if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
X 	if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
+	if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; }  /* CP-1200 with PROM 2.30 -E */
X 	if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
X 	if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
X 	if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
diff -u --recursive --new-file v2.3.5/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.5/linux/arch/sparc/kernel/sys_sunos.c	Mon May 31 22:28:04 1999
+++ linux/arch/sparc/kernel/sys_sunos.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.97 1999/05/24 19:40:39 davem Exp $
+/* $Id: sys_sunos.c,v 1.98 1999/06/09 08:23:39 davem Exp $
X  * sys_sunos.c: SunOS specific syscall compatibility support.
X  *
X  * Copyright (C) 1995 David S. Miller (da...@caip.rutgers.edu)
@@ -150,7 +150,6 @@
X 	unsigned long newbrk, oldbrk;
X 
X 	down(¤t->mm->mmap_sem);
-	lock_kernel();
X 	if(ARCH_SUN4C_SUN4) {
X 		if(brk >= 0x20000000 && brk < 0xe0000000) {
X 			goto out;
@@ -210,12 +209,9 @@
X 	 * Ok, we have probably got enough memory - let it rip.
X 	 */
X 	current->mm->brk = brk;
-	do_mmap(NULL, oldbrk, newbrk-oldbrk,
-		PROT_READ|PROT_WRITE|PROT_EXEC,
-		MAP_FIXED|MAP_PRIVATE, 0);
+	do_brk(oldbrk, newbrk-oldbrk)
X 	retval = 0;
X out:
-	unlock_kernel();
X 	up(¤t->mm->mmap_sem);
X 	return retval;
X }
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.3.5/linux/arch/sparc64/Makefile	Wed Mar 10 16:53:36 1999
+++ linux/arch/sparc64/Makefile	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.35 1999/01/02 16:45:50 davem Exp $
+# $Id: Makefile,v 1.37 1999/06/04 13:29:10 jj Exp $
X # sparc64/Makefile
X #
X # Makefile for the architecture dependent flags and dependencies on the
@@ -15,7 +15,7 @@
X CC		:= sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
X 
X CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| 	\)' > /dev/null; then echo y; else echo n; fi)
-IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
+IS_EGCS := $(shell if $(CC) -c -m64 -mcmodel=medlow -o _tmp.o arch/sparc64/math-emu/fnegq.c >/dev/null 2>&1; then echo y; else echo n; fi; rm -f _tmp.o)
X NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
X 
X ifneq ($(CC_HAS_ARGS),y)
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.5/linux/arch/sparc64/defconfig	Mon May 31 22:28:04 1999
+++ linux/arch/sparc64/defconfig	Wed Jun  9 14:44:25 1999
@@ -69,6 +69,8 @@
X # CONFIG_SUN_BPP is not set
X # CONFIG_SUN_VIDEOPIX is not set
X CONFIG_SUN_AURORA=m
+CONFIG_APM_RTC_IS_GMT=y
+# CONFIG_RTC is not set
X 
X #
X # Linux/SPARC audio subsystem (EXPERIMENTAL)
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.3.5/linux/arch/sparc64/kernel/binfmt_aout32.c	Mon Mar 22 10:06:36 1999
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Wed Jun  9 14:44:25 1999
@@ -48,9 +48,7 @@
X 	end = PAGE_ALIGN(end);
X 	if (end <= start)
X 		return;
-	do_mmap(NULL, start, end - start,
-		PROT_READ | PROT_WRITE | PROT_EXEC,
-		MAP_FIXED | MAP_PRIVATE, 0);
+	do_brk(start, end - start);
X }
X 
X /*
@@ -284,24 +282,18 @@
X  	current->flags &= ~PF_FORKNOEXEC;
X 	if (N_MAGIC(ex) == NMAGIC) {
X 		/* Fuck me plenty... */
-		error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
-				PROT_READ|PROT_WRITE|PROT_EXEC,
-				MAP_FIXED|MAP_PRIVATE, 0);
+		error = do_brk(N_TXTADDR(ex), ex.a_text);
X 		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
X 			  ex.a_text, 0);
-		error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
-				PROT_READ|PROT_WRITE|PROT_EXEC,
-				MAP_FIXED|MAP_PRIVATE, 0);
+		error = do_brk(N_DATADDR(ex), ex.a_data);
X 		read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
X 			  ex.a_data, 0);
X 		goto beyond_if;
X 	}
X 
X 	if (N_MAGIC(ex) == OMAGIC) {
-		do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
-			ex.a_text+ex.a_data + PAGE_SIZE - 1,
-			PROT_READ|PROT_WRITE|PROT_EXEC,
-			MAP_FIXED|MAP_PRIVATE, 0);
+		do_brk(N_TXTADDR(ex) & PAGE_MASK,
+			ex.a_text+ex.a_data + PAGE_SIZE - 1);
X 		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
X 			  ex.a_text+ex.a_data, 0);
X 	} else {
@@ -316,9 +308,7 @@
X 
X 		if (!file->f_op || !file->f_op->mmap) {
X 			sys_close(fd);
-			do_mmap(NULL, 0, ex.a_text+ex.a_data,
-				PROT_READ|PROT_WRITE|PROT_EXEC,
-				MAP_FIXED|MAP_PRIVATE, 0);
+			do_brk(0, ex.a_text+ex.a_data);
X 			read_exec(bprm->dentry, fd_offset,
X 				  (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
X 			goto beyond_if;
@@ -359,11 +349,16 @@
X 
X 	set_brk(current->mm->start_brk, current->mm->brk);
X 
-	p = setup_arg_pages(p, bprm);
+	retval = setup_arg_pages(bprm);
+	if (retval < 0) { 
+		/* Someone check-me: is this error path enough? */ 
+		send_sig(SIGKILL, current, 0); 
+		return retval;
+	}
X 
-	p = (unsigned long) create_aout32_tables((char *)p, bprm);
-	current->mm->start_stack = p;
-	start_thread32(regs, ex.a_entry, p);
+	current->mm->start_stack =
+		(unsigned long) create_aout32_tables((char *)bprm->p, bprm);
+	start_thread32(regs, ex.a_entry, current->mm->start_stack);
X 	if (current->flags & PF_PTRACED)
X 		send_sig(SIGTRAP, current, 0);
X 	return 0;
@@ -442,9 +437,7 @@
X 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
X 	bss = ex.a_text + ex.a_data + ex.a_bss;
X 	if (bss > len) {
-		error = do_mmap(NULL, start_addr + len, bss - len,
-				PROT_READ | PROT_WRITE | PROT_EXEC,
-				MAP_PRIVATE | MAP_FIXED, 0);
+		error = do_brk(start_addr + len, bss - len);
X 		retval = error;
X 		if (error != start_addr + len)
X 			goto out_putf;
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.5/linux/arch/sparc64/kernel/ioctl32.c	Tue May 11 08:24:31 1999
+++ linux/arch/sparc64/kernel/ioctl32.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.62 1999/05/01 09:17:44 davem Exp $
+/* $Id: ioctl32.c,v 1.63 1999/06/09 04:56:14 davem Exp $
X  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
X  *
X  * Copyright (C) 1997  Jakub Jelinek  (j...@sunsite.mff.cuni.cz)
@@ -37,6 +37,7 @@
X #include <linux/fb.h>
X #include <linux/ext2_fs.h>
X #include <linux/videodev.h>
+#include <linux/netdevice.h>
X 
X #include <scsi/scsi.h>
X /* Ugly hack. */
@@ -417,6 +418,23 @@
X         __kernel_caddr_t32  ifcbuf;
X };
X 
+static int dev_ifname32(unsigned int fd, unsigned long arg)
+{
+	struct device *dev;
+	struct ifreq32 ifr32;
+	int err;
+
+	if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+
+	dev = dev_get_by_index(ifr32.ifr_ifindex);
+	if (!dev)
+		return -ENODEV;
+
+	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
+	return (err ? -EFAULT : 0);
+}
+
X static inline int dev_ifconf(unsigned int fd, unsigned long arg)
X {
X 	struct ifconf32 ifc32;
@@ -1687,6 +1705,10 @@
X 		goto out;
X 	}
X 	switch (cmd) {
+	case SIOCGIFNAME:
+		error = dev_ifname32(fd, arg);
+		goto out;
+
X 	case SIOCGIFCONF:
X 		error = dev_ifconf(fd, arg);
X 		goto out;
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.3.5/linux/arch/sparc64/kernel/ptrace.c	Mon May 31 22:28:04 1999
+++ linux/arch/sparc64/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
@@ -204,26 +204,6 @@
X 	flush_tlb_page(vma, addr);
X }
X 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
- unsigned long addr)
-{
-	struct vm_area_struct * vma;
-
-	addr &= PAGE_MASK;
-	vma = find_vma(tsk->mm,addr);
-	if (!vma)
-		return NULL;
-	if (vma->vm_start <= addr)
-		return vma;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		return NULL;
-	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
-		return NULL;
-	vma->vm_offset -= vma->vm_start - addr;
-	vma->vm_start = addr;
-	return vma;
-}
-
X /*
X  * This routine checks the page boundaries, and that the offset is
X  * within the task area. It then calls get_long() to read a long.
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.3.5/linux/arch/sparc64/kernel/signal.c	Tue Oct 27 09:52:20 1998
+++ linux/arch/sparc64/kernel/signal.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.38 1998/10/16 03:19:04 davem Exp $
+/*  $Id: signal.c,v 1.40 1999/06/02 19:19:52 jj Exp $
X  *  arch/sparc64/kernel/signal.c
X  *
X  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -491,7 +491,7 @@
X /* Checks if the fp is valid */
X static int invalid_frame_pointer(void *fp, int fplen)
X {
-	if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x80000000000ULL - fplen)
+	if (((unsigned long) fp) & 7)
X 		return 1;
X 	return 0;
X }
@@ -554,8 +554,10 @@
X 		goto sigill;
X 
X 	if (current->tss.w_saved != 0) {
+#ifdef DEBUG_SIGNALS
X 		printk ("%s[%d]: Invalid user stack frame for "
X 			"signal delivery.\n", current->comm, current->pid);
+#endif
X 		goto sigill;
X 	}
X 
@@ -590,35 +592,7 @@
X 	regs->tnpc = (regs->tpc + 4);
X 
X 	/* 4. return to kernel instructions */
-	if (ka->ka_restorer)
-		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
-	else {
-		/* Flush instruction space. */
-		unsigned long address = ((unsigned long)&(sf->insns[0]));
-		pgd_t *pgdp = pgd_offset(current->mm, address);
-		pmd_t *pmdp = pmd_offset(pgdp, address);
-		pte_t *ptep = pte_offset(pmdp, address);
-
-		regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
-		
-		/* mov __NR_sigreturn, %g1 */
-		err |= __put_user(0x821020d8, &sf->insns[0]);
-
-		/* t 0x6d */
-		err |= __put_user(0x91d0206d, &sf->insns[1]);
-		if (err)
-			goto sigsegv;
-
-		if(pte_present(*ptep)) {
-			unsigned long page = pte_page(*ptep);
-
-			__asm__ __volatile__("
-			membar	#StoreStore
-			flush	%0 + %1"
-			: : "r" (page), "r" (address & (PAGE_SIZE - 1))
-			: "memory");
-		}
-	}
+	regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
X 	return;
X 
X sigill:
@@ -650,8 +624,10 @@
X 		goto sigill;
X 
X 	if (current->tss.w_saved != 0) {
+#ifdef DEBUG_SIGNALS
X 		printk ("%s[%d]: Invalid user stack frame for "
X 			"signal delivery.\n", current->comm, current->pid);
+#endif
X 		goto sigill;
X 	}
X 
@@ -690,35 +666,7 @@
X 	regs->tnpc = (regs->tpc + 4);
X 
X 	/* 4. return to kernel instructions */
-	if (ka->ka_restorer)
-		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
-	else {
-		/* Flush instruction space. */
-		unsigned long address = ((unsigned long)&(sf->insns[0]));
-		pgd_t *pgdp = pgd_offset(current->mm, address);
-		pmd_t *pmdp = pmd_offset(pgdp, address);
-		pte_t *ptep = pte_offset(pmdp, address);
-
-		regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
-		
-		/* mov __NR_rt_sigreturn, %g1 */
-		err |= __put_user(0x82102065, &sf->insns[0]);
-
-		/* t 0x6d */
-		err |= __put_user(0x91d0206d, &sf->insns[1]);
-		if (err)
-			goto sigsegv;
-
-		if(pte_present(*ptep)) {
-			unsigned long page = pte_page(*ptep);
-
-			__asm__ __volatile__("
-			membar	#StoreStore
-			flush	%0 + %1"
-			: : "r" (page), "r" (address & (PAGE_SIZE - 1))
-			: "memory");
-		}
-	}
+	regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
X 	return;
X 
X sigill:
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.3.5/linux/arch/sparc64/kernel/sys_sparc.c	Wed Mar 10 16:53:37 1999
+++ linux/arch/sparc64/kernel/sys_sparc.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.26 1999/01/07 19:07:01 jj Exp $
+/* $Id: sys_sparc.c,v 1.27 1999/06/02 12:06:34 jj Exp $
X  * linux/arch/sparc64/kernel/sys_sparc.c
X  *
X  * This file contains various random system calls that
@@ -325,39 +325,6 @@
X 		return -EINVAL;
X 	regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14);
X 	return 0;
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
-	      struct old_sigaction *oact)
-{
-	struct k_sigaction new_ka, old_ka;
-	int ret;
-
-	if (act) {
-		old_sigset_t mask;
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
-		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
-			return -EFAULT;
-		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
-		__get_user(mask, &act->sa_mask);
-		siginitset(&new_ka.sa.sa_mask, mask);
-		new_ka.ka_restorer = NULL;
-	}
-
-	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
-		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
-			return -EFAULT;
-		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-	}
-
-	return ret;
X }
X 
X asmlinkage int
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.5/linux/arch/sparc64/kernel/sys_sparc32.c	Mon May 17 09:55:21 1999
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.108 1999/05/16 10:50:32 davem Exp $
+/* $Id: sys_sparc32.c,v 1.109 1999/06/03 07:11:31 davem Exp $
X  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
X  *
X  * Copyright (C) 1997,1998 Jakub Jelinek (j...@sunsite.mff.cuni.cz)
@@ -2776,42 +2776,46 @@
X  * memory to free pages in kernel mem. These are in a format ready
X  * to be put directly into the top of new user memory.
X  */
-static unsigned long
-copy_strings32(int argc,u32 * argv,unsigned long *page,
-	       unsigned long p)
+static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
X {
-	u32 str;
-
-	if (!p) return 0;	/* bullet-proofing */
X 	while (argc-- > 0) {
+		u32 str;
X 		int len;
X 		unsigned long pos;
X 
-		get_user(str, argv+argc);
-		if (!str) panic("VFS: argc is wrong");
-		len = strlen_user((char *)A(str));	/* includes the '\0' */
-		if (p < len)	/* this shouldn't happen - 128kB */
-			return 0;
-		p -= len; pos = p;
+		if (get_user(str, argv + argc) ||
+		    !str ||
+		    !(len = strlen_user((char *)A(str))))
+			return -EFAULT;
+		if (bprm->p < len)
+			return -E2BIG;
+
+		bprm->p -= len;
+
+		pos = bprm->p;
X 		while (len) {
X 			char *pag;
X 			int offset, bytes_to_copy;
X 
X 			offset = pos % PAGE_SIZE;
-			if (!(pag = (char *) page[pos/PAGE_SIZE]) &&
-			    !(pag = (char *) page[pos/PAGE_SIZE] =
+			if (!(pag = (char *) bprm->page[pos/PAGE_SIZE]) &&
+			    !(pag = (char *) bprm->page[pos/PAGE_SIZE] =
X 			      (unsigned long *) get_free_page(GFP_USER)))
-				return 0;
+				return -ENOMEM;
+
X 			bytes_to_copy = PAGE_SIZE - offset;
X 			if (bytes_to_copy > len)
X 				bytes_to_copy = len;
-			copy_from_user(pag + offset, (char *)A(str), bytes_to_copy);
+
+			if (copy_from_user(pag + offset, (char *)A(str), bytes_to_copy))
+				return -EFAULT;
+
X 			pos += bytes_to_copy;
X 			str += bytes_to_copy;
X 			len -= bytes_to_copy;
X 		}
X 	}
-	return p;
+	return 0;
X }
X 
X /*
@@ -2850,29 +2854,36 @@
X 	}
X 
X 	retval = prepare_binprm(&bprm);
+	if (retval < 0)
+		goto out;
X 	
-	if(retval>=0) {
-		bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
-		bprm.exec = bprm.p;
-		bprm.p = copy_strings32(bprm.envc,envp,bprm.page,bprm.p);
-		bprm.p = copy_strings32(bprm.argc,argv,bprm.page,bprm.p);
-		if (!bprm.p)
-			retval = -E2BIG;
-	}
+	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+	if (retval < 0)
+		goto out;
+
+	bprm.exec = bprm.p;
+	retval = copy_strings32(bprm.envc, envp, &bprm);
+	if (retval < 0)
+		goto out;
X 
-	if(retval>=0)
-		retval = search_binary_handler(&bprm,regs);
-	if(retval>=0)
+	retval = copy_strings32(bprm.argc, argv, &bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = search_binary_handler(&bprm, regs);
+	if (retval >= 0)
X 		/* execve success */
X 		return retval;
X 
+out:
X 	/* Something went wrong, return the inode and free the argument pages*/
-	if(bprm.dentry)
+	if (bprm.dentry)
X 		dput(bprm.dentry);
X 
X 	for (i=0 ; i<MAX_ARG_PAGES ; i++)
X 		free_page(bprm.page[i]);
-	return(retval);
+
+	return retval;
X }
X 
X /*
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.5/linux/arch/sparc64/kernel/sys_sunos32.c	Mon May 31 22:28:04 1999
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.25 1999/05/24 19:40:44 davem Exp $
+/* $Id: sys_sunos32.c,v 1.26 1999/06/09 08:23:54 davem Exp $
X  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
X  *
X  * Copyright (C) 1995, 1996, 1997 David S. Miller (da...@caip.rutgers.edu)
@@ -134,7 +134,6 @@
X 	unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
X 
X 	down(¤t->mm->mmap_sem);
-	lock_kernel();
X 	if (brk < current->mm->end_code)
X 		goto out;
X 	newbrk = PAGE_ALIGN(brk);
@@ -175,12 +174,9 @@
X 		goto out;
X 	/* Ok, we have probably got enough memory - let it rip. */
X 	current->mm->brk = brk;
-	do_mmap(NULL, oldbrk, newbrk-oldbrk,
-		PROT_READ|PROT_WRITE|PROT_EXEC,
-		MAP_FIXED|MAP_PRIVATE, 0);
+	do_brk(oldbrk, newbrk-oldbrk);
X 	retval = 0;
X out:
-	unlock_kernel();
X 	up(¤t->mm->mmap_sem);
X 	return retval;
X }
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.3.5/linux/arch/sparc64/kernel/systbls.S	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/kernel/systbls.S	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.53 1999/04/07 17:14:11 davem Exp $
+/* $Id: systbls.S,v 1.54 1999/06/02 12:06:31 jj Exp $
X  * systbls.S: System call entry point tables for OS compatibility.
X  *            The native Linux system call table lives here also.
X  *
@@ -115,7 +115,7 @@
X /*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
X 	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
X /*190*/	.word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_sigaction, sys_sgetmask
+	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
X /*200*/	.word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
X 	.word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
X /*210*/	.word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.3.5/linux/arch/sparc64/kernel/traps.c	Mon May 31 22:28:04 1999
+++ linux/arch/sparc64/kernel/traps.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.59 1999/05/18 16:57:10 jj Exp $
+/* $Id: traps.c,v 1.60 1999/06/02 19:19:55 jj Exp $
X  * arch/sparc64/kernel/traps.c
X  *
X  * Copyright (C) 1995,1997 David S. Miller (da...@caip.rutgers.edu)
@@ -282,11 +282,16 @@
X 				   unsigned long sfsr, unsigned long sfar)
X {
X 	lock_kernel();
+	if (regs->tstate & TSTATE_PRIV) {
X #if 1
-	printk("instruction_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n",
-	       sfsr, sfar);
+		printk("instruction_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n",
+		       sfsr, sfar);
X #endif
-	die_if_kernel("Iax", regs);
+		die_if_kernel("Iax", regs);
+	}
+	current->tss.sig_desc = SUBSIG_ILLINST;
+	current->tss.sig_address = regs->tpc;
+	force_sig(SIGILL, current);
X 	unlock_kernel();
X }
X 
diff -u --recursive --new-file v2.3.5/linux/arch/sparc64/math-emu/sfp-util.h linux/arch/sparc64/math-emu/sfp-util.h
--- v2.3.5/linux/arch/sparc64/math-emu/sfp-util.h	Mon May 31 22:28:05 1999
+++ linux/arch/sparc64/math-emu/sfp-util.h	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: sfp-util.h,v 1.1 1999/05/28 13:43:07 jj Exp $
+/* $Id: sfp-util.h,v 1.2 1999/06/07 18:24:15 jj Exp $
X  * arch/sparc64/math-emu/sfp-util.h
X  *
X  * Copyright (C) 1999 Jakub Jelinek (j...@ultra.linux.cz)
@@ -55,7 +55,7 @@
X 		    srlx %7,32,%5
X 		    mulx %3,%5,%3
X 		    mulx %2,%5,%5
-		    sethi 0x80000000,%2
+		    sethi %%hi(0x80000000),%2
X 		    addcc %4,%3,%4
X 		    srlx %4,32,%4
X 		    add %2,%2,%2
diff -u --recursive --new-file v2.3.5/linux/drivers/Makefile linux/drivers/Makefile
--- v2.3.5/linux/drivers/Makefile	Mon May 10 10:18:34 1999
+++ linux/drivers/Makefile	Wed Jun  2 14:40:22 1999
@@ -53,6 +53,15 @@
X   endif
X endif 
X 
+ifeq ($(CONFIG_I2O),y)
+SUB_DIRS += i2o
+MOD_SUB_DIRS += i2o
+else
+  ifeq ($(CONFIG_I2O),m)
+  MOD_SUB_DIRS += i2o
+  endif
+endif 
+
X # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
X # but some of the low-level things may also be modules.
X ifeq ($(CONFIG_SCSI),y)
diff -u --recursive --new-file v2.3.5/linux/drivers/block/cy82c693.c linux/drivers/block/cy82c693.c
--- v2.3.5/linux/drivers/block/cy82c693.c	Mon May 31 22:28:05 1999
+++ linux/drivers/block/cy82c693.c	Wed Jun  2 22:21:51 1999
@@ -423,7 +423,8 @@
X __initfunc(void ide_init_cy82c693(ide_hwif_t *hwif))
X {
X 	hwif->chipset = ide_cy82c693;
-	hwif->dmaproc = &cy82c693_dmaproc;
+	if (hwif->dma_base)
+		hwif->dmaproc = &cy82c693_dmaproc;
X 	hwif->tuneproc = &cy82c693_tune_drive;
X 
X 	init_cy82c693_chip(hwif->pci_dev);
diff -u --recursive --new-file v2.3.5/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.5/linux/drivers/block/floppy.c	Mon May 17 09:55:21 1999
+++ linux/drivers/block/floppy.c	Wed Jun  9 16:42:58 1999
@@ -1927,8 +1927,6 @@
X 
X static void floppy_ready(void)
X {
-	unsigned long flags;
-	
X 	CHECK_RESET;
X 	if (start_motor(floppy_ready)) return;
X 	if (fdc_dtr()) return;
@@ -1948,7 +1946,7 @@
X 	if ((raw_cmd->flags & FD_RAW_READ) || 
X 	    (raw_cmd->flags & FD_RAW_WRITE))
X 	{
-		flags=claim_dma_lock();
+		unsigned long flags = claim_dma_lock();
X 		fd_chose_dma_mode(raw_cmd->kernel_data,
X 				  raw_cmd->length);
X 		release_dma_lock(flags);
diff -u --recursive --new-file v2.3.5/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.3.5/linux/drivers/block/ide-pmac.c	Fri May 14 18:55:14 1999
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 02'
echo 'File patch-2.3.6 is continued in part 03'
echo 03 > _shar_seq_.tmp
#!/bin/sh
# this is part 03 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 03; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+++ linux/drivers/block/ide-pmac.c	Mon Jun  7 12:12:22 1999
@@ -65,7 +65,6 @@
X 				ide_ioreg_t ctrl_port,
X 				int *irq)
X {
-	ide_ioreg_t reg = ide_ioreg_t data_port;
X 	int i, r;
X 
X 	if (data_port == 0)
@@ -76,20 +75,15 @@
X 	r = check_media_bay_by_base(data_port, MB_CD);
X 	if (r == -EINVAL)
X 		return;
-		
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg * 0x10;
-		reg += 1;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x160;
-	}
+	
+	for ( i = 0; i < 8 ; ++i )
+		hw->io_ports[i] = data_port + i * 0x10;
+	hw->io_ports[8] = data_port + 0x160;
+
X 	if (irq != NULL) {
X 		*irq = 0;
X 		for (i = 0; i < MAX_HWIFS; ++i) {
-			if (base == pmac_ide_regbase[i]) {
+			if (data_port == pmac_ide_regbase[i]) {
X 				*irq = pmac_ide_irq[i];
X 				break;
X 			}
@@ -156,7 +150,7 @@
X 			       np->full_name);
X 			continue;
X 		}
-		
+
X 		base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
X 		
X 		/* XXX This is bogus. Should be fixed in the registry by checking
diff -u --recursive --new-file v2.3.5/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.5/linux/drivers/block/ll_rw_blk.c	Fri May 14 18:55:14 1999
+++ linux/drivers/block/ll_rw_blk.c	Wed Jun  2 22:21:51 1999
@@ -471,6 +471,8 @@
X 	     case IDE3_MAJOR:
X 	     case IDE4_MAJOR:
X 	     case IDE5_MAJOR:
+	     case IDE6_MAJOR:
+	     case IDE7_MAJOR:
X 	     case ACSI_MAJOR:
X 	     case MFM_ACORN_MAJOR:
X 		/*
@@ -497,6 +499,7 @@
X 	     case SCSI_DISK6_MAJOR:
X 	     case SCSI_DISK7_MAJOR:
X 	     case SCSI_CDROM_MAJOR:
+	     case I2O_MAJOR:
X 
X 		do {
X 			if (req->sem)
diff -u --recursive --new-file v2.3.5/linux/drivers/block/ns87415.c linux/drivers/block/ns87415.c
--- v2.3.5/linux/drivers/block/ns87415.c	Mon May 31 22:28:05 1999
+++ linux/drivers/block/ns87415.c	Wed Jun  2 22:21:51 1999
@@ -166,13 +166,15 @@
X #endif
X 	}
X 
-	outb(0x60, hwif->dma_base + 2);
+	if (hwif->dma_base)
+		outb(0x60, hwif->dma_base + 2);
X 
X 	if (!using_inta)
X 		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
X 	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
X 		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
X 
-	hwif->dmaproc = &ns87415_dmaproc;
+	if (hwif->dma_base)
+		hwif->dmaproc = &ns87415_dmaproc;
X 	hwif->selectproc = &ns87415_selectproc;
X }
diff -u --recursive --new-file v2.3.5/linux/drivers/block/piix.c linux/drivers/block/piix.c
--- v2.3.5/linux/drivers/block/piix.c	Fri May 14 18:55:14 1999
+++ linux/drivers/block/piix.c	Wed Jun  2 22:21:51 1999
@@ -1,5 +1,5 @@
X /*
- * linux/drivers/block/piix.c	Version 0.22	March 29, 1999
+ * linux/drivers/block/piix.c	Version 0.23	May 29, 1999
X  *
X  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
X  *  Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer
@@ -13,10 +13,10 @@
X  *                 41
X  *                 43
X  *
- * | PIO 0       | c0 | 80 | 0 |
- * | PIO 2 | SW2 | d0 | 90 | 4 |
- * | PIO 3 | MW1 | e1 | a1 | 9 |
- * | PIO 4 | MW2 | e3 | a3 | b |
+ * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
+ * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
+ * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
+ * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
X  * 
X  * sitre = word40 & 0x4000; primary
X  * sitre = word42 & 0x4000; secondary
@@ -58,10 +58,40 @@
X 
X #include "ide_modes.h"
X 
-#define PIIX_DMA_PROC			0
-#define PIIX_DEBUG_SET_XFER		0
X #define PIIX_DEBUG_DRIVE_INFO		0
X 
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/*
+ *
+ */
+static byte piix_dma_2_pio (byte xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
X /*
X  *  Based on settings done by AMI BIOS
X  *  (might be usefull if drive is not registered in CMOS for any reason).
@@ -70,19 +100,22 @@
X {
X 	unsigned long flags;
X 	u16 master_data;
-	byte slave_data, speed;
-	int err;
-	int is_slave = (&HWIF(drive)->drives[1] == drive);
-	int master_port = HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port = 0x44;
-			   /* ISP  RTC */
-	byte timings[][2] = { { 0, 0 },
-			      { 0, 0 },
-			      { 1, 0 },
-			      { 2, 1 },
-			      { 2, 3 }, };
-			      
+	byte slave_data;
+	int is_slave		= (&HWIF(drive)->drives[1] == drive);
+	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+				 /* ISP  RTC */
+	byte timings[][2]	= { { 0, 0 },
+				    { 0, 0 },
+				    { 1, 0 },
+				    { 2, 1 },
+				    { 2, 3 }, };
+
+#if 1
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+#else
X 	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+#endif
X 	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
X 	if (is_slave) {
X 		master_data = master_data | 0x4000;
@@ -107,28 +140,15 @@
X 	if (is_slave)
X 		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
X 	restore_flags(flags);
-
-	switch(pio) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-
-	err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
X }
X 
-extern char *ide_xfer_verbose (byte xfer_rate);
-
X static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra)
X {
X 	struct hd_driveid *id = drive->id;
X 	ide_hwif_t *hwif = HWIF(drive);
X 	struct pci_dev *dev = hwif->pci_dev;
X 
+	unsigned long		flags;
X 	int			sitre;
X 	short			reg4042, reg44, reg48, reg4a;
X 	byte			speed;
@@ -144,23 +164,22 @@
X 	pci_read_config_word(dev, 0x48, ®48);
X 	pci_read_config_word(dev, 0x4a, ®4a);
X 
-#if PIIX_DEBUG_SET_XFER
-	printk("PIIX%s: DMA enable ",
-		(dev->device == PCI_DEVICE_ID_INTEL_82371FB_0) ? "a" :
-		(dev->device == PCI_DEVICE_ID_INTEL_82371FB_1) ? "b" :
-		(dev->device == PCI_DEVICE_ID_INTEL_82371SB_1) ? "3" :
-		(dev->device == PCI_DEVICE_ID_INTEL_82371AB)   ? "4" : " UNKNOWN" );
-#endif /* PIIX_DEBUG_SET_XFER */
+	save_flags(flags);
+	cli();
X 
X 	if (id->dma_ultra && (ultra)) {
X 		if (!(reg48 & u_flag)) {
X 			pci_write_config_word(dev, 0x48, reg48|u_flag);
X 		}
X 	} else {
-		pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg48 & u_flag) {
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		}
X 	}
X 
X 	if ((id->dma_ultra & 0x0004) && (ultra)) {
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
X 		if (!((id->dma_ultra >> 8) & 4)) {
X 			drive->id->dma_ultra &= ~0x0F00;
X 			drive->id->dma_ultra |= 0x0404;
@@ -171,6 +190,8 @@
X 		}
X 		speed = XFER_UDMA_2;
X 	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
X 		if (!((id->dma_ultra >> 8) & 2)) {
X 			drive->id->dma_ultra &= ~0x0F00;
X 			drive->id->dma_ultra |= 0x0202;
@@ -182,6 +203,8 @@
X 		}
X 		speed = XFER_UDMA_1;
X 	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
X 		if (!((id->dma_ultra >> 8) & 1)) {
X 			drive->id->dma_ultra &= ~0x0F00;
X 			drive->id->dma_ultra |= 0x0101;
@@ -193,33 +216,46 @@
X 		}
X 		speed = XFER_UDMA_0;
X 	} else if (id->dma_mword & 0x0004) {
-		drive->id->dma_ultra &= ~0x0F0F;
-		pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		drive->id->dma_ultra &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
X 		if (!((id->dma_mword >> 8) & 4)) {
X 			drive->id->dma_mword &= ~0x0F00;
X 			drive->id->dma_mword |= 0x0404;
X 		}
X 		speed = XFER_MW_DMA_2;
X 	} else if (id->dma_mword & 0x0002) {
-		drive->id->dma_ultra &= ~0x0F0F;
-		pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		drive->id->dma_ultra &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
X 		if (!((id->dma_mword >> 8) & 2)) {
X 			drive->id->dma_mword &= ~0x0F00;
X 			drive->id->dma_mword |= 0x0202;
X 		}
X 		speed = XFER_MW_DMA_1;
X 	} else if (id->dma_1word & 0x0004) {
-		drive->id->dma_ultra &= ~0x0F0F;
-		pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		drive->id->dma_ultra &= ~0x0F00;
+		drive->id->dma_mword &= ~0x0F00;
X 		if (!((id->dma_1word >> 8) & 4)) {
X 			drive->id->dma_1word &= ~0x0F00;
X 			drive->id->dma_1word |= 0x0404;
X 		}
X 		speed = XFER_SW_DMA_2;
X         } else {
-		return ide_dma_off_quietly;
+#if 0
+		speed = XFER_PIO_0;
+#else
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+#endif
X 	}
X 
+	restore_flags(flags);
+	piix_tune_drive(drive, piix_dma_2_pio(speed));
+
X 	(void) ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
X 
X #if PIIX_DEBUG_DRIVE_INFO
@@ -241,7 +277,7 @@
X 	int ultra = (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0;
X 	switch (func) {
X 		case ide_dma_check:
-			return piix_config_drive_for_dma(drive, ultra);
+			 return ide_dmaproc((ide_dma_action_t) piix_config_drive_for_dma(drive, ultra), drive);
X 		default :
X 			break;
X 	}
@@ -252,7 +288,7 @@
X void ide_init_piix (ide_hwif_t *hwif)
X {
X 	hwif->tuneproc = &piix_tune_drive;
-#if PIIX_DMA_PROC
-	hwif->dmaproc = &piix_dmaproc;
-#endif /* PIIX_DMA_PROC */
+	if (hwif->dma_base) {
+		hwif->dmaproc = &piix_dmaproc;
+	}
X }
diff -u --recursive --new-file v2.3.5/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.3.5/linux/drivers/block/rd.c	Mon May 17 09:55:21 1999
+++ linux/drivers/block/rd.c	Fri Jun  4 01:03:28 1999
@@ -627,7 +627,7 @@
X #ifdef CONFIG_BLK_DEV_INITRD
X __initfunc(void initrd_load(void))
X {
-	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0);
+	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0);
X }
X #endif
X 
diff -u --recursive --new-file v2.3.5/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.3.5/linux/drivers/char/adbmouse.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/char/adbmouse.c	Mon Jun  7 12:12:22 1999
@@ -248,7 +248,7 @@
X {
X     mouse.active = 0;
X     mouse.ready = 0;
-    mouse.wait = NULL;
+    init_waitqueue_head(&mouse.wait);
X 
X #ifdef __powerpc__
X     if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
diff -u --recursive --new-file v2.3.5/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.5/linux/drivers/char/bttv.c	Mon May 31 22:28:05 1999
+++ linux/drivers/char/bttv.c	Mon Jun  7 16:17:59 1999
@@ -1,3 +1,4 @@
+
X /* 
X     bttv - Bt848 frame grabber driver
X 
@@ -545,6 +546,8 @@
X         { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
X         /* "Leadtek WinView 601", */
X         { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
+        /* AVEC Intercapture */
+        { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
X };
X #define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
X 
@@ -2900,6 +2903,18 @@
X         I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */
X }
X 
+static void init_tea6320(struct i2c_bus *bus)
+{
+  I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB  */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB  */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB         */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB       */
+  I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */
+}
+
X static void init_tda8425(struct i2c_bus *bus) 
X {
X         I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB  */
@@ -3027,9 +3042,16 @@
X         
X         if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0)
X         {
+          if(btv->type==BTTV_AVEC_INTERCAP)
+            {
+                printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr);
+                btv->audio_chip = TEA6320;
+                init_tea6320(&(btv->i2c));
+            } else {
X 		printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr);
X 		btv->audio_chip = TEA6300;
X 		init_tea6300(&(btv->i2c));
+            }
X         } else
X 		printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr);
X 
@@ -3073,6 +3095,9 @@
X 	        case BTTV_WINVIEW_601:
X 			strcpy(btv->video_dev.name,"BT848(Leadtek WinView 601)");
X  			break;	   
+                case BTTV_AVEC_INTERCAP:
+                        strcpy(btv->video_dev.name,"(AVEC Intercapture)");
+                        break;
X 	}
X 	printk("%s\n",btv->video_dev.name);
X 	audio(btv, AUDIO_MUTE);
diff -u --recursive --new-file v2.3.5/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.3.5/linux/drivers/char/bttv.h	Mon May 31 22:28:05 1999
+++ linux/drivers/char/bttv.h	Mon Jun  7 16:17:59 1999
@@ -211,6 +211,7 @@
X #define BTTV_ZOLTRIX       0x0f
X #define BTTV_PIXVIEWPLAYTV 0x10
X #define BTTV_WINVIEW_601   0x11
+#define BTTV_AVEC_INTERCAP 0x12
X 
X #define AUDIO_TUNER        0x00
X #define AUDIO_RADIO        0x01
@@ -225,6 +226,7 @@
X #define TDA8425            0x02
X #define TDA9840            0x03
X #define TEA6300            0x04
+#define TEA6320            0x05
X 
X #define I2C_TSA5522        0xc2
X #define I2C_TDA9840	   0x84
@@ -233,7 +235,7 @@
X #define I2C_HAUPEE         0xa0
X #define I2C_STBEE          0xae
X #define I2C_VHX 	   0xc0
-#define I2C_TEA6300        0x80
+#define I2C_TEA6300        0x80 /* same as TEA6320 */
X 
X #define TDA9840_SW	   0x00
X #define TDA9840_LVADJ	   0x02
@@ -260,6 +262,22 @@
X #define TEA6300_TR         0x03		/* treble control */
X #define TEA6300_FA         0x04		/* fader control */
X #define TEA6300_SW         0x05		/* mute and source switch */
+
+
+#define TEA6320_V          0x00
+#define TEA6320_FFR        0x01  /* volume front right */
+#define TEA6320_FFL        0x02  /* volume front left */
+#define TEA6320_FRR        0x03  /* volume rear right */
+#define TEA6320_FRL        0x04  /* volume rear left */
+#define TEA6320_BA         0x05  /* bass */
+#define TEA6320_TR         0x06  /* treble */
+#define TEA6320_S          0x07  /* switch register */
+                                 /* values for those registers: */
+#define TEA6320_S_SA       0x01  /* stereo A input */
+#define TEA6320_S_SB       0x02  /* stereo B */
+#define TEA6320_S_SC       0x04  /* stereo C */
+#define TEA6320_S_GMU      0x80  /* general mute */
+
X 
X #define PT2254_L_CHANEL 0x10
X #define PT2254_R_CHANEL 0x08
diff -u --recursive --new-file v2.3.5/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.3.5/linux/drivers/char/misc.c	Fri Mar 26 13:57:41 1999
+++ linux/drivers/char/misc.c	Wed Jun  9 14:44:25 1999
@@ -76,6 +76,7 @@
X extern void dtlk_init(void);
X extern void pcwatchdog_init(void);
X extern int rtc_init(void);
+extern int rtc_sun_init(void);		/* Combines MK48T02 and MK48T08 */
X extern int rtc_DP8570A_init(void);
X extern int rtc_MK48T08_init(void);
X extern int dsp56k_init(void);
@@ -247,7 +248,10 @@
X #ifdef CONFIG_BVME6000
X 	rtc_DP8570A_init();
X #endif
-#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
+#if defined(CONFIG_SUN_MOSTEK_RTC)
+	rtc_sun_init();
+#endif
+#if defined(CONFIG_RTC)
X 	rtc_init();
X #endif
X #ifdef CONFIG_ATARI_DSP56K
diff -u --recursive --new-file v2.3.5/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c
--- v2.3.5/linux/drivers/char/radio-cadet.c	Fri May 14 18:55:17 1999
+++ linux/drivers/char/radio-cadet.c	Mon Jun  7 16:17:59 1999
@@ -1,7 +1,7 @@
X /* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card 
X  *
X  * by Fred Gleason <fr...@wava.com>
- * Version 0.3.1
+ * Version 0.3.2
X  *
X  * (Loosely) based on code for the Aztech radio card by
X  *
@@ -557,7 +557,7 @@
X 		return -EINVAL;
X 		
X 	request_region(io,2,"cadet");
-	printk(KERN_INFO "ADS Cadet Radio Card at %x\n",io);
+	printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
X 	return 0;
X }
X 
@@ -570,12 +570,11 @@
X 
X 	for(i=0;i<8;i++) {
X 	        io=iovals[i];
-	        if(check_region(io,2)) {
-	                return -1;
-		}  
-		cadet_setfreq(1410);
-		if(cadet_getfreq()==1410) {
-		        return io;
+	        if(check_region(io,2)>=0) {
+		        cadet_setfreq(1410);
+			if(cadet_getfreq()==1410) {
+			        return io;
+			}
X 		}
X 	}
X 	return -1;
diff -u --recursive --new-file v2.3.5/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.3.5/linux/drivers/char/rtc.c	Fri May 14 18:55:17 1999
+++ linux/drivers/char/rtc.c	Wed Jun  9 14:44:25 1999
@@ -32,10 +32,11 @@
X  *	1.08	Miquel van Smoorenburg: disallow certain things on the
X  *		DEC Alpha as the CMOS clock is also used for other things.
X  *	1.09	Nikita Schmidt: epoch support and some Alpha cleanup.
+ *	1.09a	Pete Zaitcev: Sun SPARC
X  *
X  */
X 
-#define RTC_VERSION		"1.09"
+#define RTC_VERSION		"1.09a"
X 
X #define RTC_IRQ 	8	/* Can't see this changing soon.	*/
X #define RTC_IO_EXTENT	0x10	/* Only really two ports, but...	*/
@@ -62,6 +63,12 @@
X #include <asm/uaccess.h>
X #include <asm/system.h>
X 
+#ifdef __sparc__
+#include <asm/ebus.h>
+
+static unsigned long rtc_port;
+#endif
+
X /*
X  *	We sponge a minor off of the misc major. No need slurping
X  *	up another valuable major dev number for this. If you add
@@ -83,12 +90,12 @@
X 
X static unsigned int rtc_poll(struct file *file, poll_table *wait);
X 
-void get_rtc_time (struct rtc_time *rtc_tm);
-void get_rtc_alm_time (struct rtc_time *alm_tm);
-void rtc_dropped_irq(unsigned long data);
+static void get_rtc_time (struct rtc_time *rtc_tm);
+static void get_rtc_alm_time (struct rtc_time *alm_tm);
+static void rtc_dropped_irq(unsigned long data);
X 
-void set_rtc_irq_bit(unsigned char bit);
-void mask_rtc_irq_bit(unsigned char bit);
+static void set_rtc_irq_bit(unsigned char bit);
+static void mask_rtc_irq_bit(unsigned char bit);
X 
X static inline unsigned char rtc_is_updating(void);
X 
@@ -525,7 +532,42 @@
X 	unsigned long uip_watchdog;
X 	char *guess = NULL;
X #endif
+#ifdef __sparc__
+	struct linux_ebus *ebus;
+	struct linux_ebus_device *edev;
+	int rtc_irq;
+#endif
+
X 	printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
+#ifdef __sparc__
+	for_each_ebus(ebus) {
+		for_each_ebusdev(edev, ebus) {
+			if(strcmp(edev->prom_name, "rtc") == 0) {
+				goto found;
+			}
+		}
+	}
+	printk("rtc_init: no PC rtc found\n");
+	return -EIO;
+
+found:
+	rtc_port = edev->base_address[0];
+	rtc_irq = edev->irqs[0];
+	/*
+	 * XXX Interrupt pin #7 in Espresso is shared between RTC and
+	 * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here
+	 * is asking for trouble with add-on boards. Change to SA_SHIRQ.
+	 */
+	if(request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) {
+		/*
+		 * Standard way for sparc to print irq's is to use
+		 * __irq_itoa(). I think for EBus it's ok to use %d.
+		 */
+		printk("rtc: cannot register IRQ %d\n", rtc_irq);
+		return -EIO;
+	}
+	misc_register(&rtc_dev);
+#else
X 	if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
X 	{
X 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
@@ -535,6 +577,7 @@
X 	misc_register(&rtc_dev);
X 	/* Check region? Naaah! Just snarf it up. */
X 	request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+#endif /* __sparc__ vs. others */
X #ifdef __alpha__
X 	rtc_freq = HZ;
X 	
@@ -588,7 +631,7 @@
X  *	for something that requires a steady > 1KHz signal anyways.)
X  */
X 
-void rtc_dropped_irq(unsigned long data)
+static void rtc_dropped_irq(unsigned long data)
X {
X 	unsigned long flags;
X 
@@ -696,7 +739,7 @@
X 	return uip;
X }
X 
-void get_rtc_time(struct rtc_time *rtc_tm)
+static void get_rtc_time(struct rtc_time *rtc_tm)
X {
X 
X 	unsigned long flags, uip_watchdog = jiffies;
@@ -753,7 +796,7 @@
X 	rtc_tm->tm_mon--;
X }
X 
-void get_rtc_alm_time(struct rtc_time *alm_tm)
+static void get_rtc_alm_time(struct rtc_time *alm_tm)
X {
X 	unsigned long flags;
X 	unsigned char ctrl;
@@ -803,7 +846,7 @@
X 	rtc_irq_data = 0;
X }
X 
-void set_rtc_irq_bit(unsigned char bit)
+static void set_rtc_irq_bit(unsigned char bit)
X {
X 	unsigned char val;
X 	unsigned long flags;
diff -u --recursive --new-file v2.3.5/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
--- v2.3.5/linux/drivers/char/tuner.c	Sun Jan 17 18:28:06 1999
+++ linux/drivers/char/tuner.c	Mon Jun  7 16:17:59 1999
@@ -84,7 +84,9 @@
X 	      //  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
X 	        16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623},
X 	{"Temic 4036 FY5 NTSC", TEMIC, NTSC,
-		16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+	        16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+        {"Alps HSBH1", TEMIC, NTSC,
+                16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
X };
X 
X /* ---------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.5/linux/drivers/char/tuner.h linux/drivers/char/tuner.h
--- v2.3.5/linux/drivers/char/tuner.h	Sun Nov  8 14:36:46 1998
+++ linux/drivers/char/tuner.h	Mon Jun  7 16:17:59 1999
@@ -31,6 +31,7 @@
X #define TUNER_TEMIC_NTSC    6
X #define TUNER_TEMIC_PAL_I   7
X #define TUNER_TEMIC_4036FY5_NTSC	8
+#define TUNER_ALPS_TSBH1_NTSC 9
X 
X #define NOTUNER 0
X #define PAL     1
diff -u --recursive --new-file v2.3.5/linux/drivers/i2o/Config.in linux/drivers/i2o/Config.in
--- v2.3.5/linux/drivers/i2o/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/Config.in	Wed Jun  2 14:47:42 1999
@@ -0,0 +1,12 @@
+mainmenu_option next_comment
+comment 'I2O device support'
+
+tristate 'I2O support' CONFIG_I2O
+
+dep_tristate 'I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
+dep_tristate 'I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O
+dep_tristate 'I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
+dep_tristate 'I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O
+dep_tristate 'I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O
+
+endmenu
diff -u --recursive --new-file v2.3.5/linux/drivers/i2o/Makefile linux/drivers/i2o/Makefile
--- v2.3.5/linux/drivers/i2o/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/Makefile	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,75 @@
+#
+# Makefile for the kernel I2O OSM.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+#
+# Note : at this point, these files are compiled on all systems.
+# In the future, some of these should be built conditionally.
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+
+L_TARGET := i2o.a
+L_OBJS   := 
+M_OBJS   :=
+
+ifeq ($(CONFIG_I2O_PCI),y)
+L_OBJS += i2o_pci.o
+else
+  ifeq ($(CONFIG_I2O_PCI),m)
+  M_OBJS += i2o_pci.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O),y)
+LX_OBJS += i2o_core.o i2o_config.o
+else
+  ifeq ($(CONFIG_I2O),m)
+  MX_OBJS += i2o_core.o i2o_config.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O_BLOCK),y)
+LX_OBJS += i2o_block.o
+else
+  ifeq ($(CONFIG_I2O_BLOCK),m)
+  MX_OBJS += i2o_block.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O_LAN),y)
+LX_OBJS += i2o_lan.o
+else
+  ifeq ($(CONFIG_I2O_LAN),m)
+  MX_OBJS += i2o_lan.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O_SCSI),y)
+LX_OBJS += i2o_scsi.o
+else
+  ifeq ($(CONFIG_I2O_SCSI),m)
+  MX_OBJS += i2o_scsi.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O_PROC),y)
+LX_OBJS += i2o_proc.o
+else
+  ifeq ($(CONFIG_I2O_PROC),m)
+  MX_OBJS += i2o_proc.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.3.5/linux/drivers/i2o/README linux/drivers/i2o/README
--- v2.3.5/linux/drivers/i2o/README	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/README	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,78 @@
+
+	Linux I2O Support	(c) Copyright 1999 Red Hat Software
+					and others.
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version
+	2 of the License, or (at your option) any later version.
+
+AUTHORS (so far)
+
+Alan Cox, 	Building Number Three Ltd.
+	Core code, SCSI and Block OSMs
+
+Steve Ralston,	LSI Logic Corp.
+	Debugging SCSI and Block OSM
+
+Deepak Saxena,	Intel Corp.
+	/proc interface, bug fixes
+	Ioctl interfaces for control
+
+Philip Rumpf
+	Fixed assorted dumb SMP locking bugs
+
+Juha Sievanen,  University Of Helsinki Finland
+	LAN OSM
+	Bug fixes
+	Core code extensions
+
+CREDITS
+
+	This work was made possible by 
+
+Red Hat Software
+	Funding for the Building #3 part of the project
+
+Symbios Logic (Now LSI)
+	Host adapters, hints, known to work platforms when I hit
+	compatibility problems
+
+BoxHill Corporation
+	Loan of initial FibreChannel disk array used for development work.
+
+STATUS:
+
+o	The core setup works within limits.
+o	The scsi layer seems to almost work. I'm still chasing down the hang
+	bug.
+o	The block OSM is fairly minimal but does seem to work.
+
+
+TO DO:
+
+General:
+o	Support multiple IOP's and tell them about each other
+o	Provide hidden address space if asked
+o	Long term message flow control
+o	PCI IOP's without interrupts are not supported yet
+o	Push FAIL handling into the core
+o	DDM control interfaces for module load etc
+
+Block:
+o	Real error handler
+o	Multiple major numbers
+o	Read ahead and cache handling stuff. Talk to Ingo and people
+o	Power management
+o	Finish Media changers
+
+SCSI:
+o	Find the right way to associate drives/luns/busses
+
+Net:
+o	Port the existing RCPCI work to the frame work or write a new
+	driver. This one is with the Finns
+
+Tape:
+o	Anyone seen anything implementing this ?
+
diff -u --recursive --new-file v2.3.5/linux/drivers/i2o/README.ioctl linux/drivers/i2o/README.ioctl
--- v2.3.5/linux/drivers/i2o/README.ioctl	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/README.ioctl	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,398 @@
+
+Linux I2O User Space Interface
+rev 0.3 - 04/20/99
+
+=============================================================================
+Originally written by Deepak Saxena(deepak...@intel.com)
+Currently maintained by Deepak Saxena(deepak...@intel.com)
+=============================================================================
+
+I. Introduction
+
+The Linux I2O susbsytem provides a set of ioctl() commands than can be
+utilized by user space applications to communicate with IOPs and devices
+on individual IOPs. This document defines the specific ioctl() commands
+that are available to the user and provides examples of their uses.
+
+This document assumes the reader is familiar with or has access to the 
+I2O specification as no I2O message parameters are outlined.  For information 
+on the specification, see http://www.i2osig.org
+
+This document and the I2O user space interface are currently maintained
+by Deepak Saxena.  Please send all comments, errata, and bug fixes to
+deepak...@intel.com
+
+II. IOP Access
+
+Access to the I2O subsystem is provided through the device file named 
+/dev/i2octl.  This file is a character file with major number 10 and minor
+number 166.  It can be created through the following command:
+
+   mknod /dev/i2octl c 10 166
+
+III. Determining the IOP Count
+
+   SYNOPSIS 
+
+   ioctl(fd, I2OGETIOPS,  int *count);
+
+   u8 count[MAX_I2O_CONTROLLERS];
+
+   DESCRIPTION
+
+   This function returns the system's active IOP table.  count should
+   point to a buffer containing MAX_I2O_CONTROLLERS entries.  Upon 
+   returning, each entry will contain a non-zero value if the given
+   IOP unit is active, and NULL if it is inactive or non-existent.
+
+   RETURN VALUE.
+
+   Returns 0 if no errors occur, and -1 otherwise.  If an error occurs,
+   errno is set appropriately:
+
+      EIO      Unkown error
+
+IV. ExecHrtGet Message
+
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts an ExecHrtHet message to the IOP specified by
+   hrt->iop and returns the data in the buffer pointed to by hrt->buf
+   The size of the data written is placed into the memory pointed to
+   by hrt->len.
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriately:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(hrt->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+  
+V. ExecLctNotify Message
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts an ExecLctGet message to the IOP specified by 
+   lct->iop and returns the data in the buffer pointed to by lct->buf
+   The size of the data written is placed into the memory pointed to
+   by lct->reslen.
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriately:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(lct->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+
+VI. UtilParamsSet Message
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops);
+
+      struct i2o_cmd_psetget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsSet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is 
+   sent through the ops->oplen buffer, and the result list is written
+   into the buffer pointed to by ops->oplen.  The number of bytes 
+   written is placed into *(ops->reslen). 
+
+   RETURNS
+
+   The return value is the size in bytes of the data written into
+   ops->resbuf if no errors occur.  If an error occurs, -1 is returned 
+   and errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+
+   A return value of 0 does not mean that the value was actually
+   changed properly on the IOP.  The user should check the result
+   list to determine the specific status of the transaction.
+
+VII. UtilParamsGet Message
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops);
+
+      struct i2o_parm_setget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsGet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is 
+   sent through the ops->oplen buffer, and the result list is written
+   into the buffer pointed to by ops->oplen.  The actual size of data
+   written is placed into *(ops->reslen).
+
+   RETURNS
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+
+   A return value of 0 does not mean that the value was actually
+   properly retreived.  The user should check the result list 
+   to determine the specific status of the transaction.
+
+VIII. ExecSwDownload Message
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;       /* IOP unit number */
+         u8    dl_flags;  /* DownLoadFlags field */
+         u8    sw_type;   /* Software type */
+         u32   sw_id;     /* Software ID */
+         void  *buf;      /* Pointer to software buffer */
+         u32   *swlen;    /* Length of software data */        
+         u32   *maxfrag;  /* Number of fragments */
+         u32   *curfrag;  /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function downloads the software pointed to by  sw->buf to the
+   iop identified by sw->iop. The DownloadFlags, SwID, and SwType fields
+   of the ExecSwDownload message are filed in with the values of 
+   sw->dl_flags, sw->sw_id, and sw->sw_type.
+
+   Once the ioctl() is called and software transfer begins, the 
+   user can read the value *(sw->maxfrag) and *(sw->curfrag) to
+   determine the status of the software transfer. As the IOP
+   is very slow when it comes to SW transfers, this can be
+   used by a separate thread to report status to the user. The
+   user _should not_ write to this memory location until the ioctl()
+   has returned.
+
+   RETURNS
+
+   This function returns 0 no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+
+IX. ExecSwUpload Message
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags;    /* Unused */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Pointer to software buffer */
+         u32   *swlen;   /* Length in bytes of software */        
+         u32   *maxfrag; /* Number of fragments */
+         u32   *curfrag; /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function uploads software from the IOP identified by sw->iop
+   and places it in the buffer pointed to by sw->buf.  The SwID, SwType
+   and SwSize fields of the ExecSwDownload message are filed in 
+   with the values of sw->sw_id, sw->sw_type, sw->swlen, and.  The 
+   actual size of the module is written into *(sw->buflen).
+
+   Once the ioctl() is called and software transfer begins, the 
+   user can read the value *(sw->maxfrag) and *(sw->curfrag) to
+   determine the status of the software transfer.  As the IOP
+   is very slow when it comes to SW transfers, this can be
+   used by a separate thread to report status to the user. The
+   user _should not_ write to this memory location until the ioctl()
+   has returned.
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+         
+X. ExecSwRemove Message
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags;    /* Unused */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Unused */
+         u32   *swlen;   /* Length in bytes of software data */        
+         u32   *maxfrag; /* Unused */
+         u32   *curfrag; /* Unused */
+      };
+
+   DESCRIPTION
+
+   This function uploads software from the IOP identified by sw->iop
+   and places it in the buffer pointed to by sw->buf.  The SwID, SwType
+   and SwSize fields of the ExecSwDownload message are filed in 
+   with the values of sw->dl_flags, sw->sw_id, and sw->sw_type.  The 
+   actual size of the module is written into *(sw->buflen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+
+X. UtilConfigDialog Message
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OHTML, struct i2o_html *htquery);
+
+      struct i2o_html
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device ID */
+         u32   page;     /* HTML page */
+         void  *resbuf;  /* Buffer for reply HTML page */
+         u32   *reslen;  /* Length in bytes of reply buffer */
+         void  *qbuf;    /* Pointer to HTTP query string */
+         u32   qlen;     /* Length in bytes of query string buffer */        
+      };
+
+   DESCRIPTION
+
+   This function posts an UtilConfigDialog message to the device identified
+   by htquery->iop and htquery->tid.  The requested HTML page number is 
+   provided by the htquery->page field, and the resultant data is stored 
+   in the buffer pointed to by htquery->resbuf.  If there is an HTTP query 
+   string that is to be sent to the device, it should be sent in the buffer
+   pointed to by htquery->qbuf.  If there is no query string, this field
+   should be set to NULL. The actual size of the reply received is written
+   into *(htquery->reslen)
+  
+   RETURNS
+
+   This function returns 0 if no error occur. If an error occurs, -1
+   is returned and J errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      EIO         Unkown error
+
+XI. Events
+
+    In the process of determining this.  Current idea is to have use
+    the select() interface to allow user apps to periodically poll
+    the /dev/i2octl device for events.  When select() notifies the user
+    that an event is available, the user would call read() to retrieve
+    a list of all the events that are pending for the specific device.
+
+=============================================================================
+Revision History
+=============================================================================
+
+Rev 0.1 - 04/01/99
+- Initial revision
+
+Rev 0.2 - 04/06/99
+- Changed return values to match UNIX ioctl() standard.  Only return values
+  are 0 and -1.  All errors are reported through errno.
+- Added summary of proposed possible event interfaces
+
+Rev 0.3 - 04/20/99
+- Changed all ioctls() to use pointers to user data instead of actual data
+- Updated error values to match the code
+
+
diff -u --recursive --new-file v2.3.5/linux/drivers/i2o/README.lan linux/drivers/i2o/README.lan
--- v2.3.5/linux/drivers/i2o/README.lan	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/README.lan	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,38 @@
+
+	Linux I2O LAN OSM
+	(c) University of Helsinki, Department of Computer Science
+
+	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.
+
+AUTHORS
+Auvo Häkkinen, Auvo.H...@cs.Helsinki.FI
+Juha Sievänen, Juha.S...@cs.Helsinki.FI
+
+CREDITS
+
+	This work was made possible by 
+
+European Committee
+	Funding for the project
+
+SysKonnect
+	Loaning of FDDI cards
+
+ASUSTeK
+	I2O motherboard
+
+STATUS:
+o	The FDDI part of LAN OSM is working to some extent.
+o	Only packet per bucket is now supported.
+
+TO DO:
+
+LAN:
+o	Add support for bactches
+o	Find why big packets flow from I2O box out, but don't want to come in
+o	Find the bug in i2o_set_multicast_list(), which kills interrupt
+	handler in i2o_wait_reply()
+o	Add support for Ethernet, Token Ring, AnyLAN, Fibre Channel
diff -u --recursive --new-file v2.3.5/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.3.5/linux/drivers/i2o/i2o_block.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/i2o_block.c	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,1071 @@
+/*
+ *	I2O block device driver. 
+ *
+ *	(C) Copyright 1999   Red Hat Software
+ *	
+ *	Written by Alan Cox, Building Number Three Ltd
+ *
+ *	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 is an initial test release. Most of the good code was taken
+ *	from the nbd driver by Pavel Machek, who in turn took some of it
+ *	from loop.c. Isn't free software great for reusability 8)
+ *
+ *	Fixes:
+ *		Steve Ralston:	Multiple device handling error fixes,
+ *				Added a queue depth.
+ */
+
+#include <linux/major.h>
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ioctl.h>
+#include <linux/i2o.h>
+#include <linux/blkdev.h>
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+
+#define MAJOR_NR I2O_MAJOR
+
+#include <linux/blk.h>
+
+#define MAX_I2OB	16
+
+#define MAX_I2OB_DEPTH	4
+
+/*
+ *	Some of these can be made smaller later
+ */
+
+static int i2ob_blksizes[MAX_I2OB<<4];
+static int i2ob_hardsizes[MAX_I2OB<<4];
+static int i2ob_sizes[MAX_I2OB<<4];
+static int i2ob_media_change_flag[MAX_I2OB];
+static u32 i2ob_max_sectors[MAX_I2OB<<4];
+
+static int i2ob_context;
+
+#ifdef __SMP__
+static spinlock_t i2ob_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+struct i2ob_device
+{
+	struct i2o_controller *controller;
+	struct i2o_device *i2odev;
+	int tid;
+	int flags;
+	int refcnt;
+	struct request *head, *tail;
+	int done_flag;
+};
+
+/*
+ *	Each I2O disk is one of these.
+ */
+
+static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
+static int i2ob_devices = 0;
+static struct hd_struct i2ob[MAX_I2OB<<4];
+static struct gendisk i2ob_gendisk;	/* Declared later */
+
+static atomic_t queue_depth;		/* For flow control later on */
+
+#define DEBUG( s )
+/* #define DEBUG( s ) printk( s ) 
+ */
+
+static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
+static void i2ob_end_request(struct request *);
+static void do_i2ob_request(void);
+
+/*
+ *	Get a message
+ */
+
+static u32 i2ob_get(struct i2ob_device *dev)
+{ 
+	struct i2o_controller *c=dev->controller;
+	return I2O_POST_READ32(c);
+}
+ 
+/*
+ *	Turn a Linux block request into an I2O block read/write.
+ */
+
+static int i2ob_send(u32 m, struct i2ob_device *dev, struct request *req, u32 base, int unit)
+{
+	struct i2o_controller *c = dev->controller;
+	int tid = dev->tid;
+	u32 *msg;
+	u32 *mptr;
+	u64 offset;
+	struct buffer_head *bh = req->bh;
+	static int old_qd = 2;
+	int count = req->nr_sectors<<9;
+	
+	/*
+	 *	Build a message
+	 */
+	
+	msg = bus_to_virt(c->mem_offset + m);
+	
+	msg[2] = i2ob_context|(unit<<8);
+	msg[3] = (u32)req;	/* 64bit issue again here */
+	msg[5] = req->nr_sectors << 9;
+	
+	/* This can be optimised later - just want to be sure its right for
+	   starters */
+	offset = ((u64)(req->sector+base)) << 9;
+	msg[6] = offset & 0xFFFFFFFF;
+	msg[7] = (offset>>32);
+	mptr=msg+8;
+	
+	if(req->cmd == READ)
+	{
+		msg[1] = I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid;
+		/* We don't yet do cache/readahead and other magic */
+		msg[4] = 1<<16;	
+		while(bh!=NULL)
+		{
+			*mptr++ = 0x10000000|(bh->b_size);
+			*mptr++ = virt_to_bus(bh->b_data);
+			count -= bh->b_size;
+			bh = bh->b_reqnext;
+		}
+	}
+	else if(req->cmd == WRITE)
+	{
+		msg[1] = I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid;
+		msg[4] = 1<<16;
+		while(bh!=NULL)
+		{
+			*mptr++ = 0x14000000|(bh->b_size);
+			count -= bh->b_size;
+			*mptr++ = virt_to_bus(bh->b_data);
+			bh = bh->b_reqnext;
+		}
+	}
+	mptr[-2]|= 0xC0000000;
+	msg[0] = I2O_MESSAGE_SIZE(mptr-msg) | SGL_OFFSET_8;
+	
+	if(req->current_nr_sectors > 8)
+		printk("Gathered sectors %ld.\n", 
+			req->current_nr_sectors);
+			
+	if(count != 0)
+	{
+		printk("Request count botched by %d.\n", count);
+		msg[5] -= count;
+	}
+
+//	printk("Send for %p\n", req);
+
+	i2o_post_message(c,m);
+	atomic_inc(&queue_depth);
+	if(atomic_read(&queue_depth)>old_qd)
+	{
+		old_qd=atomic_read(&queue_depth);
+		printk("Depth now %d.\n", old_qd);
+	}
+	return 0;
+}
+
+/*
+ *	Remove a request from the _locked_ request list. We update both the
+ *	list chain and if this is the last item the tail pointer.
+ */
+ 
+static void i2ob_unhook_request(struct i2ob_device *dev, struct request *req)
+{
+	struct request **p = &dev->head;
+	struct request *nt = NULL;
+	static int crap = 0;
+	
+	while(*p!=NULL)
+	{
+		if(*p==req)
+		{
+			if(dev->tail==req)
+				dev->tail = nt;
+			*p=req->next;
+			return;
+		}
+		nt=*p;
+		p=&(nt->next);
+	}
+	if(!crap++)
+		printk("i2o_block: request queue corrupt!\n");
+}
+
+/*
+ *	Request completion handler
+ */
+ 
+static void i2ob_end_request(struct request *req)
+{
+	/*
+	 * Loop until all of the buffers that are linked
+	 * to this request have been marked updated and
+	 * unlocked.
+	 */
+	while (end_that_request_first( req, !req->errors, "i2o block" ));
+
+	/*
+	 * It is now ok to complete the request.
+	 */
+	end_that_request_last( req );
+}
+
+
+/*
+ *	OSM reply handler. This gets all the message replies
+ */
+
+static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
+{
+	struct request *req;
+	u8 st;
+	u32 *m = (u32 *)msg;
+	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
+	
+	if(m[0] & (1<<13))
+	{
+		printk("IOP fail.\n");
+		printk("From %d To %d Cmd %d.\n",
+			(m[1]>>12)&0xFFF,
+			m[1]&0xFFF,
+			m[1]>>24);
+		printk("Failure Code %d.\n", m[4]>>24);
+		if(m[4]&(1<<16))
+			printk("Format error.\n");
+		if(m[4]&(1<<17))
+			printk("Path error.\n");
+		if(m[4]&(1<<18))
+			printk("Path State.\n");
+		if(m[4]&(1<<18))
+			printk("Congestion.\n");
+		
+		m=(u32 *)bus_to_virt(m[7]);
+		printk("Failing message is %p.\n", m);
+		
+		/* We need to up the request failure count here and maybe
+		   abort it */
+		req=(struct request *)m[3];
+		/* Now flush the message by making it a NOP */
+		m[0]&=0x00FFFFFF;
+		m[0]|=(I2O_CMD_UTIL_NOP)<<24;
+		i2o_post_message(c,virt_to_bus(m));
+		
+	}
+	else
+	{
+		if(m[2]&0x80000000)
+		{
+			int * ptr = (int *)m[3];
+			if(m[4]>>24)
+				*ptr = -1;
+			else
+				*ptr = 1;
+			return;
+		}
+		/*
+		 *	Lets see what is cooking. We stuffed the
+		 *	request in the context.
+		 */
+		 
+		req=(struct request *)m[3];
+		st=m[4]>>24;
+	
+		if(st!=0)
+		{
+			printk(KERN_ERR "i2ob: error %08X\n", m[4]);
+			/*
+			 *	Now error out the request block
+			 */
+			req->errors++;	
+		}
+	}
+	/*
+	 *	Dequeue the request.
+	 */
+	
+	spin_lock(&io_request_lock);
+	spin_lock(&i2ob_lock);
+	i2ob_unhook_request(&i2ob_dev[unit], req);
+	i2ob_end_request(req);
+	
+	/*
+	 *	We may be able to do more I/O
+	 */
+	 
+	atomic_dec(&queue_depth);
+	do_i2ob_request();
+	spin_unlock(&i2ob_lock);
+	spin_unlock(&io_request_lock);
+}
+
+static struct i2o_handler i2o_block_handler =
+{
+	i2o_block_reply,
+	"I2O Block OSM",
+	0
+};
+
+
+/*
+ *	Flush all pending requests as errors. Must call with the queue
+ *	locked.
+ */
+ 
+#if 0
+static void i2ob_clear_queue(struct i2ob_device *dev)
+{
+	struct request *req;
+
+	while (1) {
+		req = dev->tail;
+		if (!req)
+			return;
+		req->errors++;
+		i2ob_end_request(req);
+
+		if (dev->tail == dev->head)
+			dev->head = NULL;
+		dev->tail = dev->tail->next;
+	}
+}
+#endif
+
+/*
+ *	The I2O block driver is listed as one of those that pulls the
+ *	front entry off the queue before processing it. This is important
+ *	to remember here. If we drop the io lock then CURRENT will change
+ *	on us. We must unlink CURRENT in this routine before we return, if
+ *	we use it.
+ */
+
+static void do_i2ob_request(void)
+{
+	struct request *req;
+	int unit;
+	struct i2ob_device *dev;
+	u32 m;
+
+	while (CURRENT) {
+		/*
+		 *	On an IRQ completion if there is an inactive
+		 *	request on the queue head it means it isnt yet
+		 *	ready to dispatch.
+		 */
+		if(CURRENT->rq_status == RQ_INACTIVE)
+			return;
+			
+		/*
+		 *	Queue depths probably belong with some kind of
+		 *	generic IOP commit control. Certainly its not right
+		 *	its global!
+		 */
+		if(atomic_read(&queue_depth)>=MAX_I2OB_DEPTH)
+			break;
+
+		req = CURRENT;
+		unit = MINOR(req->rq_dev);
+		dev = &i2ob_dev[(unit&0xF0)];
+		/* Get a message */
+		m = i2ob_get(dev);
+		/* No messages -> punt 
+		   FIXME: if we have no messages, and there are no messages 
+		   we deadlock now. Need a timer/callback ?? */
+		if(m==0xFFFFFFFF)
+		{
+			printk("i2ob: no messages!\n");
+			break;
+		}
+		req->errors = 0;
+		CURRENT = CURRENT->next;
+		req->next = NULL;
+
+		if (dev->head == NULL) {
+			dev->head = req;
+			dev->tail = req;
+		} else {
+			dev->tail->next = req;
+			dev->tail = req;
+		}
+		i2ob_send(m, dev, req, i2ob[unit].start_sect, (unit&0xF0));
+	}
+}
+
+static void i2ob_request(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&i2ob_lock, flags);
+	do_i2ob_request();
+	spin_unlock_irqrestore(&i2ob_lock, flags);
+}	
+
+/*
+ *	SCSI-CAM for ioctl geometry mapping
+ *	Duplicated with SCSI - this should be moved into somewhere common
+ *	perhaps genhd ?
+ */
+ 
+static void i2o_block_biosparam(
+	unsigned long capacity,
+	unsigned short *cyls,
+	unsigned char *hds,
+	unsigned char *secs) 
+{ 
+	unsigned long heads, sectors, cylinders, temp; 
+
+	cylinders = 1024L;			/* Set number of cylinders to max */ 
+	sectors = 62L;      			/* Maximize sectors per track */ 
+
+	temp = cylinders * sectors;		/* Compute divisor for heads */ 
+	heads = capacity / temp;		/* Compute value for number of heads */
+	if (capacity % temp) {			/* If no remainder, done! */ 
+    		heads++;                	/* Else, increment number of heads */ 
+    		temp = cylinders * heads;	/* Compute divisor for sectors */ 
+    		sectors = capacity / temp;	/* Compute value for sectors per
+						       track */ 
+	    	if (capacity % temp) {		/* If no remainder, done! */ 
+			sectors++;                  /* Else, increment number of sectors */ 
+	      		temp = heads * sectors;	/* Compute divisor for cylinders */
+	      		cylinders = capacity / temp;/* Compute number of cylinders */ 
+		} 
+	} 
+	/* if something went wrong, then apparently we have to return
+	   a geometry with more than 1024 cylinders */
+	if (cylinders == 0 || heads > 255 || sectors > 63 || cylinders >1023) 
+	{
+		unsigned long temp_cyl;
+		
+		heads = 64;
+		sectors = 32;
+		temp_cyl = capacity / (heads * sectors);
+		if (temp_cyl > 1024) 
+		{
+			heads = 255;
+			sectors = 63;
+		}
+		cylinders = capacity / (heads * sectors);
+	}
+	*cyls = (unsigned int) cylinders;	/* Stuff return values */ 
+	*secs = (unsigned int) sectors; 
+	*hds  = (unsigned int) heads; 
+} 
+
+/*
+ *	Rescan the partition tables
+ */
+ 
+static int do_i2ob_revalidate(kdev_t dev, int maxu)
+{
+	int minor=MINOR(dev);
+	int i;
+	
+	minor&=0xF0;
+	
+	i2ob_dev[minor].refcnt++;
+	if(i2ob_dev[minor].refcnt>maxu+1)
+	{
+		i2ob_dev[minor].refcnt--;
+		return -EBUSY;
+	}
+	
+	for( i = 15; i>=0 ; i--)
+	{
+		int m = minor+i;
+		kdev_t d = MKDEV(MAJOR_NR, m);
+		struct super_block *sb = get_super(d);
+		
+		sync_dev(d);
+		if(sb)
+			invalidate_inodes(sb);
+		invalidate_buffers(d);
+		i2ob_gendisk.part[m].start_sect = 0;
+		i2ob_gendisk.part[m].nr_sects = 0;
+	}
+
+	/*
+	 *	Do a physical check and then reconfigure
+	 */
+	 
+	i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev,
+		minor);
+	i2ob_dev[minor].refcnt--;
+	return 0;
+}
+
+/*
+ *	Issue device specific ioctl calls.
+ */
+
+static int i2ob_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct i2ob_device *dev;
+	int minor;
+
+	/* Anyone capable of this syscall can do *real bad* things */
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!inode)
+		return -EINVAL;
+	minor = MINOR(inode->i_rdev);
+	if (minor >= (MAX_I2OB<<4))
+		return -ENODEV;
+
+	dev = &i2ob_dev[minor];
+	switch (cmd) {
+		case BLKRASET:
+			if(!capable(CAP_SYS_ADMIN))  return -EACCES;
+			if(arg > 0xff) return -EINVAL;
+			read_ahead[MAJOR(inode->i_rdev)] = arg;
+			return 0;
+
+		case BLKRAGET:
+			if (!arg)  return -EINVAL;
+			return put_user(read_ahead[MAJOR(inode->i_rdev)],
+					(long *) arg); 
+		case BLKGETSIZE:
+			return put_user(i2ob[minor].nr_sects, (long *) arg);
+
+		case BLKFLSBUF:
+			if(!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
+			fsync_dev(inode->i_rdev);
+			invalidate_buffers(inode->i_rdev);
+			return 0;
+			
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g;
+			int u=minor&0xF0;
+			i2o_block_biosparam(i2ob_sizes[u]<<1, 
+				&g.cylinders, &g.heads, &g.sectors);
+			g.start = i2ob[minor].start_sect;
+			return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0;
+		}
+	
+		case BLKRRPART:
+			if(!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			return do_i2ob_revalidate(inode->i_rdev,1);
+			
+		default:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+	}
+}
+
+/*
+ *	Issue UTIL_CLAIM messages
+ */
+ 
+static int i2ob_claim_device(struct i2ob_device *dev, int onoff)
+{
+	return i2o_issue_claim(dev->controller, dev->tid, i2ob_context, onoff, &dev->done_flag);
+}
+
+/*
+ *	Close the block device down
+ */
+ 
+static int i2ob_release(struct inode *inode, struct file *file)
+{
+	struct i2ob_device *dev;
+	int minor;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor >= (MAX_I2OB<<4))
+		return -ENODEV;
+	sync_dev(inode->i_rdev);
+	dev = &i2ob_dev[(minor&0xF0)];
+	if (dev->refcnt <= 0)
+		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
+	dev->refcnt--;
+	if(dev->refcnt==0)
+	{
+		/*
+		 *	Flush the onboard cache on unmount
+		 */
+		u32 msg[5];
+		int *query_done = &dev->done_flag;
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x80000000;
+		msg[3] = (u32)query_done;
+		msg[4] = 60<<16;
+		i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2);
+		/*
+		 *	Unlock the media
+		 */
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x80000000;
+		msg[3] = (u32)query_done;
+		msg[4] = -1;
+		i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2);
+	
+		/*
+                 * Now unclaim the device.
+                 */
+                if (i2ob_claim_device(dev, 0)<0)
+                        printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
+
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	Open the block device.
+ */
+ 
+static int i2ob_open(struct inode *inode, struct file *file)
+{
+	int minor;
+	struct i2ob_device *dev;
+	
+	if (!inode)
+		return -EINVAL;
+	minor = MINOR(inode->i_rdev);
+	if (minor >= MAX_I2OB<<4)
+		return -ENODEV;
+	dev=&i2ob_dev[(minor&0xF0)];
+
+	if(dev->refcnt++==0)
+	{ 
+		u32 msg[6];
+		int *query_done;
+		
+		
+		if(i2ob_claim_device(dev, 1)<0)
+		{
+			dev->refcnt--;
+			return -EBUSY;
+		}
+		
+		query_done = &dev->done_flag;
+		/*
+		 *	Mount the media if needed. Note that we don't use
+		 *	the lock bit. Since we have to issue a lock if it
+		 *	refuses a mount (quite possible) then we might as
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 03'
echo 'File patch-2.3.6 is continued in part 04'
echo 04 > _shar_seq_.tmp
#!/bin/sh
# this is part 11 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 11; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define _SK_MCA_DRIVER_
+#include "sk_mca.h"
+
+/* ------------------------------------------------------------------------
+ * global static data - not more since we can handle multiple boards and
+ * have to pack all state info into the device struct!
+ * ------------------------------------------------------------------------ */
+
+static char *MediaNames[Media_Count]=
+            {"10Base2", "10BaseT", "10Base5", "Unknown"};
+
+static unsigned char poly[] =
+       {1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
+        1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0};
+
+/* ------------------------------------------------------------------------
+ * private subfunctions
+ * ------------------------------------------------------------------------ */
+
+/* dump parts of shared memory - only needed during debugging */
+
+#ifdef DEBUG
+static void dumpmem(struct device *dev, u32 start, u32 len)
+{
+  int z;
+
+  for (z = 0; z < len; z++)
+  {
+    if ((z & 15) == 0)
+      printk("%04x:", z);
+    printk(" %02x", readb(dev->mem_start + start + z));
+    if ((z & 15) == 15)
+      printk("\n");
+  }
+}
+
+/* print exact time - ditto */
+
+static void PrTime(void)
+{
+  struct timeval tv;
+
+  do_gettimeofday(&tv);
+  printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
+}
+#endif
+
+/* deduce resources out of POS registers */
+
+static void getaddrs(int slot, int junior, int *base, int *irq,
+                     skmca_medium *medium)
+{
+  u_char pos0, pos1, pos2;
+  
+  if (junior)
+  {
+    pos0 = mca_read_stored_pos(slot, 2);
+    *base = ((pos0 & 0x0e) << 13) + 0xc0000;
+    *irq = ((pos0 & 0x10) >> 4) + 10;
+    *medium = Media_Unknown;
+  }
+  else
+  {
+    /* reset POS 104 Bits 0+1 so the shared memory region goes to the
+       configured area between 640K and 1M.  Afterwards, enable the MC2.
+       I really don't know what rode SK to do this... */
+       
+    mca_write_pos(slot, 4, mca_read_stored_pos(slot, 4) & 0xfc);
+    mca_write_pos(slot, 2, mca_read_stored_pos(slot, 2) | 0x01);
+       
+    pos1 = mca_read_stored_pos(slot, 3);
+    pos2 = mca_read_stored_pos(slot, 4);
+    *base = ((pos1 & 0x07) << 14) + 0xc0000;
+    switch (pos2 & 0x0c)
+    {
+      case 0: *irq = 3; break;
+      case 4: *irq = 5; break;
+      case 8: *irq = 10; break;
+      case 12: *irq = 11; break;
+    }
+    *medium = (pos2 >> 6) & 3;
+  }
+}
+
+/* check for both cards:
+   When the MC2 is turned off, it was configured for more than 15MB RAM,
+   is disabled and won't get detected using the standard probe.  We
+   therefore have to scan the slots manually :-( */
+
+static int dofind(int *junior, int firstslot)
+{
+  int slot;
+  unsigned int id;
+
+  for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++)
+  {
+    id = mca_read_stored_pos(slot, 0)
+       + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
+       
+    *junior = 0;
+    if (id == SKNET_MCA_ID)
+      return slot;
+    *junior = 1;
+    if (id == SKNET_JUNIOR_MCA_ID)
+      return slot;
+  }
+  return MCA_NOTFOUND;
+}
+
+/* reset the whole board */
+
+static void ResetBoard(struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  writeb(CTRL_RESET_ON, priv->ctrladdr);
+  udelay(10);
+  writeb(CTRL_RESET_OFF, priv->ctrladdr);
+}
+
+/* set LANCE register - must be atomic */
+
+static void SetLANCE(struct device *dev, u16 addr, u16 value)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  unsigned long flags;
+
+ /* disable interrupts */
+
+  save_flags(flags);
+  cli();
+
+  /* wait until no transfer is pending */
+  
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer register address to RAP */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+  writew(addr, priv->ioregaddr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer data to register */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
+  writew(value, priv->ioregaddr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* reenable interrupts */
+
+  restore_flags(flags);
+}
+
+/* get LANCE register */
+
+static u16 GetLANCE(struct device *dev, u16 addr)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  unsigned long flags;
+  unsigned int res;
+
+  /* disable interrupts */
+
+  save_flags(flags);
+  cli();
+
+  /* wait until no transfer is pending */
+
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer register address to RAP */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+  writew(addr, priv->ioregaddr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+  /* transfer data from register */
+
+  writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
+  writeb(IOCMD_GO, priv->cmdaddr);
+  udelay(1);
+  while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+  res = readw(priv->ioregaddr);
+
+  /* reenable interrupts */
+
+  restore_flags(flags);
+
+  return res;
+}
+
+/* build up descriptors in shared RAM */
+
+static void InitDscrs(struct device *dev)
+{
+  u32 bufaddr;
+
+  /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
+     are always 0. */
+
+  bufaddr = RAM_DATABASE;
+  {
+    LANCE_TxDescr descr;
+    int z;
+
+    for (z = 0; z < TXCOUNT; z++)
+    {
+      descr.LowAddr = bufaddr;
+      descr.Flags = 0;
+      descr.Len = 0xf000;
+      descr.Status = 0;
+      memcpy_toio(dev->mem_start + RAM_TXBASE + (z * sizeof(LANCE_TxDescr)),
+                  &descr, sizeof(LANCE_TxDescr));
+      memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
+      bufaddr += RAM_BUFSIZE;
+    }
+  }
+
+  /* do the same for the Rx descriptors */
+ 
+  {
+    LANCE_RxDescr descr;
+    int z;
+
+    for (z = 0; z < RXCOUNT; z++)
+    {
+      descr.LowAddr = bufaddr;
+      descr.Flags = RXDSCR_FLAGS_OWN;
+      descr.MaxLen = -RAM_BUFSIZE;
+      descr.Len = 0;
+      memcpy_toio(dev->mem_start + RAM_RXBASE + (z * sizeof(LANCE_RxDescr)),
+                  &descr, sizeof(LANCE_RxDescr));
+      memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
+      bufaddr += RAM_BUFSIZE;
+    }
+  }
+}
+
+/* calculate the hash bit position for a given multicast address
+   taken more or less directly from the AMD datasheet... */
+
+static void UpdateCRC(unsigned char *CRC, int bit)
+{
+  int j;
+
+  /* shift CRC one bit */
+
+  memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
+  CRC[0] = 0;
+
+  /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
+
+  if (bit ^ CRC[32])
+    for (j = 0; j < 32; j++)
+      CRC[j] ^= poly[j];
+}
+
+static unsigned int GetHash(char *address)
+{
+  unsigned char CRC[33];
+  int i, byte, hashcode;
+
+  /* a multicast address has bit 0 in the first byte set */
+
+  if ((address[0] & 1) == 0)
+    return -1;
+
+  /* initialize CRC */
+
+  memset(CRC, 1, sizeof(CRC));
+
+  /* loop through address bits */
+
+  for (byte = 0; byte < 6; byte++)
+    for (i = 0; i < 8; i++)
+      UpdateCRC(CRC, (address[byte] >> i) & 1);
+
+  /* hashcode is the 6 least significant bits of the CRC */
+
+  hashcode = 0;
+  for (i = 0; i < 6; i++)
+    hashcode = (hashcode << 1) + CRC[i];
+  return hashcode;
+}
+
+/* feed ready-built initialization block into LANCE */
+
+static void InitLANCE(struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  /* build up descriptors. */
+
+  InitDscrs(dev);
+
+  /* next RX descriptor to be read is the first one.  Since the LANCE
+     will start from the beginning after initialization, we have to 
+     reset out pointers too. */
+
+  priv->nextrx = 0;
+
+  /* no TX descriptors active */
+
+  priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
+
+  /* set up the LANCE bus control register - constant for SKnet boards */
+
+  SetLANCE(dev, LANCE_CSR3, CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
+
+  /* write address of initialization block into LANCE */
+
+  SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
+  SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
+
+  /* we don't get ready until the LANCE has read the init block */
+
+  dev->tbusy = 1;
+
+  /* let LANCE read the initialization block.  LANCE is ready
+     when we receive the corresponding interrupt. */
+
+  SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
+}
+
+/* stop the LANCE so we can reinitialize it */
+
+static void StopLANCE(struct device *dev)
+{
+  /* can't take frames any more */
+
+  dev->tbusy = 1;
+
+  /* disable interrupts, stop it */
+
+  SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
+}
+
+/* initialize card and LANCE for proper operation */
+
+static void InitBoard(struct device *dev)
+{
+  LANCE_InitBlock block;
+
+  /* Lay out the shared RAM - first we create the init block for the LANCE.
+     We do not overwrite it later because we need it again when we switch
+     promiscous mode on/off. */
+
+  block.Mode = 0;
+  if (dev->flags & IFF_PROMISC)
+    block.Mode |= LANCE_INIT_PROM;
+  memcpy(block.PAdr, dev->dev_addr, 6);
+  memset(block.LAdrF, 0, sizeof(block.LAdrF));
+  block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
+  block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
+
+  memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+
+  /* initialize LANCE. Implicitly sets up other structures in RAM. */
+
+  InitLANCE(dev);
+}
+
+/* deinitialize card and LANCE */
+
+static void DeinitBoard(struct device *dev)
+{
+  /* stop LANCE */
+
+  StopLANCE(dev);
+
+  /* reset board */
+
+  ResetBoard(dev);
+}
+
+/* ------------------------------------------------------------------------
+ * interrupt handler(s)
+ * ------------------------------------------------------------------------ */
+
+/* LANCE has read initializazion block -> start it */
+
+static u16 irqstart_handler(struct device *dev, u16 oldcsr0)
+{
+  /* now we're ready to transmit */
+
+  dev->tbusy = 0;
+
+  /* reset IDON bit, start LANCE */
+
+  SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
+  return GetLANCE(dev, LANCE_CSR0);
+}
+
+/* receive interrupt */
+
+static u16 irqrx_handler(struct device *dev, u16 oldcsr0)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  LANCE_RxDescr descr;
+  unsigned int descraddr;
+
+  /* did we loose blocks due to a FIFO overrun ? */
+
+  if (oldcsr0 & CSR0_MISS)
+    priv->stat.rx_fifo_errors++;
+
+  /* run through queue until we reach a descriptor we do not own */
+
+  descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
+  while (1)
+  {
+    /* read descriptor */
+    memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_RxDescr));
+ 
+    /* if we reach a descriptor we do not own, we're done */
+    if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
+      break;
+
+#ifdef DEBUG
+    PrTime(); printk("Receive packet on descr %d len %d\n", priv->nextrx, descr.Len);
+#endif
+
+    /* erroneous packet ? */
+    if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0)
+    {
+      priv->stat.rx_errors++;
+      if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+        priv->stat.rx_crc_errors++;
+      else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+        priv->stat.rx_frame_errors++;
+      else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
+        priv->stat.rx_fifo_errors++;
+    }
+
+    /* good packet ? */
+    else
+    {
+      struct sk_buff *skb;
+
+      skb = dev_alloc_skb(descr.Len + 2);
+      if (skb == NULL)
+        priv->stat.rx_dropped++;
+      else
+      {
+        memcpy_fromio(skb_put(skb, descr.Len),
+                      dev->mem_start + descr.LowAddr, descr.Len);
+        skb->dev = dev;
+        skb->protocol = eth_type_trans(skb, dev);
+        skb->ip_summed = CHECKSUM_NONE;
+        priv->stat.rx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119       /* byte counters for >= 2.1.25 */
+        priv->stat.rx_bytes += descr.Len;
+#endif
+        netif_rx(skb);
+      }
+    }
+
+    /* give descriptor back to LANCE */
+    descr.Len = 0;
+    descr.Flags |= RXDSCR_FLAGS_OWN;
+
+    /* update descriptor in shared RAM */
+    memcpy_toio(dev->mem_start + descraddr, &descr, sizeof(LANCE_RxDescr));
+
+    /* go to next descriptor */
+    priv->nextrx++; descraddr += sizeof(LANCE_RxDescr);
+    if (priv->nextrx >= RXCOUNT)
+    {
+      priv->nextrx = 0;
+      descraddr = RAM_RXBASE;
+    }
+  }
+
+  /* reset RINT bit */
+
+  SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
+  return GetLANCE(dev, LANCE_CSR0);
+}
+
+/* transmit interrupt */
+
+static u16 irqtx_handler(struct device *dev, u16 oldcsr0)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  LANCE_TxDescr descr;
+  unsigned int descraddr;
+
+  /* check descriptors at most until no busy one is left */
+
+  descraddr = RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
+  while (priv->txbusy > 0)
+  {
+    /* read descriptor */
+    memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_TxDescr));
+
+    /* if the LANCE still owns this one, we've worked out all sent packets */
+    if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
+      break;
+
+#ifdef DEBUG
+    PrTime(); printk("Send packet done on descr %d\n", priv->nexttxdone);
+#endif
+
+    /* update statistics */
+    if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0)
+    {
+      priv->stat.tx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119       /* byte counters for >= 2.1.25 */
+      priv->stat.tx_bytes++;
+#endif
+    }
+    else
+    {
+      priv->stat.tx_errors++;
+      if ((descr.Status & TXDSCR_STATUS_UFLO) != 0)
+      {
+        priv->stat.tx_fifo_errors++;
+        InitLANCE(dev);
+      }
+      else if ((descr.Status & TXDSCR_STATUS_LCOL) != 0)
+        priv->stat.tx_window_errors++;
+      else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
+        priv->stat.tx_carrier_errors++;
+      else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
+        priv->stat.tx_aborted_errors++;
+    }
+
+    /* go to next descriptor */
+    priv->nexttxdone++;
+    descraddr += sizeof(LANCE_TxDescr);
+    if (priv->nexttxdone >= TXCOUNT)
+    {
+      priv->nexttxdone = 0;
+      descraddr = RAM_TXBASE;
+    }
+    priv->txbusy--;
+  }
+
+  /* reset TX interrupt bit */
+
+  SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
+  oldcsr0 = GetLANCE(dev, LANCE_CSR0);
+
+  /* at least one descriptor is freed.  Therefore we can accept
+     a new one */
+
+  dev->tbusy = 0;
+
+  /* inform upper layers we're in business again */
+
+  mark_bh(NET_BH);
+
+  return oldcsr0;
+}
+
+/* general interrupt entry */
+
+static void irq_handler(int irq, void *device, struct pt_regs *regs)
+{
+  struct device *dev = (struct device*) device;
+  u16 csr0val;
+
+  /* read CSR0 to get interrupt cause */
+
+  csr0val = GetLANCE(dev, LANCE_CSR0);
+
+  /* in case we're not meant... */
+
+  if ((csr0val & CSR0_INTR) == 0)
+    return;
+
+  dev->interrupt = 1;
+
+  /* loop through the interrupt bits until everything is clear */
+
+  do
+  {
+    if ((csr0val & CSR0_IDON) != 0)
+      csr0val = irqstart_handler(dev, csr0val);
+    if ((csr0val & CSR0_RINT) != 0)
+      csr0val = irqrx_handler(dev, csr0val);
+    if ((csr0val & CSR0_TINT) != 0)
+      csr0val = irqtx_handler(dev, csr0val);
+  }
+  while ((csr0val & CSR0_INTR) != 0);
+
+  dev->interrupt = 0;
+}
+
+/* ------------------------------------------------------------------------
+ * driver methods
+ * ------------------------------------------------------------------------ */
+
+/* MCA info */
+
+static int skmca_getinfo(char *buf, int slot, void *d)
+{
+  int len = 0, i;
+  struct device *dev = (struct device*) d;
+  skmca_priv *priv;
+  
+  /* can't say anything about an uninitialized device... */
+
+  if (dev == NULL)
+    return len;
+  if (dev->priv == NULL)
+    return len;
+  priv = (skmca_priv*) dev->priv;
+
+  /* print info */
+
+  len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
+  len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
+                 dev->mem_end - 1);
+  len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
+  len += sprintf(buf + len, "Device: %s\n", dev->name);
+  len += sprintf(buf + len, "MAC address:");
+  for (i = 0; i < 6; i ++ )
+    len += sprintf( buf+len, " %02x", dev->dev_addr[i] );
+  buf[len++] = '\n';
+  buf[len] = 0;
+
+  return len;
+}
+
+/* open driver.  Means also initialization and start of LANCE */
+
+static int skmca_open(struct device *dev)
+{
+  int result;
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  /* register resources - only necessary for IRQ */
+  result = request_irq(priv->realirq, irq_handler, SA_SHIRQ | SA_SAMPLE_RANDOM,
+                       "sk_mca", dev);
+  if (result != 0)
+  {
+    printk("%s: failed to register irq %d\n", dev->name, dev->irq);
+    return result;
+  }
+  dev->irq = priv->realirq;
+
+  /* set up the card and LANCE */
+  InitBoard(dev);
+
+#ifdef MODULE
+  MOD_INC_USE_COUNT;
+#endif
+
+  return 0;
+}
+
+/* close driver.  Shut down board and free allocated resources */
+
+static int skmca_close(struct device *dev)
+{
+  /* turn off board */
+  DeinitBoard(dev);
+
+  /* release resources */
+  if (dev->irq != 0)
+    free_irq(dev->irq, dev);
+  dev->irq = 0;
+
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
+#endif
+
+  return 0;
+}
+
+/* transmit a block. */
+
+static int skmca_tx(struct sk_buff *skb, struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+  LANCE_TxDescr descr;
+  unsigned int address;
+  int tmplen, retval = 0;
+  unsigned long flags;
+
+  /* if we get called with a NULL descriptor, the Ethernet layer thinks 
+     our card is stuck an we should reset it.  We'll do this completely: */
+
+  if (skb == NULL)
+  {
+    DeinitBoard(dev);
+    InitBoard(dev);
+    return 0; /* don't try to free the block here ;-) */
+  }
+
+  /* is there space in the Tx queue ? If no, the upper layer gave us a
+     packet in spite of us not being ready and is really in trouble.
+     We'll do the dropping for him: */
+  if (priv->txbusy >= TXCOUNT)
+  {
+    priv->stat.tx_dropped++;
+    retval = -EIO;
+    goto tx_done;
+  }
+
+  /* get TX descriptor */
+  address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
+  memcpy_fromio(&descr, dev->mem_start + address, sizeof(LANCE_TxDescr));
+
+  /* enter packet length as 2s complement - assure minimum length */
+  tmplen = skb->len;
+  if (tmplen < 60)
+    tmplen = 60;
+  descr.Len = 65536 - tmplen;
+
+  /* copy filler into RAM - in case we're filling up... 
+     we're filling a bit more than necessary, but that doesn't harm
+     since the buffer is far larger... */
+  if (tmplen > skb->len)
+  {
+    char *fill = "NetBSD is a nice OS too! ";
+    unsigned int destoffs = 0, l = strlen(fill);
+
+    while (destoffs < tmplen)
+    {
+      memcpy_toio(dev->mem_start + descr.LowAddr + destoffs, fill, l);
+      destoffs += l;
+    }
+  }
+
+  /* do the real data copying */
+  memcpy_toio(dev->mem_start + descr.LowAddr, skb->data, skb->len);
+
+  /* hand descriptor over to LANCE - this is the first and last chunk */
+  descr.Flags = TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
+
+#ifdef DEBUG
+  PrTime(); printk("Send packet on descr %d len %d\n", priv->nexttxput, skb->len);
+#endif
+
+  /* one more descriptor busy */
+  save_flags(flags);
+  cli();
+  priv->nexttxput++;
+  if (priv->nexttxput >= TXCOUNT)
+    priv->nexttxput = 0;
+  priv->txbusy++;
+  dev->tbusy = (priv->txbusy >= TXCOUNT);
+
+  /* write descriptor back to RAM */
+  memcpy_toio(dev->mem_start + address, &descr, sizeof(LANCE_TxDescr));
+
+  /* if no descriptors were active, give the LANCE a hint to read it
+     immediately */
+
+  if (priv->txbusy == 0)
+    SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
+
+  restore_flags(flags);
+
+tx_done:
+
+  /* When did that change exactly ? */
+
+#if LINUX_VERSION_CODE >= 0x020200
+  dev_kfree_skb(skb);
+#else
+  dev_kfree_skb(skb, FREE_WRITE);
+#endif
+  return retval;
+}
+
+/* return pointer to Ethernet statistics */
+
+static struct enet_statistics *skmca_stats(struct device *dev)
+{
+  skmca_priv *priv = (skmca_priv*) dev->priv;
+
+  return &(priv->stat);
+}
+
+/* we don't support runtime reconfiguration, since am MCA card can
+   be unambigously identified by its POS registers. */
+
+static int skmca_config(struct device *dev, struct ifmap *map)
+{
+  return 0;
+}
+
+/* switch receiver mode.  We use the LANCE's multicast filter to prefilter
+   multicast addresses. */
+
+static void skmca_set_multicast_list(struct device *dev)
+{
+  LANCE_InitBlock block;
+
+  /* first stop the LANCE... */
+  StopLANCE(dev);
+
+  /* ...then modify the initialization block... */
+  memcpy_fromio(&block, dev->mem_start + RAM_INITBASE, sizeof(block));
+  if (dev->flags & IFF_PROMISC)
+    block.Mode |= LANCE_INIT_PROM;
+  else
+    block.Mode &= ~LANCE_INIT_PROM;
+
+  if (dev->flags & IFF_ALLMULTI)   /* get all multicasts */
+  {
+    memset(block.LAdrF, 8, 0xff);
+  }
+  else                             /* get selected/no multicasts */
+  {
+    struct dev_mc_list *mptr;
+    int code;
+
+    memset(block.LAdrF, 8, 0x00);
+    for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next)
+    {
+      code = GetHash(mptr->dmi_addr);
+      block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
+    }
+  }
+
+  memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+
+  /* ...then reinit LANCE with the correct flags */
+  InitLANCE(dev);
+}
+
+/* ------------------------------------------------------------------------
+ * hardware check
+ * ------------------------------------------------------------------------ */
+
+#ifdef MODULE
+static int startslot; /* counts through slots when probing multiple devices */
+#else
+#define startslot 0   /* otherwise a dummy, since there is only eth0 in-kern*/
+#endif
+
+int skmca_probe(struct device *dev)
+{
+  int force_detect = 0;
+  int junior, slot, i;
+  int base = 0, irq = 0;
+  skmca_priv *priv;
+  skmca_medium medium;
+
+  /* can't work without an MCA bus ;-) */
+  
+  if (MCA_bus == 0)
+    return ENODEV;
+    
+  /* start address of 1 --> forced detection */
+  
+  if (dev->mem_start == 1)
+    force_detect = 1;
+
+  /* search through slots */
+  
+  if (dev != NULL)
+  {
+    base = dev->mem_start;
+    irq = dev->irq;
+  }
+  slot = dofind(&junior, startslot);
+
+  while (slot != -1)
+  {
+    /* deduce card addresses */
+
+    getaddrs(slot, junior, &base, &irq, &medium);
+
+#if 0
+    /* this should work, but it doesn't with 2.2.9 :-( 
+       somehow 'mca_is_adapter_used()' is missing in kernel syms... */
+#if LINUX_VERSION_CODE >= 0x020200
+    /* slot already in use ? */
+
+    if (mca_is_adapter_used(slot))
+    {
+      slot = dofind(&junior, slot + 1);
+      continue;
+    }
+#endif
+#endif
+
+    /* were we looking for something different ? */
+    
+    if ((dev->irq != 0) || (dev->mem_start != 0))
+    {
+      if ((dev->irq != 0) && (dev->irq != irq))
+      {
+        slot = dofind(&junior, slot + 1);
+        continue;
+      }
+      if ((dev->mem_start != 0) && (dev->mem_start != base))
+      {
+        slot = dofind(&junior, slot + 1);
+        continue;
+      }
+    }
+  
+    /* found something that matches */
+    
+    break;
+  }
+
+  /* nothing found ? */
+  
+  if (slot == -1)
+    return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV;
+    
+  /* make procfs entries */
+    
+  if (junior)
+    mca_set_adapter_name(slot, "SKNET junior MC2 Ethernet Adapter");
+  else
+    mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
+  mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
+
+#if LINUX_VERSION_CODE >= 0x020200
+  mca_mark_as_used(slot);
+#endif
+  
+  /* announce success */
+  printk("%s: SKNet %s adapter found in slot %d\n", dev->name, 
+         junior ? "Junior MC2" : "MC2+", slot + 1);
+
+  /* allocate structure */
+  priv = dev->priv = (skmca_priv*) kmalloc(sizeof(skmca_priv), GFP_KERNEL);
+  priv->slot = slot;
+  priv->macbase = base + 0x3fc0;
+  priv->ioregaddr = base + 0x3ff0;
+  priv->ctrladdr = base + 0x3ff2;
+  priv->cmdaddr = base + 0x3ff3;
+  priv->realirq = irq;
+  priv->medium = medium;
+  memset(&(priv->stat), 0, sizeof(struct enet_statistics));
+  
+  /* set base + irq for this device (irq not allocated so far) */
+  dev->irq = 0;
+  dev->mem_start = base;
+  dev->mem_end = base + 0x4000;
+ 
+  /* set methods */
+  dev->open = skmca_open;
+  dev->stop = skmca_close;
+  dev->set_config = skmca_config;
+  dev->hard_start_xmit = skmca_tx;
+  dev->do_ioctl = NULL;
+  dev->get_stats = skmca_stats;
+  dev->set_multicast_list = skmca_set_multicast_list;
+  dev->flags |= IFF_MULTICAST;
+
+  /* generic setup */
+  ether_setup(dev);
+  dev->interrupt = 0;
+  dev->tbusy = 0;
+  dev->start = 0;
+ 
+  /* copy out MAC address */
+  for (i = 0; i < 6; i++)
+    dev->dev_addr[i] = readb(priv->macbase + (i << 1));
+
+  /* print config */
+  printk("%s: IRQ %d, memory %#lx-%#lx, "
+         "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
+         dev->name, priv->realirq,  dev->mem_start, dev->mem_end - 1,
+         dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+         dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+  printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
+
+  /* reset board */
+
+  ResetBoard(dev);
+
+#ifdef MODULE
+  startslot = slot + 1;
+#endif
+
+  return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * modularization support
+ * ------------------------------------------------------------------------ */
+
+#ifdef MODULE
+
+#define DEVMAX 5
+
+static char NameSpace[8 * DEVMAX];
+static struct device moddevs[DEVMAX] =
+       {{NameSpace +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace +  8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+        {NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}};
+
+int irq=0;
+int io=0;
+
+int init_module(void)
+{
+  int z, res;
+
+  startslot = 0;
+  for (z = 0; z < DEVMAX; z++)
+  {
+    strcpy(moddevs[z].name, "     ");
+    res = register_netdev(moddevs + z);
+    if (res != 0)
+      return (z > 0) ? 0 : -EIO;
+  }
+
+  return 0;
+}
+
+void cleanup_module(void)
+{
+  struct device *dev;
+  skmca_priv *priv;
+  int z;
+
+  if (MOD_IN_USE)
+  {
+    printk("cannot unload, module in use\n");
+    return;
+  }
+
+  for (z = 0; z < DEVMAX; z++)
+  {
+    dev = moddevs + z;
+    if (dev->priv != NULL)
+    {
+      priv = (skmca_priv*) dev->priv;
+      DeinitBoard(dev);
+      if (dev->irq != 0)
+        free_irq(dev->irq, dev);
+      dev->irq = 0;
+      unregister_netdev(dev);
+#if LINUX_VERSION_CODE >= 0x020200
+      mca_mark_as_unused(priv->slot);
+#endif
+      mca_set_adapter_procfn(priv->slot, NULL, NULL);
+      kfree_s(dev->priv, sizeof(skmca_priv));
+      dev->priv = NULL;
+    }
+  }
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.5/linux/drivers/net/sk_mca.h linux/drivers/net/sk_mca.h
--- v2.3.5/linux/drivers/net/sk_mca.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sk_mca.h	Mon Jun  7 14:34:46 1999
@@ -0,0 +1,174 @@
+#ifndef _SK_MCA_INCLUDE_
+#define _SK_MCA_INCLUDE_
+
+#ifdef _SK_MCA_DRIVER_
+
+/* Adapter ID's */
+#define SKNET_MCA_ID 0x6afd
+#define SKNET_JUNIOR_MCA_ID 0x6be9
+
+/* media enumeration - defined in a way that it fits onto the MC2+'s
+   POS registers... */
+   
+typedef enum {Media_10Base2, Media_10BaseT,
+              Media_10Base5, Media_Unknown, Media_Count} skmca_medium;
+
+/* private structure */
+typedef struct
+        {
+          unsigned int slot;       /* MCA-Slot-#                       */
+          unsigned int macbase;    /* base address of MAC address PROM */
+          unsigned int ioregaddr;  /* address of I/O-register (Lo)     */
+          unsigned int ctrladdr;   /* address of control/stat register */
+          unsigned int cmdaddr;    /* address of I/O-command register  */
+          int nextrx;              /* index of next RX descriptor to
+                                      be read                          */
+          int nexttxput;           /* index of next free TX descriptor */
+          int nexttxdone;          /* index of next TX descriptor to 
+                                      be finished                      */
+          int txbusy;              /* # of busy TX descriptors         */
+          struct enet_statistics stat; /* packet statistics            */
+          int realirq;             /* memorizes actual IRQ, even when 
+                                      currently not allocated          */
+          skmca_medium medium;     /* physical cannector               */
+        } skmca_priv;
+
+/* card registers: control/status register bits */
+
+#define CTRL_ADR_DATA      0      /* Bit 0 = 0 ->access data register  */
+#define CTRL_ADR_RAP       1      /* Bit 0 = 1 ->access RAP register   */
+#define CTRL_RW_WRITE      0      /* Bit 1 = 0 ->write register        */
+#define CTRL_RW_READ       2      /* Bit 1 = 1 ->read register         */
+#define CTRL_RESET_ON      0      /* Bit 3 = 0 ->reset board           */
+#define CTRL_RESET_OFF     8      /* Bit 3 = 1 ->no reset of board     */
+
+#define STAT_ADR_DATA      0      /* Bit 0 of ctrl register read back  */
+#define STAT_ADR_RAP       1
+#define STAT_RW_WRITE      0      /* Bit 1 of ctrl register read back  */
+#define STAT_RW_READ       2
+#define STAT_RESET_ON      0      /* Bit 3 of ctrl register read back  */
+#define STAT_RESET_OFF     8
+#define STAT_IRQ_ACT       0      /* interrupt pending                 */
+#define STAT_IRQ_NOACT     16     /* no interrupt pending              */
+#define STAT_IO_NOBUSY     0      /* no transfer busy                  */
+#define STAT_IO_BUSY       32     /* transfer busy                     */
+
+/* I/O command register bits */
+
+#define IOCMD_GO           128    /* Bit 7 = 1 -> start register xfer  */
+
+/* LANCE registers */
+
+#define LANCE_CSR0         0      /* Status/Control                    */
+
+#define CSR0_ERR           0x8000 /* general error flag                */
+#define CSR0_BABL          0x4000 /* transmitter timeout               */
+#define CSR0_CERR          0x2000 /* collision error                   */
+#define CSR0_MISS          0x1000 /* lost Rx block                     */
+#define CSR0_MERR          0x0800 /* memory access error               */
+#define CSR0_RINT          0x0400 /* receiver interrupt                */
+#define CSR0_TINT          0x0200 /* transmitter interrupt             */
+#define CSR0_IDON          0x0100 /* initialization done               */
+#define CSR0_INTR          0x0080 /* general interrupt flag            */
+#define CSR0_INEA          0x0040 /* interrupt enable                  */
+#define CSR0_RXON          0x0020 /* receiver enabled                  */
+#define CSR0_TXON          0x0010 /* transmitter enabled               */
+#define CSR0_TDMD          0x0008 /* force transmission now            */
+#define CSR0_STOP          0x0004 /* stop LANCE                        */
+#define CSR0_STRT          0x0002 /* start LANCE                       */
+#define CSR0_INIT          0x0001 /* read initialization block         */          
+
+#define LANCE_CSR1         1      /* addr bit 0..15 of initialization  */
+#define LANCE_CSR2         2      /*          16..23 block             */
+
+#define LANCE_CSR3         3      /* Bus control                       */
+#define CSR3_BCON_HOLD     0      /* Bit 0 = 0 -> BM1,BM0,HOLD         */
+#define CSR3_BCON_BUSRQ    1      /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ    */
+#define CSR3_ALE_HIGH      0      /* Bit 1 = 0 -> ALE asserted high    */
+#define CSR3_ALE_LOW       2      /* Bit 1 = 1 -> ALE asserted low     */
+#define CSR3_BSWAP_OFF     0      /* Bit 2 = 0 -> no byte swap         */
+#define CSR3_BSWAP_ON      0      /* Bit 2 = 1 -> byte swap            */
+
+/* LANCE structures */
+
+typedef struct                    /* LANCE initialization block        */
+        {
+          u16 Mode;               /* mode flags                        */
+          u8  PAdr[6];            /* MAC address                       */
+          u8  LAdrF[8];           /* Multicast filter                  */
+          u32 RdrP;               /* Receive descriptor                */
+          u32 TdrP;               /* Transmit descriptor               */
+        } LANCE_InitBlock;
+        
+/* Mode flags init block */
+
+#define LANCE_INIT_PROM    0x8000 /* enable promiscous mode            */
+#define LANCE_INIT_INTL    0x0040 /* internal loopback                 */
+#define LANCE_INIT_DRTY    0x0020 /* disable retry                     */
+#define LANCE_INIT_COLL    0x0010 /* force collision                   */
+#define LANCE_INIT_DTCR    0x0008 /* disable transmit CRC              */
+#define LANCE_INIT_LOOP    0x0004 /* loopback                          */
+#define LANCE_INIT_DTX     0x0002 /* disable transmitter               */
+#define LANCE_INIT_DRX     0x0001 /* disable receiver                  */
+
+typedef struct                    /* LANCE Tx descriptor               */
+        {
+          u16 LowAddr;            /* bit 0..15 of address              */
+          u16 Flags;              /* bit 16..23 of address + Flags     */
+          u16 Len;                /* 2s complement of packet length    */
+          u16 Status;             /* Result of transmission            */
+        } LANCE_TxDescr;
+
+#define TXDSCR_FLAGS_OWN   0x8000 /* LANCE owns descriptor             */
+#define TXDSCR_FLAGS_ERR   0x4000 /* summary error flag                */
+#define TXDSCR_FLAGS_MORE  0x1000 /* more than one retry needed?       */
+#define TXDSCR_FLAGS_ONE   0x0800 /* one retry?                        */
+#define TXDSCR_FLAGS_DEF   0x0400 /* transmission deferred?            */
+#define TXDSCR_FLAGS_STP   0x0200 /* first packet in chain?            */
+#define TXDSCR_FLAGS_ENP   0x0100 /* last packet in chain?             */
+
+#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error?                     */
+#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit?   */
+#define TXDSCR_STATUS_LCOL 0x1000 /* late collision?                   */
+#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier?                  */
+#define TXDSCR_STATUS_RTRY 0x0400 /* retry error?                      */
+        
+typedef struct                    /* LANCE Rx descriptor               */
+        {
+          u16 LowAddr;            /* bit 0..15 of address              */
+          u16 Flags;              /* bit 16..23 of address + Flags     */
+          u16 MaxLen;             /* 2s complement of buffer length    */
+          u16 Len;                /* packet length                     */
+        } LANCE_RxDescr;
+
+#define RXDSCR_FLAGS_OWN   0x8000 /* LANCE owns descriptor             */
+#define RXDSCR_FLAGS_ERR   0x4000 /* summary error flag                */
+#define RXDSCR_FLAGS_FRAM  0x2000 /* framing error flag                */
+#define RXDSCR_FLAGS_OFLO  0x1000 /* FIFO overflow?                    */
+#define RXDSCR_FLAGS_CRC   0x0800 /* CRC error?                        */
+#define RXDSCR_FLAGS_BUFF  0x0400 /* buffer error?                     */
+#define RXDSCR_FLAGS_STP   0x0200 /* first packet in chain?            */
+#define RXDCSR_FLAGS_ENP   0x0100 /* last packet in chain?             */
+
+/* RAM layout */
+
+#define TXCOUNT            4      /* length of TX descriptor queue     */
+#define LTXCOUNT           2      /* log2 of it                        */
+#define RXCOUNT            4      /* length of RX descriptor queue     */
+#define LRXCOUNT           2      /* log2 of it                        */
+
+#define RAM_INITBASE       0      /* LANCE init block                  */
+#define RAM_TXBASE         24     /* Start of TX descriptor queue      */
+#define RAM_RXBASE         \
+(RAM_TXBASE + (TXCOUNT * 8))      /* Start of RX descriptor queue      */
+#define RAM_DATABASE       \
+(RAM_RXBASE + (RXCOUNT * 8))      /* Start of data area for frames     */
+#define RAM_BUFSIZE        1580   /* max. frame size - should never be
+                                     reached                           */
+
+#endif /* _SK_MCA_DRIVER_ */
+
+extern int skmca_probe(struct device *);
+
+
+#endif /* _SK_MCA_INCLUDE_ */
\ No newline at end of file
diff -u --recursive --new-file v2.3.5/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.3.5/linux/drivers/pci/oldproc.c	Fri May 14 18:55:20 1999
+++ linux/drivers/pci/oldproc.c	Wed Jun  9 16:59:15 1999
@@ -102,6 +102,7 @@
X 	DEVICE( DEC,		DEC_21150,	"DC21150"),
X 	DEVICE( DEC,		DEC_21152,	"DC21152"),
X 	DEVICE( DEC,		DEC_21153,	"DC21153"),
+	DEVICE( DEC,		DEC_21154,	"DC21154"),
X 	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548"),
X 	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
X 	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434"),
@@ -202,6 +203,8 @@
X 	DEVICE( MOTOROLA,	MOTOROLA_MPC105,"MPC105 Eagle"),
X 	DEVICE( MOTOROLA,	MOTOROLA_MPC106,"MPC106 Grackle"),
X 	DEVICE( MOTOROLA,	MOTOROLA_RAVEN,	"Raven"),
+	DEVICE( MOTOROLA,	MOTOROLA_FALCON,"Falcon"),
+	DEVICE( MOTOROLA,	MOTOROLA_CPX8216,"CPX8216"),
X 	DEVICE( PROMISE,        PROMISE_20246,	"IDE UltraDMA/33"),
X 	DEVICE(	PROMISE,	PROMISE_20262,	"IDE UltraDMA/66"),
X 	DEVICE( PROMISE,	PROMISE_5300,	"DC5030"),
@@ -467,6 +470,7 @@
X 	DEVICE( PICTUREL,	PICTUREL_PCIVST,"PCIVST"),
X 	DEVICE( NVIDIA_SGS,	NVIDIA_SGS_RIVA128,	"Riva 128"),
X 	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16"),
+	DEVICE( MOTOROLA_OOPS,	MOTOROLA_FALCON,"Falcon"),
X 	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
X 	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
X 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
@@ -536,9 +540,11 @@
X  	DEVICE( INTEL,		INTEL_82450GX,	"82450GX Orion P6"),
X 	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7810,	"AIC-7810 RAID"),
+	DEVICE( ADAPTEC,	ADAPTEC_7821,	"AIC-7860"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7850,	"AIC-7850"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7855,	"AIC-7855"),
X 	DEVICE( ADAPTEC,	ADAPTEC_5800,	"AIC-5800"),
+	DEVICE( ADAPTEC,	ADAPTEC_3860,	"AIC-7860"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7860,	"AIC-7860"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7861,	"AIC-7861"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7870,	"AIC-7870"),
@@ -552,13 +558,26 @@
X 	DEVICE( ADAPTEC,	ADAPTEC_7882,	"AIC-7882U"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7883,	"AIC-7883U"),
X 	DEVICE( ADAPTEC,	ADAPTEC_7884,	"AIC-7884U"),
+	DEVICE( ADAPTEC,	ADAPTEC_7885,	"AIC-7885U"),
+	DEVICE( ADAPTEC,	ADAPTEC_7886,	"AIC-7886U"),
+	DEVICE( ADAPTEC,	ADAPTEC_7887,	"AIC-7887U"),
+	DEVICE( ADAPTEC,	ADAPTEC_7888,	"AIC-7888U"),
X 	DEVICE( ADAPTEC,	ADAPTEC_1030,	"ABA-1030 DVB receiver"),
X 	DEVICE( ADAPTEC2,	ADAPTEC2_2940U2,"AHA-2940U2"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_78902,	"AIC-7890/1"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_2930U2,"AHA-2930U2"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7890B,	"AIC-7890/1"),
X 	DEVICE( ADAPTEC2,	ADAPTEC2_7890,	"AIC-7890/1"),
X 	DEVICE( ADAPTEC2,	ADAPTEC2_3940U2,"AHA-3940U2"),
X 	DEVICE( ADAPTEC2,	ADAPTEC2_3950U2D,"AHA-3950U2D"),
X 	DEVICE( ADAPTEC2,	ADAPTEC2_7896,	"AIC-7896/7"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892A,	"AIC-7892"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892B,	"AIC-7892"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892D,	"AIC-7892"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892P,	"AIC-7892"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899A,	"AIC-7899"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899B,	"AIC-7899"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899D,	"AIC-7899"),
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899P,	"AIC-7899"),
X   	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL"),
X 	DEVICE( TIGERJET,	TIGERJET_300,	"Tiger300 ISDN"),
X 	DEVICE( ARK,		ARK_STING,	"Stingray"),
@@ -676,6 +695,8 @@
X 	      case PCI_CLASS_SERIAL_USB:		return "USB Controller";
X 	      case PCI_CLASS_SERIAL_FIBER:		return "Fiber Channel";
X 
+	      case PCI_CLASS_HOT_SWAP_CONTROLLER:	return "Hot Swap Controller";
+
X 	      default:					return "Unknown class";
X 	}
X }
@@ -715,6 +736,7 @@
X 	      case PCI_VENDOR_ID_OAK: 		return "OAK";
X 	      case PCI_VENDOR_ID_WINBOND2:	return "Winbond";
X 	      case PCI_VENDOR_ID_MOTOROLA:	return "Motorola";
+	      case PCI_VENDOR_ID_MOTOROLA_OOPS:	return "Motorola";
X 	      case PCI_VENDOR_ID_PROMISE:	return "Promise Technology";
X 	      case PCI_VENDOR_ID_N9:		return "Number Nine";
X 	      case PCI_VENDOR_ID_UMC:		return "UMC";
diff -u --recursive --new-file v2.3.5/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in
--- v2.3.5/linux/drivers/sbus/char/Config.in	Mon May 31 22:28:06 1999
+++ linux/drivers/sbus/char/Config.in	Wed Jun  9 14:44:25 1999
@@ -12,4 +12,10 @@
X   tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP
X   tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
X   tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA
+
+  # XXX Why don't we do "source drivers/char/Config.in" somewhere?
+  if [ "$CONFIG_PCI" = "y" ]; then
+    define_bool CONFIG_APM_RTC_IS_GMT y		# no shit
+    bool 'PC-style RTC' CONFIG_RTC
+  fi
X fi
diff -u --recursive --new-file v2.3.5/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.3.5/linux/drivers/sbus/char/aurora.c	Mon May 31 22:28:06 1999
+++ linux/drivers/sbus/char/aurora.c	Wed Jun  9 14:44:25 1999
@@ -53,6 +53,7 @@
X #include <linux/kernel.h>
X #include <linux/init.h>
X #include <linux/tqueue.h>
+#include <linux/delay.h>
X 
X #include <asm/io.h>
X #include <asm/irq.h>
@@ -60,7 +61,6 @@
X #include <asm/system.h>
X #include <asm/segment.h>
X #include <asm/bitops.h>
-#include <asm/delay.h>
X #include <asm/kdebug.h>
X #include <asm/sbus.h>
X #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.5/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.3.5/linux/drivers/sbus/char/bpp.c	Fri May 14 18:55:21 1999
+++ linux/drivers/sbus/char/bpp.c	Wed Jun  9 14:44:25 1999
@@ -997,7 +997,7 @@
X       instances[idx].enhanced = 0;
X       instances[idx].direction = 0;
X       instances[idx].mode = COMPATIBILITY;
-      instances[idx].wait_queue = 0;
+      init_waitqueue_head(&instances[idx].wait_queue);
X       instances[idx].run_length = 0;
X       instances[idx].run_flag = 0;
X       init_timer(&instances[idx].timer_list);
diff -u --recursive --new-file v2.3.5/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.3.5/linux/drivers/sbus/char/pcikbd.c	Mon May 17 09:55:22 1999
+++ linux/drivers/sbus/char/pcikbd.c	Wed Jun  9 14:44:25 1999
@@ -1,8 +1,8 @@
-/* $Id: pcikbd.c,v 1.29 1999/05/16 13:47:53 ecd Exp $
+/* $Id: pcikbd.c,v 1.30 1999/06/03 15:02:36 davem Exp $
X  * pcikbd.c: Ultra/AX PC keyboard support.
X  *
X  * Copyright (C) 1997  Eddie C. Dost  (e...@skynet.be)
- * JavaStation(MrCoffee) support by Pete A. Zaitcev.
+ * JavaStation support by Pete A. Zaitcev.
X  *
X  * This code is mainly put together from various places in
X  * drivers/char, please refer to these sources for credits
@@ -30,13 +30,16 @@
X #include <asm/io.h>
X #include <asm/uaccess.h>
X 
-#ifdef __sparc_v9__
-#define	PCI_KB_NAME	"kb_ps2"
-#define PCI_MS_NAME	"kdmouse"
-#else
-#define PCI_KB_NAME	"keyboard"
-#define PCI_MS_NAME	"mouse"
-#endif
+/*
+ * Different platforms provide different permutations of names.
+ * AXi - kb_ps2, kdmouse.
+ * MrCoffee - keyboard, mouse.
+ * Espresso - keyboard, kdmouse.
+ */
+#define	PCI_KB_NAME1	"kb_ps2"
+#define PCI_KB_NAME2	"keyboard"
+#define PCI_MS_NAME1	"kdmouse"
+#define PCI_MS_NAME2	"mouse"
X 
X #include "pcikbd.h"
X #include "sunserial.h"
@@ -502,7 +505,8 @@
X 			for_each_ebusdev(edev, ebus) {
X 				if(!strcmp(edev->prom_name, "8042")) {
X 					for_each_edevchild(edev, child) {
-                                                if (!strcmp(child->prom_name, PCI_KB_NAME))
+                                                if (strcmp(child->prom_name, PCI_KB_NAME1) == 0 ||
+						    strcmp(child->prom_name, PCI_KB_NAME2) == 0)
X 							goto found;
X 					}
X 				}
@@ -513,12 +517,14 @@
X 
X found:
X 		pcikbd_iobase = child->base_address[0];
+#ifdef __sparc_v9__
X 		if (check_region(pcikbd_iobase, sizeof(unsigned long))) {
X 			printk("8042: can't get region %lx, %d\n",
X 			       pcikbd_iobase, (int)sizeof(unsigned long));
X 			return;
X 		}
X 		request_region(pcikbd_iobase, sizeof(unsigned long), "8042 controller");
+#endif
X 
X 		pcikbd_irq = child->irqs[0];
X 		if (request_irq(pcikbd_irq, &pcikbd_interrupt,
@@ -548,7 +554,7 @@
X 	 * XXX: my 3.1.3 PROM does not give me the beeper node for the audio
X 	 *      auxio register, though I know it is there... (ecd)
X 	 *
-	 * Both JE1 & MrCoffe have no beeper. How about Krups? --zaitcev
+	 * JavaStations appear not to have beeper. --zaitcev
X 	 */
X 	if (!edev)
X 		pcibeep_iobase = (pcikbd_iobase & ~(0xffffff)) | 0x722000;
@@ -575,7 +581,6 @@
X }
X 
X 
-
X /*
X  * Here begins the Mouse Driver.
X  */
@@ -955,7 +960,8 @@
X 			for_each_ebusdev(edev, ebus) {
X 				if(!strcmp(edev->prom_name, "8042")) {
X 					for_each_edevchild(edev, child) {
-							if (!strcmp(child->prom_name, PCI_MS_NAME))
+							if (strcmp(child->prom_name, PCI_MS_NAME1) == 0 ||
+							    strcmp(child->prom_name, PCI_MS_NAME2) == 0)
X 							goto found;
X 					}
X 				}
@@ -1023,7 +1029,7 @@
X 
X __initfunc(int ps2kbd_probe(unsigned long *memory_start))
X {
-	int pnode, enode, node, dnode;
+	int pnode, enode, node, dnode, xnode;
X 	int kbnode = 0, msnode = 0, bnode = 0;
X 	int devices = 0;
X 	char prop[128];
@@ -1103,18 +1109,20 @@
X 			 * For each '8042' on this EBus...
X 			 */
X 			while (node) {
+				dnode = prom_getchild(node);
+
X 				/*
X 				 * Does it match?
X 				 */
-				dnode = prom_getchild(node);
-				dnode = prom_searchsiblings(dnode, PCI_KB_NAME);
-				if (dnode == kbnode) {
+				if ((xnode = prom_searchsiblings(dnode, PCI_KB_NAME1)) == kbnode) {
+					++devices;
+				} else if ((xnode = prom_searchsiblings(dnode, PCI_KB_NAME2)) == kbnode) {
X 					++devices;
X 				}
X 
-				dnode = prom_getchild(node);
-				dnode = prom_searchsiblings(dnode, PCI_MS_NAME);
-				if (dnode == msnode) {
+				if ((xnode = prom_searchsiblings(dnode, PCI_MS_NAME1)) == msnode) {
+					++devices;
+				} else if ((xnode = prom_searchsiblings(dnode, PCI_MS_NAME2)) == msnode) {
X 					++devices;
X 				}
X 
diff -u --recursive --new-file v2.3.5/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c
--- v2.3.5/linux/drivers/sbus/char/rtc.c	Sun Oct  4 10:22:44 1998
+++ linux/drivers/sbus/char/rtc.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.13 1998/08/26 10:29:44 davem Exp $
+/* $Id: rtc.c,v 1.14 1999/06/03 15:02:38 davem Exp $
X  *
X  * Linux/SPARC Real Time Clock Driver
X  * Copyright (C) 1996 Thomas K. Dyas (td...@eden.rutgers.edu)
@@ -107,6 +107,7 @@
X 
X static int rtc_open(struct inode *inode, struct file *file)
X {
+
X 	if (rtc_busy)
X 		return -EBUSY;
X 
@@ -144,14 +145,20 @@
X #ifdef MODULE
X int init_module(void)
X #else
-__initfunc(int rtc_init(void))
+__initfunc(int rtc_sun_init(void))
X #endif
X {
X 	int error;
X 
+	if (mstk48t02_regs == 0) {
+		/* This diagnostic is a debugging aid... But a useful one. */
+		printk(KERN_ERR "rtc: no Mostek in this computer\n");
+		return -ENODEV;
+	}
+
X 	error = misc_register(&rtc_dev);
X 	if (error) {
-		printk(KERN_ERR "rtc: unable to get misc minor\n");
+		printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n");
X 		return error;
X 	}
X 
diff -u --recursive --new-file v2.3.5/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.3.5/linux/drivers/sbus/char/su.c	Fri May 14 18:55:21 1999
+++ linux/drivers/sbus/char/su.c	Wed Jun  9 14:44:25 1999
@@ -1,8 +1,8 @@
-/* $Id: su.c,v 1.19 1999/05/12 11:15:14 davem Exp $
+/* $Id: su.c,v 1.20 1999/06/03 15:02:40 davem Exp $
X  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
X  *
X  * Copyright (C) 1997  Eddie C. Dost  (e...@skynet.be)
- * Coypright (C) 1998  Pete Zaitcev   (zai...@metabyte.com)
+ * Copyright (C) 1998-1999  Pete Zaitcev   (zai...@metabyte.com)
X  *
X  * This is mainly a variation of drivers/char/serial.c,
X  * credits go to authors mentioned therein.
@@ -92,6 +92,11 @@
X int su_serial_console_init(void);
X #endif
X 
+enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
+static char *su_typev[] = { "???", "mouse", "kbd", "serial" };
+
+#define SU_PROPSIZE	128
+
X /*
X  * serial.c saves memory when it allocates async_info upon first open.
X  * We have parts of state structure together because we do call startup
@@ -107,8 +112,7 @@
X 	int		 line;
X 	int		 cflag;
X 
-	int		 kbd_node;
-	int		 ms_node;
+	enum su_type	 port_type;	/* Hookup type: e.g. mouse */
X 	int		 port_node;
X 
X 	char		 name[16];
@@ -145,6 +149,18 @@
X 	unsigned long		last_active;	/* For async_struct, to be */
X };
X 
+/*
+ * Scan status structure.
+ * "prop" is a local variable but it eats stack to keep it in each
+ * stack frame of a recursive procedure.
+ */
+struct su_probe_scan {
+	int msnode, kbnode;	/* PROM nodes for mouse and keyboard */
+	int msx, kbx;		/* minors for mouse and keyboard */
+	int devices;		/* scan index */
+	char prop[SU_PROPSIZE];
+};
+
X static char *serial_name = "PCIO serial driver";
X static char serial_version[16];
X 
@@ -223,8 +239,6 @@
X 	return 0;
X }
X 
-#ifdef __sparc_v9__
-
X static inline
X unsigned int su_inb(struct su_struct *info, unsigned long offset)
X {
@@ -234,20 +248,7 @@
X static inline void
X su_outb(struct su_struct *info, unsigned long offset, int value)
X {
-	outb(value, info->port + offset);
-}
-
-#else
-
-static inline
-unsigned int su_inb(struct su_struct *info, unsigned long offset)
-{
-	return (unsigned int)(*(volatile unsigned char *)(info->port + offset));
-}
-
-static inline void
-su_outb(struct su_struct *info, unsigned long offset, int value)
-{
+#ifndef __sparc_v9__
X 	/*
X 	 * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
X 	 * connected with a gate then go to SlavIO. When IRQ4 goes tristated
@@ -257,10 +258,9 @@
X 	 * This problem is similar to what Alpha people suffer, see serial.c.
X 	 */
X 	if (offset == UART_MCR) value |= UART_MCR_OUT2;
-	*(volatile unsigned char *)(info->port + offset) = value;
-}
-
X #endif
+	outb(value, info->port + offset);
+}
X 
X #define serial_in(info, off)		su_inb(info, off)
X #define serial_inp(info, off)		su_inb(info, off)
@@ -348,7 +348,7 @@
X 
X 	do {
X 		ch = serial_inp(info, UART_RX);
-		if (info->kbd_node) {
+		if (info->port_type == SU_PORT_KBD) {
X 			if(ch == SUNKBD_RESET) {
X                         	l1a_state.kbd_id = 1;
X                         	l1a_state.l1_down = 0;
@@ -529,7 +529,7 @@
X 			    (status & UART_MSR_DCD))
X 				hardpps();
X #endif
-	}
+		}
X 		if (status & UART_MSR_DCTS)
X 			icount->cts++;
X 		wake_up_interruptible(&info->delta_msr_wait);
@@ -775,7 +775,7 @@
X 	/*
X 	 * Allocate the IRQ if necessary
X 	 */
-	if (info->kbd_node || info->ms_node) {
+	if (info->port_type != SU_PORT_PORT) {
X 		retval = request_irq(info->irq, su_kbd_ms_interrupt,
X 				     SA_SHIRQ, info->name, info);
X 	} else {
@@ -956,7 +956,7 @@
X 	int		bits;
X 	unsigned long	flags;
X 
-	if (!info->kbd_node && !info->ms_node) {
+	if (info->port_type == SU_PORT_PORT) {
X 		if (!info->tty || !info->tty->termios)
X 			return;
X 		if (!info->port)
@@ -1133,9 +1133,9 @@
X 	struct su_struct *info = su_table;
X 	int lsr;
X 
-	if (!info->kbd_node)
+	if (!info->port_type != SU_PORT_KBD)
X 		++info;
-	if (!info)
+	if (!info->port_type != SU_PORT_KBD)
X 		return;
X 
X 	do {
@@ -1151,9 +1151,9 @@
X {
X 	struct su_struct *info = su_table;
X 
-	if (!info->ms_node)
+	if (!info->port_type != SU_PORT_MS)
X 		++info;
-	if (!info)
+	if (!info->port_type != SU_PORT_MS)
X 		return;
X 
X 	info->cflag &= ~(CBAUDEX | CBAUD);
@@ -2202,9 +2202,9 @@
X 
X /*
X  * ---------------------------------------------------------------------
- * su_init() and friends
+ * su_XXX_init() and friends
X  *
- * su_init() is called at boot-time to initialize the serial driver.
+ * su_XXX_init() is called at boot-time to initialize the serial driver.
X  * ---------------------------------------------------------------------
X  */
X 
@@ -2215,7 +2215,7 @@
X  */
X __initfunc(static __inline__ void show_su_version(void))
X {
-	char *revision = "$Revision: 1.19 $";
+	char *revision = "$Revision: 1.20 $";
X 	char *version, *p;
X 
X 	version = strchr(revision, ' ');
@@ -2226,8 +2226,8 @@
X }
X 
X /*
- * This routine is called by su_init() to initialize a specific serial
- * port.  It determines what type of UART chip this serial port is
+ * This routine is called by su_{serial|kbd_ms}_init() to initialize a specific
+ * serial port.  It determines what type of UART chip this serial port is
X  * using: 8250, 16450, 16550, 16550A.  The important question is
X  * whether or not this UART is a 16550A, since this will determine
X  * whether or not we can use its FIFO features.
@@ -2236,38 +2236,42 @@
X autoconfig(struct su_struct *info)
X {
X 	unsigned char status1, status2, scratch, scratch2;
-#ifdef __sparc_v9__
X 	struct linux_ebus_device *dev = 0;
X 	struct linux_ebus *ebus;
-#else
+#ifndef __sparc_v9__
X 	struct linux_prom_registers reg0;
X #endif
X 	unsigned long flags;
X 
-#ifdef __sparc_v9__
+	if (!info->port_node || !info->port_type)
+		return;
+
+	/*
+	 * First we look for Ebus-bases su's
+	 */
X 	for_each_ebus(ebus) {
X 		for_each_ebusdev(dev, ebus) {
-			if (!strncmp(dev->prom_name, "su", 2)) {
-				if (dev->prom_node == info->kbd_node)
-					goto ebus_done;
-				if (dev->prom_node == info->ms_node)
-					goto ebus_done;
+			if (dev->prom_node == info->port_node) {
+				info->port = dev->base_address[0];
+#ifdef __sparc_v9__
+				if (check_region(info->port, 8))
+					return;
+#endif
+				info->irq = dev->irqs[0];
+				goto ebus_done;
X 			}
X 		}
X 	}
-ebus_done:
-	if (!dev)
-		return;
-
-	info->port = dev->base_address[0];
-	if (check_region(info->port, 8))
-		return;
X 
-	info->irq = dev->irqs[0];
+#ifdef __sparc_v9__
+	/*
+	 * Not on Ebus, bailing.
+	 */
+	return;
X #else
-	if (!info->port_node)
-		return;
-
+	/*
+	 * Not on Ebus, must be OBIO.
+	 */
X 	if (prom_getproperty(info->port_node, "reg",
X 	    (char *)®0, sizeof(reg0)) == -1) {
X 		prom_printf("su: no \"reg\" property\n");
@@ -2279,21 +2283,24 @@
X 		prom_printf("su: cannot map\n");
X 		return;
X 	}
+
X 	/*
-	 * There is no intr property on MrCoffee, so hardwire it. Krups?
+	 * There is no intr property on MrCoffee, so hardwire it.
X 	 */
X 	info->irq = IRQ_4M(13);
X #endif
X 
-#ifdef DEBUG_SERIAL_OPEN
-	printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
-	       __irq_itoa(dev->irqs[0]));
+ebus_done:
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Found 'su' at %016lx IRQ %s\n", info->port,
+		__irq_itoa(info->irq));
X #endif
X 
X 	info->magic = SERIAL_MAGIC;
X 
X 	save_flags(flags); cli();
-	
+
X 	/*
X 	 * Do a simple existence test first; if we fail this, there's
X 	 * no point trying anything else.
@@ -2312,17 +2319,20 @@
X 		return;		/* We failed; there's nothing here */
X 	}
X 
-#if 0 /* P3: This does not work on MrCoffee. OUT2 is 0x80 - should work... */
X 	scratch = serial_inp(info, UART_MCR);
X 	serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
X 	serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
X 	status1 = serial_inp(info, UART_MSR) & 0xF0;
X 	serial_outp(info, UART_MCR, scratch);
X 	if (status1 != 0x90) {
+		/*
+		 * This code fragment used to fail, now it fixed itself.
+		 * We keep the printout for a case.
+		 */
+		printk("su: loopback returned status 0x%02x\n", status1);
X 		restore_flags(flags);
X 		return;
X 	} 
-#endif
X 
X 	scratch2 = serial_in(info, UART_LCR);
X 	serial_outp(info, UART_LCR, 0xBF);	/* set up for StarTech test */
@@ -2389,10 +2399,7 @@
X 		return;
X 	}
X 
-	if (info->kbd_node || info->ms_node)
-		sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
-	else
-		strcpy(info->name, "su(serial)");
+	sprintf(info->name, "su(%s)", su_typev[info->port_type]);
X 
X #ifdef __sparc_v9__
X 	request_region(info->port, 8, info->name);
@@ -2494,13 +2501,16 @@
X 		info->tqueue.routine = do_softint;
X 		info->tqueue.data = info;
X 		info->cflag = serial_driver.init_termios.c_cflag;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+		init_waitqueue_head(&info->delta_msr_wait);
X 
X 		autoconfig(info);
X 		if (info->type == PORT_UNKNOWN)
X 			continue;
X 
-		printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
-		       info->name, info->port, __irq_itoa(info->irq),
+		printk(KERN_INFO "%s at 0x%lx (tty %d irq %s) is a %s\n",
+		       info->name, (long)info->port, i, __irq_itoa(info->irq),
X 		       uart_config[info->type].name);
X 	}
X 
@@ -2519,11 +2529,15 @@
X 		info->type = PORT_UNKNOWN;
X 		info->baud_base = BAUD_BASE;
X 
-		if (info->kbd_node)
+		if (info->port_type == SU_PORT_KBD)
X 			info->cflag = B1200 | CS8 | CLOCAL | CREAD;
X 		else
X 			info->cflag = B4800 | CS8 | CLOCAL | CREAD;
X 
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+		init_waitqueue_head(&info->delta_msr_wait);
+
X 		autoconfig(info);
X 		if (info->type == PORT_UNKNOWN)
X 			continue;
@@ -2533,7 +2547,7 @@
X 		       uart_config[info->type].name);
X 
X 		startup(info);
-		if (info->kbd_node)
+		if (info->port_type == SU_PORT_KBD)
X 			keyboard_zsinit(su_put_char_kbd);
X 		else
X 			sun_mouse_zsinit();
@@ -2541,154 +2555,126 @@
X 	return 0;
X }
X 
-__initfunc(int su_probe (unsigned long *memory_start))
+/*
+ * We got several platforms which present 'su' in different parts
+ * of device tree. 'su' may be found under obio, ebus, isa and pci.
+ * We walk over the tree and find them wherever PROM hides them.
+ */
+__initfunc(void su_probe_any(struct su_probe_scan *t, int sunode))
X {
-	struct su_struct *info = su_table;
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 11'
echo 'File patch-2.3.6 is continued in part 12'
echo 12 > _shar_seq_.tmp
exit 0
#!/bin/sh
# this is part 13 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 13; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
X         p->needsdtr_copy |= (1<<tindex);
X 
-        if (p->flags & AHC_SEEPROM_FOUND)
+        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+        if (p->transinfo[tindex].user_offset)
X         {
-          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-          p->transinfo[tindex].goal_offset = p->transinfo[tindex].user_offset;
-        }
-        else
-        {
-          if (p->features & AHC_ULTRA2)
-          {
-            p->transinfo[tindex].goal_period =
-              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
-          }
-          else if (p->features & AHC_ULTRA)
-          {
-            p->transinfo[tindex].goal_period =
-              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
-          }
-          else
-          {
-            p->transinfo[tindex].goal_period =
-              aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
-          }
X           if (p->features & AHC_ULTRA2)
X             p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
X           else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
@@ -2952,14 +2931,57 @@
X         p->needsdtr_copy &= ~(1<<tindex);
X         p->transinfo[tindex].goal_period = 0;
X         p->transinfo[tindex].goal_offset = 0;
+        p->transinfo[tindex].goal_options = 0;
+      }
+      if ( (buffer[2] & SCSI_VERSION_BITS) == 3 )
+      {
+        p->dev_flags[tindex] |= DEVICE_SCSI_3;
+        /*
+         * OK, we are a SCSI 3 device and we are in need of negotiation.
+         * Use PPR messages instead of WDTR and SDTR messages.
+         */
+        if ( (p->needsdtr & (1<<tindex)) ||
+             (p->needwdtr & (1<<tindex)) )
+        {
+          p->needppr |= (1<<tindex);
+          p->needppr_copy |= (1<<tindex);
+        }
+        p->needwdtr &= ~(1<<tindex);
+        p->needwdtr_copy &= ~(1<<tindex);
+        p->needsdtr &= ~(1<<tindex);
+        p->needsdtr_copy &= ~(1<<tindex);
+      }
+      /*
+       * Get the INQUIRY checksum.  We use this on Ultra 160/m
+       * and older devices both.  It allows us to drop speed on any bus type
+       * while at the same time giving us the needed domain validation for
+       * Ultra 160/m
+       *
+       * Note: We only get the checksum and set the SCANNED bit if this is
+       * one of our dtr commands.  If we don't do this, then we end up
+       * getting bad checksum results on the mid-level SCSI code's INQUIRY
+       * commands.
+       */
+      if(p->dev_dtr_cmnd[tindex] == cmd) {
+        unsigned int checksum = 0;
+        int *ibuffer;
+        int i=0;
+
+        ibuffer = (int *)buffer;
+        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
+        {
+          checksum += ibuffer[i];
+        }
+        p->dev_checksum[tindex] = checksum;
+        p->dev_flags[tindex] |= DEVICE_SCANNED;
+        p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
X       }
-      p->dev_flags[tindex] |= DEVICE_SCANNED;
-      p->dev_flags[tindex] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
X #undef WIDE_INQUIRY_BITS
X #undef SYNC_INQUIRY_BITS
+#undef SCSI_VERSION_BITS
X     }
X   }
-  else if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
X   {
X     unsigned short mask;
X     int message_error = FALSE;
@@ -2979,11 +3001,11 @@
X 
X     if (scb->flags & SCB_MSGOUT_WDTR)
X     {
-      p->wdtr_pending &= ~mask;
+      p->dtr_pending &= ~mask;
X       if (message_error)
X       {
X         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
X         {
X           printk(INFO_LEAD "Device failed to complete Wide Negotiation "
X             "processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -2991,7 +3013,6 @@
X             "disabling future\n", p->host_no, CTL_OF_SCB(scb));
X           printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
X             CTL_OF_SCB(scb));
-          p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
X         }
X         p->needwdtr &= ~mask;
X         p->needwdtr_copy &= ~mask;
@@ -2999,11 +3020,11 @@
X     }
X     if (scb->flags & SCB_MSGOUT_SDTR)
X     {
-      p->sdtr_pending &= ~mask;
+      p->dtr_pending &= ~mask;
X       if (message_error)
X       {
X         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
X         {
X           printk(INFO_LEAD "Device failed to complete Sync Negotiation "
X             "processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -3011,12 +3032,38 @@
X             "disabling future\n", p->host_no, CTL_OF_SCB(scb));
X           printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
X             CTL_OF_SCB(scb));
-          p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
X         }
X         p->needsdtr &= ~mask;
X         p->needsdtr_copy &= ~mask;
X       }
X     }
+    if (scb->flags & SCB_MSGOUT_PPR)
+    {
+      p->dtr_pending &= ~mask;
+      if(message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Parallel Protocol "
+            "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Parallel Protocol Request negotiation to this "
+            "device.\n", p->host_no, CTL_OF_SCB(scb));
+        }
+        /*
+         * Disable PPR negotiation and revert back to WDTR and SDTR setup
+         */
+        p->needppr &= ~mask;
+        p->needppr_copy &= ~mask;
+        p->needsdtr |= mask;
+        p->needsdtr_copy |= mask;
+        p->needwdtr |= mask;
+        p->needwdtr_copy |= mask;
+      }
+    }
X   }
X   queue_depth = p->dev_temp_queue_depth[tindex];
X   if (queue_depth >= p->dev_active_cmds[tindex])
@@ -3058,16 +3105,6 @@
X   p->dev_active_cmds[tindex]--;
X   p->activescbs--;
X 
-  /*
-   * If this was an untagged I/O, unbusy the target so the sequencer won't
-   * mistake things later
-   */
-  if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
-      scb->hscb->tag)
-  {
-    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
-  }
-
X   {
X     int actual;
X 
@@ -3122,7 +3159,7 @@
X #endif /* AIC7XXX_PROC_STATS */
X       }
X #ifdef AIC7XXX_PROC_STATS
-      x = -10;
+      x = -11;
X       while(actual)
X       {
X         actual >>= 1;
@@ -3429,11 +3466,10 @@
X       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
X         printk(INFO_LEAD "Cleaning up status information "
X           "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
X       if ( tag == SCB_LIST_NULL )
X       {
-        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR |
-                           DEVICE_RESET_DELAY;
+        p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
X         p->dev_expires[i] = jiffies + (4 * HZ);
X         p->dev_timer_active |= (0x01 << i);
X         p->dev_last_queue_full_count[i] = 0;
@@ -3625,7 +3661,7 @@
X   if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
X     printk(INFO_LEAD "Cleaning disconnected scbs "
X       "list.\n", p->host_no, channel, target, lun);
-  if (p->features & AHC_PAGESCBS)
+  if (p->flags & AHC_PAGESCBS)
X   {
X     unsigned char next, prev, scb_index;
X 
@@ -3641,14 +3677,14 @@
X         printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
X           "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
X           p->scb_data->numscbs);
-        next = aic7xxx_rem_scb_from_disc_list(p, next);
+        next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
X       }
X       else
X       {
X         scbp = p->scb_data->scb_array[scb_index];
X         if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
X         {
-          next = aic7xxx_rem_scb_from_disc_list(p, next);
+          next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
X           if (scbp->flags & SCB_WAITINGQ)
X           {
X             p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
@@ -3677,7 +3713,7 @@
X    * Walk the free list making sure no entries on the free list have
X    * a valid SCB_TAG value or SCB_CONTROL byte.
X    */
-  if (p->features & AHC_PAGESCBS)
+  if (p->flags & AHC_PAGESCBS)
X   {
X     unsigned char next;
X 
@@ -3734,7 +3770,6 @@
X     {
X       aic_outb(p, SCB_LIST_NULL, SCB_TAG);
X       aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
-      aic_outb(p, SCB_LIST_NULL, SCB_PREV);
X       aic_outb(p, 0, SCB_CONTROL);
X       aic7xxx_add_curscb_to_free_list(p);
X     }
@@ -3863,28 +3898,35 @@
X   if (channel == 1)
X   {
X     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
-    p->sdtr_pending &= 0x00FF;
+    p->dtr_pending &= 0x00FF;
X     offset_min = 8;
X     offset_max = 16;
X   }
X   else
X   {
-    if (p->features & AHC_WIDE)
+    if (p->features & AHC_TWIN)
X     {
-      p->needsdtr = p->needsdtr_copy;
-      p->needwdtr = p->needwdtr_copy;
-      p->sdtr_pending = 0x0;
-      p->wdtr_pending = 0x0;
+      /* Channel A */
+      p->needsdtr |= (p->needsdtr_copy & 0x00FF);
+      p->dtr_pending &= 0xFF00;
X       offset_min = 0;
-      offset_max = 16;
+      offset_max = 8;
X     }
X     else
X     {
-      /* Channel A */
-      p->needsdtr |= (p->needsdtr_copy & 0x00FF);
-      p->sdtr_pending &= 0xFF00;
+      p->needppr = p->needppr_copy;
+      p->needsdtr = p->needsdtr_copy;
+      p->needwdtr = p->needwdtr_copy;
+      p->dtr_pending = 0x0;
X       offset_min = 0;
-      offset_max = 8;
+      if (p->features & AHC_WIDE)
+      {
+        offset_max = 16;
+      }
+      else
+      {
+        offset_max = 8;
+      }
X     }
X   }
X 
@@ -4188,6 +4230,30 @@
X 
X /*+F*************************************************************************
X  * Function:
+ *   aic7xxx_construct_ppr
+ *
+ * Description:
+ *   Build up a Parallel Protocol Request message for use with SCSI-3
+ *   devices.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int tindex = TARGET_INDEX(scb->cmd);
+
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period;
+  p->msg_buf[p->msg_index++] = 0;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options;
+  p->msg_len += 8;
+}
+
+/*+F*************************************************************************
+ * Function:
X  *   aic7xxx_construct_sdtr
X  *
X  * Description:
@@ -4304,10 +4370,10 @@
X   /*
X    * Go back to async/narrow transfers and renegotiate.
X    */
+  p->needppr |= (p->needppr_copy & targ_mask);
X   p->needsdtr |= (p->needsdtr_copy & targ_mask);
X   p->needwdtr |= (p->needwdtr_copy & targ_mask);
-  p->sdtr_pending &= ~targ_mask;
-  p->wdtr_pending &= ~targ_mask;
+  p->dtr_pending &= ~targ_mask;
X   aic_outb(p, 0, TARG_SCSIRATE + tindex);
X   if (p->features & AHC_ULTRA2)
X     aic_outb(p, 0, TARG_OFFSET + tindex);
@@ -4315,7 +4381,7 @@
X   if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
X     printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
X       target, -1);
-  aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
X }
X 
X /*+F*************************************************************************
@@ -4360,6 +4426,8 @@
X                p->host_no, channel, target, lun,
X                aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
X                (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+        if (aic7xxx_panic_on_abort)
+          aic7xxx_panic_abort(p, NULL);
X       }
X       break;
X 
@@ -4387,7 +4455,7 @@
X             lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
X 
X         aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
-        aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, TRUE);
X 
X       }
X       break;
@@ -4517,7 +4585,7 @@
X                   aic7xxx_reset_device(p, target, channel, lun, i);
X                   reset++;
X                 }
-                aic7xxx_run_done_queue(p, FALSE);
+                aic7xxx_run_done_queue(p, TRUE);
X               }
X             }
X             aic7xxx_verbose = old_verbose;
@@ -4533,6 +4601,51 @@
X             aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
X           }
X         }
+        else if (scb->flags & SCB_MSGOUT_PPR)
+        {
+          /*
+           * As per the draft specs, any device capable of supporting any of
+           * the option values other than 0 are not allowed to reject the
+           * PPR message.  Instead, they must negotiate out what they do
+           * support instead of rejecting our offering.
+           */
+          p->needppr &= ~target_mask;
+          p->needppr_copy &= ~target_mask;
+          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+            (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+          p->transinfo[tindex].goal_options = 0;
+          p->dtr_pending &= ~target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting PPR messages, falling "
+              "back.\n", p->host_no, channel, target, lun);
+          }
+          if ( p->transinfo[tindex].goal_width )
+          {
+            p->needwdtr |= target_mask;
+            p->needwdtr_copy |= target_mask;
+            p->dtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_WDTR;
+          }
+          if ( p->transinfo[tindex].goal_offset )
+          {
+            p->needsdtr |= target_mask;
+            p->needsdtr_copy |= target_mask;
+            if( !(p->dtr_pending & target_mask) )
+            {
+              p->dtr_pending |= target_mask;
+              scb->flags |= SCB_MSGOUT_SDTR;
+            }
+          }
+          if ( p->dtr_pending & target_mask )
+          {
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+        }
X         else if (scb->flags & SCB_MSGOUT_WDTR)
X         {
X           /*
@@ -4540,20 +4653,18 @@
X            */
X           p->needwdtr &= ~target_mask;
X           p->needwdtr_copy &= ~target_mask;
-          p->wdtr_pending &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
X           scb->flags &= ~SCB_MSGOUT_BITS;
X           aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
X             (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
-          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
X                                AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-          if ( (p->needsdtr_copy & target_mask) &&
-               !(p->sdtr_pending & target_mask) )
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
X           {
-            p->sdtr_pending |= target_mask;
-            scb->flags |= SCB_MSGOUT_SDTR;
-            aic_outb(p, HOST_MSG, MSG_OUT);
-            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+            printk(INFO_LEAD "Device is rejecting WDTR messages, using "
+              "narrow transfers.\n", p->host_no, channel, target, lun);
X           }
+          p->needsdtr |= (p->needsdtr_copy & target_mask);
X         }
X         else if (scb->flags & SCB_MSGOUT_SDTR)
X         {
@@ -4562,10 +4673,15 @@
X           */
X           p->needsdtr &= ~target_mask;
X           p->needsdtr_copy &= ~target_mask;
-          p->sdtr_pending &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
X           scb->flags &= ~SCB_MSGOUT_SDTR;
-          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
X             (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting SDTR messages, using "
+              "async transfers.\n", p->host_no, channel, target, lun);
+          }
X         }
X         else if (aic7xxx_verbose & VERBOSE_SEQINT)
X         {
@@ -4681,41 +4797,24 @@
X                  * However, if this SCB already was attempting to negotiate,
X                  * then we assume this isn't the problem and skip this part.
X                  */
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
X                 if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
X                      (p->dev_flags[tindex] & DEVICE_SCANNED) &&
-                     !(p->wdtr_pending & target_mask) && 
-                     !(p->sdtr_pending & target_mask) )
+                     !(p->dtr_pending & target_mask) ) 
X                 {
+                  p->needppr |= (p->needppr_copy & target_mask);
X                   p->needwdtr |= (p->needwdtr_copy & target_mask);
X                   p->needsdtr |= (p->needsdtr_copy & target_mask);
X                 }
-                else if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) ||
-                          (scb->cmd == p->dev_sdtr_cmnd[tindex]) )
+                else if ( scb->cmd == p->dev_dtr_cmnd[tindex] )
X                 {
X                   /*
X                    * This is already a negotiation command, so we must have
-                   * already done either WDTR or SDTR (or maybe both).  So
-                   * we simply check sdtr_pending and needsdtr to see if we
-                   * should throw out SDTR on this command.
-                   *
-                   * Note: Don't check the needsdtr_copy here, instead just
-                   * check to see if WDTR wiped out our SDTR and set needsdtr.
-                   * Even if WDTR did wipe out SDTR and set needsdtr, if
-                   * parse_msg() then turned around and started our SDTR
-                   * in back to back fasion, then conclusion of that should
-                   * have negated any needsdtr setting.  That's why we only
-                   * check needsdtr and sdtr_pending.
+                   * already done PPR, WDTR or SDTR.  Since our negotiation
+                   * could have gotten rejected, we don't really know the
+                   * full state of things.  Don't do anything here, and allow
+                   * the negotiation_complete() handler to do the right
+                   * thing.
X                    */
-                  scb->flags &= ~SCB_MSGOUT_BITS;
-                  if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) &&
-                       !(p->sdtr_pending & target_mask) &&
-                       (p->needsdtr & target_mask) )
-                  {
-                    p->sdtr_pending |= target_mask;
-                    hscb->control |= MK_MESSAGE;
-                    scb->flags |= SCB_MSGOUT_SDTR;
-                  }
X 
X                   /*
X                    * This is the important part though.  We are getting sense
@@ -4736,43 +4835,13 @@
X                     hscb->data_pointer = scb->sg_list[0].address;
X                   }
X                 }
-#else
-                if (  (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
-                     !(scb->flags & SCB_MSGOUT_BITS) && 
-                      (scb->cmd->lun == 0) &&
-                      (p->dev_flags[TARGET_INDEX(scb->cmd)] & DEVICE_SCANNED) )
-                {
-                  if ( (p->needwdtr_copy & target_mask) &&
-                      !(p->wdtr_pending & target_mask) &&
-                      !(p->sdtr_pending & target_mask) )
-                  {
-                    p->needwdtr |= target_mask;
-                    p->wdtr_pending |= target_mask;
-                    hscb->control |= MK_MESSAGE;
-                    scb->flags |= SCB_MSGOUT_WDTR;
-                  }
-                  if ( p->needsdtr_copy & target_mask )
-                  {
-                    p->needsdtr |= target_mask;
-                    if ( !(p->wdtr_pending & target_mask) &&
-                         !(p->sdtr_pending & target_mask) )
-                    {
-                      p->sdtr_pending |= target_mask;
-                      hscb->control |= MK_MESSAGE;
-                      scb->flags |= SCB_MSGOUT_SDTR;
-                    }
-                  }
-                }
-                else
-                  scb->flags &= ~SCB_MSGOUT_BITS;
-#endif /* AIC7XXX_FAKE_NEGOTIATION_CMDS */
X                 scb->flags |= SCB_SENSE;
X                 /*
X                  * Ensure the target is busy since this will be an
X                  * an untagged request.
X                  */
X #ifdef AIC7XXX_VERBOSE_DEBUGGING
-                if (aic7xxx_verbose > 0xffff)
+                if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
X                 {
X                   if (scb->flags & SCB_MSGOUT_BITS)
X                     printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
@@ -4914,7 +4983,8 @@
X                 }
X               }
X #ifdef AIC7XXX_VERBOSE_DEBUGGING
-              if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+              if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
+                  (aic7xxx_verbose > 0xffff) )
X               {
X                 if (queue_flag)
X                   printk(INFO_LEAD "Queue full received; queue depth %d, "
@@ -4928,8 +4998,6 @@
X #endif
X               if (queue_flag)
X               {
-                p->dev_temp_queue_depth[tindex] = 
-                  p->dev_active_cmds[tindex];
X                 if ( p->dev_last_queue_full[tindex] !=
X                      p->dev_active_cmds[tindex] )
X                 {
@@ -4951,10 +5019,28 @@
X                       p->dev_active_cmds[tindex];
X                   p->dev_last_queue_full[tindex] = 0;
X                   p->dev_last_queue_full_count[tindex] = 0;
+                  p->dev_temp_queue_depth[tindex] = 
+                    p->dev_active_cmds[tindex];
+                }
+                else if (p->dev_active_cmds[tindex] == 0)
+                {
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                  {
+                    printk(INFO_LEAD "QUEUE_FULL status received with 0 "
+                           "commands active.\n", p->host_no, CTL_OF_SCB(scb));
+                    printk(INFO_LEAD "Tagged Command Queueing disabled\n",
+                           p->host_no, CTL_OF_SCB(scb));
+                  }
+                  p->dev_max_queue_depth[tindex] = 1;
+                  p->dev_temp_queue_depth[tindex] = 1;
+                  scb->tag_action = 0;
+                  scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG);
X                 }
X                 else
X                 {
X                   p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+                  p->dev_temp_queue_depth[tindex] = 
+                    p->dev_active_cmds[tindex];
X                 }
X               }
X               break;
@@ -4989,7 +5075,7 @@
X          */
X 
X         if ( !(scb->flags & SCB_DEVICE_RESET) &&
-              (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG) &&
+              (msg_out == MSG_IDENTIFYFLAG) &&
X               (scb->hscb->control & TAG_ENB) )
X         {
X           p->msg_buf[p->msg_index++] = scb->tag_action;
@@ -5020,34 +5106,68 @@
X             printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
X               CTL_OF_SCB(scb));
X         }
-        else if (scb->flags & SCB_MSGOUT_WDTR)
+        else if (scb->flags & SCB_MSGOUT_PPR)
X         {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-          if (aic7xxx_verbose > 0xffff)
+          unsigned int max_sync, period;
+          unsigned char options = p->transinfo[tindex].goal_options;
+
+          if (p->features & AHC_ULTRA2)
+          {
+            if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+                !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+            {
+              if( (p->features & AHC_ULTRA3) &&
+                  (p->dev_flags[tindex] & DEVICE_SCSI_3) &&
+                  (p->transinfo[tindex].goal_width ==
+                   MSG_EXT_WDTR_BUS_16_BIT) &&
+                  (options != 0) )
+              {
+                max_sync = AHC_SYNCRATE_ULTRA3;
+              }
+              else
+              {
+                max_sync = AHC_SYNCRATE_ULTRA2;
+              }
+            }
+            else
+            {
+              max_sync = AHC_SYNCRATE_ULTRA;
+            }
+          }
+          else if (p->features & AHC_ULTRA)
+          {
+            max_sync = AHC_SYNCRATE_ULTRA;
+          }
+          else
+          {
+            max_sync = AHC_SYNCRATE_FAST;
+          }
+          period = p->transinfo[tindex].goal_period;
+          aic7xxx_find_syncrate(p, &period, max_sync, &options);
+          p->transinfo[tindex].goal_period = period;
+          p->transinfo[tindex].goal_options = options;
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
+                   p->host_no, CTL_OF_SCB(scb), period,
+                   p->transinfo[tindex].goal_offset,
+                   p->transinfo[tindex].goal_width, options);
+          }
+          aic7xxx_construct_ppr(p, scb);
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
X             printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
X                    CTL_OF_SCB(scb));
-#endif
-          aic7xxx_construct_wdtr(p,
-            p->transinfo[TARGET_INDEX(scb->cmd)].goal_width);
+          }
+          aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width);
X         }
X         else if (scb->flags & SCB_MSGOUT_SDTR)
X         {
X           unsigned int max_sync, period;
-          /*
-           * We need to set an accurate goal_offset instead of
-           * the ridiculously high one we default to.  We should
-           * now know if we are wide.  Plus, the WDTR code will 
-           * set our goal_offset for us as well.
-           */
-          if (p->transinfo[tindex].goal_offset)
-          {
-            if (p->features & AHC_ULTRA2)
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-            else if (p->transinfo[tindex].cur_width == MSG_EXT_WDTR_BUS_16_BIT)
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-            else
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-          }
+          unsigned char options = 0;
X           /*
X            * Now that the device is selected, use the bits in SBLKCTL and
X            * SSTAT2 to determine the max sync rate for this device.
@@ -5073,14 +5193,14 @@
X             max_sync = AHC_SYNCRATE_FAST;
X           }
X           period = p->transinfo[tindex].goal_period;
-          aic7xxx_find_syncrate(p, &period, max_sync);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-          if (aic7xxx_verbose > 0xffff)
+          aic7xxx_find_syncrate(p, &period, max_sync, &options);
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
X             printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
X                    CTL_OF_SCB(scb),
X                    p->transinfo[tindex].goal_period,
X                    p->transinfo[tindex].goal_offset);
-#endif
+          }
X           aic7xxx_construct_sdtr(p, period,
X             p->transinfo[tindex].goal_offset);
X         }
@@ -5154,15 +5274,15 @@
X #if AIC7XXX_NOT_YET 
X     case TRACEPOINT:
X       {
-        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
-          target, lun);
+        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
+               channel, target, lun);
X       }
X       break;
X 
X     case TRACEPOINT2:
X       {
-        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
-          target, lun);
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
+               channel, target, lun);
X       }
X       break;
X 
@@ -5237,7 +5357,7 @@
X       case MSG_EXT_SDTR:
X       {
X         unsigned int period, offset;
-        unsigned char maxsync, saved_offset;
+        unsigned char maxsync, saved_offset, options;
X         struct aic7xxx_syncrate *syncrate;
X         
X         if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
@@ -5253,7 +5373,13 @@
X 
X         period = p->msg_buf[3];
X         saved_offset = offset = p->msg_buf[4];
+        options = 0;
X 
+        /*
+         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+         * using the SDTR messages.  We need the PPR messages to enable the
+         * higher speeds that include things like Dual Edge clocking.
+         */
X         if (p->features & AHC_ULTRA2)
X         {
X           if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
@@ -5283,7 +5409,9 @@
X         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
X              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
X         {
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
+              !(p->needsdtr_copy & target_mask) &&
+               (p->transinfo[tindex].user_offset) )
X           {
X             /*
X              * Not only is the device starting this up, but it also hasn't
@@ -5295,38 +5423,49 @@
X              */
X             p->transinfo[tindex].goal_period =
X               p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
+            if(p->features & AHC_ULTRA2)
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+            }
+            else if (p->transinfo[tindex].cur_width)
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+            }
+            else
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+            }
X             p->needsdtr_copy |= target_mask;
X           }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive SDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
X           if ( !p->transinfo[tindex].goal_offset )
X             period = 255;
X           if ( p->transinfo[tindex].goal_period > period )
X             period = p->transinfo[tindex].goal_period;
X         }
X   
-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
+        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
X         aic7xxx_validate_offset(p, syncrate, &offset,
X                                 target_scsirate & WIDEXFER);
X         aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                             offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
X 
X         /*
-         * Did we drop to async?  If so, are we sending a reply?  If we are,
+         * Did we drop to async?  Or are we sending a reply?  If we are,
X          * then we have to make sure that the reply value reflects the proper
X          * settings so we need to set the goal values according to what
X          * we need to send.
X          */
-        if ( (offset == 0) || (offset != saved_offset) ||
+        if ( (offset != saved_offset) ||
X              ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
X               (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
X         {
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-          if ( offset == 0 )
-          {
-            p->needsdtr_copy &= ~target_mask;
-          }
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
+                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
X         }
X         
X         /*
@@ -5334,15 +5473,13 @@
X          * go async, then send an SDTR back to the target
X          */
X         p->needsdtr &= ~target_mask;
-        p->sdtr_pending &= ~target_mask;
-        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ==
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) &&
-             (offset == saved_offset) )
-        {
-          scb->flags &= ~SCB_MSGOUT_BITS;
-        }
-        else
+        p->dtr_pending &= ~target_mask;
+        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
+             (offset != saved_offset) )
X         {
+          reply = TRUE;
+          p->dtr_pending |= target_mask;
X           scb->flags &= ~SCB_MSGOUT_BITS;
X           scb->flags |= SCB_MSGOUT_SDTR;
X           aic_outb(p, HOST_MSG, MSG_OUT);
@@ -5376,12 +5513,11 @@
X             {
X               reject = TRUE;
X               if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_WDTR) ||
+                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
X                     (aic7xxx_verbose > 0xffff)) )
X               {
X                 printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
X                   p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
-                p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
X               }
X             } /* We fall through on purpose */
X             case MSG_EXT_WDTR_BUS_8_BIT:
@@ -5395,15 +5531,11 @@
X               break;
X             }
X           }
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          p->wdtr_pending &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
X           p->needwdtr &= ~target_mask;
X         }
X         else
X         {
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_WDTR;
-          reply = TRUE;
X           if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
X           {
X             /* 
@@ -5413,13 +5545,33 @@
X              */
X             p->transinfo[tindex].goal_period =
X               p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
+            if(p->transinfo[tindex].user_offset)
+            {
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( p->transinfo[tindex].user_width &&
+                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                       p->features & AHC_WIDE )
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
+            }
X             p->transinfo[tindex].goal_width =
X               p->transinfo[tindex].user_width;
X             p->needwdtr_copy |= target_mask;
X             p->needsdtr_copy |= target_mask;
X           }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive WDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
X           switch(bus_width)
X           {
X             default:
@@ -5441,8 +5593,11 @@
X               break;
X             }
X           }
+          reply = TRUE;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_WDTR;
X           p->needwdtr &= ~target_mask;
-          p->wdtr_pending &= ~target_mask;
+          p->dtr_pending |= target_mask;
X           aic_outb(p, HOST_MSG, MSG_OUT);
X           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
X         }
@@ -5456,24 +5611,211 @@
X          * supports SDTR at all.  Therefore, we check needsdtr_copy instead
X          * of needstr.
X          */
-        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
X                              AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-        if ( (p->needsdtr_copy & target_mask) &&
-            !(p->sdtr_pending & target_mask))
+        p->needsdtr |= (p->needsdtr_copy & target_mask);
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_PPR:
+      {
+        unsigned char bus_width, trans_options, new_trans_options;
+        unsigned int period, offset;
+        unsigned char maxsync, saved_offset;
+        struct aic7xxx_syncrate *syncrate;
+        
+        if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        /*
+         * If we aren't on one of the new Ultra3 cards, then reject any PPR
+         * message since we can't support any option field other than 0
+         */
+        if( !(p->features & AHC_ULTRA3) )
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        offset = saved_offset = p->msg_buf[5];
+        bus_width = p->msg_buf[6];
+        trans_options = new_trans_options = p->msg_buf[7] & 0xf;
+
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+        {
+          printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset, bus_width,
+                 trans_options);
+        }
+
+        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
X         {
-          p->needsdtr |= target_mask;
-          if ( !reject && !reply )
+          if(p->features & AHC_ULTRA3)
+          {
+            maxsync = AHC_SYNCRATE_ULTRA3;
+          }
+          else
X           {
-            scb->flags &= ~SCB_MSGOUT_WDTR;
-            if (p->transinfo[tindex].goal_period)
+            maxsync = AHC_SYNCRATE_ULTRA2;
+          }
+        }
+        else
+        {
+          maxsync = AHC_SYNCRATE_ULTRA;
+        }
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
+        {
+          reply = TRUE;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_PPR;
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+          {
+            /*
+             * Not only is the device starting this up, but it also hasn't
+             * been scanned yet, so this would likely be our TUR or our
+             * INQUIRY command at scan time, so we need to use the
+             * settings from the SEEPROM if they existed.  Of course, even
+             * if we didn't find a SEEPROM, we stuffed default values into
+             * the user settings anyway, so use those in all cases.
+             */
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            if(p->transinfo[tindex].user_offset)
X             {
-              p->sdtr_pending |= target_mask;
-              scb->flags |= SCB_MSGOUT_SDTR;
-              aic_outb(p, HOST_MSG, MSG_OUT);
-              aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( p->transinfo[tindex].user_width &&
+                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                       p->features & AHC_WIDE )
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
+            }
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
+            p->transinfo[tindex].goal_options =
+              p->transinfo[tindex].user_options;
+            p->needppr_copy |= target_mask;
+          }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive PPR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          if ( !p->transinfo[tindex].goal_offset )
+            period = 255;
+          if ( p->transinfo[tindex].goal_period > period )
+            period = p->transinfo[tindex].goal_period;
+          if ( p->transinfo[tindex].goal_options == 0 )
+            new_trans_options = 0;
+          switch(bus_width)
+          {
+            default:
+            {
+              if ( (p->features & AHC_WIDE) &&
+                   (p->transinfo[tindex].goal_width ==
+                    MSG_EXT_WDTR_BUS_16_BIT) )
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              p->needwdtr_copy &= ~target_mask;
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic7xxx_set_width(p, target, channel, lun, bus_width,
+                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+              break;
+            }
+          }
+        }
+        else
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reply = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                    (aic7xxx_verbose > 0xffff)) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              /*
+               * According to the spec, if we aren't wide, we also can't be
+               * Dual Edge so clear the options byte
+               */
+              new_trans_options = 0;
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              break;
X             }
X           }
X         }
+
+        aic7xxx_set_width(p, target, channel, lun, bus_width,
+                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
+                                         &new_trans_options);
+        aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
+        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                             offset, new_trans_options,
+                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+
+        if( (offset != saved_offset) ||
+            (trans_options != new_trans_options) ||
+            ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) )
+        {
+          aic7xxx_set_width(p, target, channel, lun, bus_width,
+                            AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                               offset, new_trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          reply = TRUE;
+        }
+        p->dtr_pending &= ~target_mask;
+        p->needppr &= ~target_mask;
+        if(reply)
+        {
+          p->dtr_pending |= target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_PPR;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
X         done = TRUE;
X         break;
X       }
@@ -5485,7 +5827,7 @@
X     } /* end of switch(p->msg_type) */
X   } /* end of if (!reject && (p->msg_len > 2)) */
X 
-  if (reject)
+  if (!reply && reject)
X   {
X     aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
X     aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
@@ -5657,12 +5999,14 @@
X     if (aic7xxx_verbose & VERBOSE_RESET)
X       printk(WARN_LEAD "Someone else reset the channel!!\n",
X            p->host_no, channel, -1, -1);
+    if (aic7xxx_panic_on_abort)
+      aic7xxx_panic_abort(p, NULL);
X     /*
X      * Go through and abort all commands for the channel, but do not
X      * reset the channel again.
X      */
X     aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
-    aic7xxx_run_done_queue(p, FALSE);
+    aic7xxx_run_done_queue(p, TRUE);
X     scb = NULL;
X   }
X   else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
@@ -5698,7 +6042,7 @@
X             CTL_OF_SCB(scb), scb->hscb->tag);
X         aic7xxx_reset_device(p, target, channel, ALL_LUNS,
X                 (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
-        aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, TRUE);
X         scb = NULL;
X         printerror = 0;
X       }
@@ -5709,6 +6053,22 @@
X         printerror = 0;
X       }
X     }
+    if ( (scb != NULL) &&
+         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+    {
+      /*
+       * This might be a SCSI-3 device that is dropping the bus due to
+       * errors and signalling that we should reduce the transfer speed.
+       * All we have to do is complete this command (since it's a negotiation
+       * command already) and the checksum routine should flag an error and
+       * reduce the speed setting and renegotiate.  We call the reset routing
+       * just to clean out the hardware from this scb.
+       */
+      printerror = 0;
+      aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
+      aic7xxx_run_done_queue(p, TRUE);
+      scb = NULL;
+    }
X     if (printerror != 0)
X     {
X       if (scb != NULL)
@@ -5724,7 +6084,12 @@
X           tag = SCB_LIST_NULL;
X         }
X         aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
-        aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, TRUE);
+      }
+      else
+      {
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+        aic7xxx_run_done_queue(p, TRUE);
X       }
X       printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
X              "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
@@ -5829,12 +6194,26 @@
X         cmd->result = 0;
X         scb = NULL;
X       }
+      if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
+      {
+        /*
+         * Turn off the needsdtr, needwdtr, and needppr bits since this device
+         * doesn't seem to exist.
+         */
+        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+      }
X     }
X     /*
X      * Restarting the sequencer will stop the selection and make sure devices
X      * are allowed to reselect in.
X      */
X     aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, CLRSELINGO, CLRSINT0);
X     aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
X     p->flags &= ~AHC_HANDLING_REQINITS;
X     aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
@@ -5868,6 +6247,8 @@
X     Scsi_Cmnd *cmd;
X     unsigned char mesg_out = MSG_NOOP;
X     unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char sstat2 = aic_inb(p, SSTAT2);
+    unsigned char tindex = TARGET_INDEX(scb->cmd);
X 
X     cmd = scb->cmd;
X     switch (lastphase)
@@ -5898,12 +6279,81 @@
X         break;
X     }
X 
-    /*
-     * A parity error has occurred during a data
-     * transfer phase. Flag it and continue.
-     */
-    printk(WARN_LEAD "Parity error during %s phase.\n",
-           p->host_no, CTL_OF_SCB(scb), phase);
+    /*
+     * A parity error has occurred during a data
+     * transfer phase. Flag it and continue.
+     */
+    if( (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && (lastphase == P_DATAIN) )
+    {
+      printk(WARN_LEAD "CRC error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
+      if(sstat2 & CRCVALERR)
+      {
+        printk(WARN_LEAD "  CRC error in intermediate CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCENDERR)
+      {
+        printk(WARN_LEAD "  CRC error in ending CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCREQERR)
+      {
+        printk(WARN_LEAD "  Target incorrectly requested a CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & DUAL_EDGE_ERROR)
+      {
+        printk(WARN_LEAD "  Dual Edge transmission error.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+    }
+    else
+    {
+      printk(WARN_LEAD "Parity error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
+    }
+
+    if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+    {
+      struct aic7xxx_syncrate *syncrate;
+      unsigned int period = p->transinfo[tindex].cur_period;
+      unsigned char options = p->transinfo[tindex].cur_options;
+      /*
+       * oops, we had a failure, lower the transfer rate and try again.  It's
+       * worth noting here that it might be wise to also check for typical
+       * wide setting on narrow cable type problems and try disabling wide
+       * instead of slowing down if those exist.  That's hard to do with simple
+       * checksums though.
+       */
+      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+      {
+        syncrate++;
+        if( (syncrate->rate[0] != NULL) &&
+            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+        {
+          p->transinfo[tindex].goal_period = syncrate->period;
+          if( !(syncrate->sxfr_ultra2 & 0x40) )
+          {
+            p->transinfo[tindex].goal_options = 0;
+          }
+        }
+        else
+        {
+          p->transinfo[tindex].goal_offset = 0;
+          p->transinfo[tindex].goal_period = 0;
+          p->transinfo[tindex].goal_options = 0;
+        }
+        p->needppr |= (p->needppr_copy & (1<<tindex));
+        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+      }
+      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
+    }
+    else
+    {
+      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
+    }
X 
X     /*
X      * We've set the hardware to assert ATN if we get a parity
@@ -6072,13 +6522,6 @@
X       printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
X       bogus = TRUE;
X     }
-    temp = aic_inb(p, SCB_PREV);
-    if ((temp != SCB_LIST_NULL) &&
-        (temp >= p->scb_data->maxhscbs))
-    {
-      printk("HSCB %d bad, SCB_PREV invalid(%d).\n", i, temp);
-      bogus = TRUE;
-    }
X     if (scb_status[i] == 0)
X       lost++;
X     if (lost > 1)
@@ -6163,7 +6606,7 @@
X     unsigned char scb_index;
X 
X #ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if(aic7xxx_verbose > 0xffff)
+    if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
X       printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
X #endif
X     
@@ -6368,7 +6811,7 @@
X  *   Determines the queue depth for a given device.  There are two ways
X  *   a queue depth can be obtained for a tagged queueing device.  One
X  *   way is the default queue depth which is determined by whether
- *   AIC7XXX_CMDS_PER_LUN is defined.  If it is defined, then it is used
+ *   AIC7XXX_CMDS_PER_DEVICE is defined.  If it is defined, then it is used
X  *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
X  *   default queue depth (dependent on the number of hardware SCBs).
X  *   The other way we determine queue depth is through the use of the
@@ -6396,7 +6839,7 @@
X   {
X     int tag_enabled = TRUE;
X 
-    default_depth = AIC7XXX_CMDS_PER_LUN;
+    default_depth = AIC7XXX_CMDS_PER_DEVICE;
X  
X     if (!(p->discenable & target_mask))
X     {
@@ -6958,7 +7401,7 @@
X   }
X   printk("\n");
X #endif
-  if (checksum != scarray[len - 1])
+  if ( (checksum != scarray[len - 1]) || (checksum == 0) )
X   {
X     return (0);
X   }
@@ -7371,7 +7814,6 @@
X       aic_outb(p, i, SCBPTR);
X       aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
X       aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
-      aic_outb(p, i - 1, SCB_PREV);  /* Set the prev pointer. */
X       aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
X       aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS);  /* no busy untagged */
X       aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
@@ -7840,6 +8282,11 @@
X    */
X   aic7xxx_loadseq(p);
X 
+  /*
+   * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
+   */
+  aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
+
X   if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
X   {
X     aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
@@ -8035,6 +8482,7 @@
X     {
X       p->transinfo[i].goal_period = 0;
X       p->transinfo[i].goal_offset = 0;
+      p->transinfo[i].goal_options = 0;
X       p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
X     }
X     DRIVER_LOCK_INIT
@@ -8090,10 +8538,14 @@
X    */
X   for (i = 0; i < MAX_TARGETS; i++)
X   {
-    if(p->dev_wdtr_cmnd[i])
-      kfree(p->dev_wdtr_cmnd[i]);
-    if(p->dev_sdtr_cmnd[i])
-      kfree(p->dev_sdtr_cmnd[i]);
+    if(p->dev_dtr_cmnd[i])
+    {
+      if(p->dev_dtr_cmnd[i]->request_buffer)
+      {
+        kfree(p->dev_dtr_cmnd[i]->request_buffer);
+      }
+      kfree(p->dev_dtr_cmnd[i]);
+    }
X   }
X 
X }
@@ -8184,14 +8636,16 @@
X     {
X       printk("aic7xxx: Using leftover BIOS values.\n");
X     }
-    if ( *sxfrctl1 & STPWEN )
+    if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
X     {
X       p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
X       sc->adapter_control &= ~CFAUTOTERM;
X       sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
X     }
X     if (aic7xxx_extended)
-      p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
+      p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+    else
+      p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
X   }
X   else
X   {
@@ -8256,8 +8710,7 @@
X    * Limit to 16 targets just in case.  The 2842 for one is known to
X    * blow the max_targets setting, future cards might also.
X    */
-  max_targets = MIN(sc->max_targets & CFMAXTARG,
-                   ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8));
+  max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
X 
X   if (have_seeprom)
X   {
@@ -8279,7 +8732,7 @@
X     mask = (0x01 << i);
X     if (!have_seeprom)
X     {
-      if(aic_inb(p, SCSISEQ) != 0)
+      if (aic_inb(p, SCSISEQ) != 0)
X       {
X         /*
X          * OK...the BIOS set things up and left behind the settings we need.
@@ -8323,7 +8776,9 @@
X         sc->device_flags[i] = CFDISC;
X         if (p->features & AHC_WIDE)
X           sc->device_flags[i] |= CFWIDEB;
-        if (p->features & AHC_ULTRA2)
+        if (p->features & AHC_ULTRA3)
+          sc->device_flags[i] |= 2;
+        else if (p->features & AHC_ULTRA2)
X           sc->device_flags[i] |= 3;
X         else if (p->features & AHC_ULTRA)
X           sc->device_flags[i] |= CFSYNCHISULTRA;
@@ -8339,20 +8794,30 @@
X     }
X     if (p->flags & AHC_NEWEEPROM_FMT)
X     {
-      if (sc->device_flags[i] & CFSYNCHISULTRA)
-      {
-        p->ultraenb |= mask;
-      }
-      else if (sc->device_flags[i] & CFNEWULTRAFORMAT)
+      if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+          !(p->features & AHC_ULTRA2) )
X       {
-        if ( ((sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03) &&
-             !(p->features & AHC_ULTRA2) )
+        /*
+         * I know of two different Ultra BIOSes that do this differently.
+         * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
+         * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s
+         * while on the IBM Netfinity 5000 they want the same thing
+         * to be something else, while flags[i] & CFXFER == 0x03 and
+         * SYNCISULTRA false should be 40MByte/s.  So, we set both to
+         * 40MByte/s and the lower speeds be damned.  People will have
+         * to select around the conversely mapped lower speeds in order
+         * to select lower speeds on these boards.
+         */
+        if ((sc->device_flags[i] & (CFXFER)) == 0x03)
X         {
X           sc->device_flags[i] &= ~CFXFER;
X           sc->device_flags[i] |= CFSYNCHISULTRA;
-          p->ultraenb |= mask;
X         }
X       }
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 13'
echo 'File patch-2.3.6 is continued in part 14'
echo 14 > _shar_seq_.tmp
exit 0
#!/bin/sh
# this is part 10 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 10; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+
+	MOD_INC_USE_COUNT;
X 
X 	/* Ready to play! */
X 	dev->tbusy = 0;
X 	dev->interrupt = 0;
X 	dev->start = 1;
X 
-	MOD_INC_USE_COUNT;
-
-	irport_start(iobase);
+	/* Change speed to make sure dongles follow us again */
+	if (idev->change_speed)
+		idev->change_speed(idev, 9600);
X 
X 	return 0;
X }
@@ -558,12 +619,12 @@
X 
X 	iobase = idev->io.iobase2;
X 
-	irport_stop(iobase);
-
X 	/* Stop device */
X 	dev->tbusy = 1;
X 	dev->start = 0;
X 
+	irport_stop(idev, iobase);
+
X 	free_irq(idev->io.irq2, idev);
X 
X 	MOD_DEC_USE_COUNT;
@@ -571,12 +632,32 @@
X 	return 0;
X }
X 
-static void irport_wait_until_sent(struct irda_device *idev)
+/*
+ * Function irport_wait_until_sent (idev)
+ *
+ *    Delay exectution until finished transmitting
+ *
+ */
+void irport_wait_until_sent(struct irda_device *idev)
X {
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(60*HZ/1000);
+	int iobase;
+
+	iobase = idev->io.iobase2;
+
+	/* Wait until Tx FIFO is empty */
+	while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+		DEBUG(2, __FUNCTION__ "(), waiting!\n");
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(MSECS_TO_JIFFIES(60));
+	}
X }
X 
+/*
+ * Function irport_is_receiving (idev)
+ *
+ *    Returns true is we are currently receiving data
+ *
+ */
X static int irport_is_receiving(struct irda_device *idev)
X {
X 	return (idev->rx_buff.state != OUTSIDE_FRAME);
@@ -635,6 +716,9 @@
X 
X MODULE_PARM(io, "1-4i");
X MODULE_PARM(irq, "1-4i");
+
+MODULE_AUTHOR("Dag Brattli <da...@cs.uit.no>");
+MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode");
X 
X /*
X  * Function cleanup_module (void)
diff -u --recursive --new-file v2.3.5/linux/drivers/net/irda/litelink.c linux/drivers/net/irda/litelink.c
--- v2.3.5/linux/drivers/net/irda/litelink.c	Mon May 31 22:28:05 1999
+++ linux/drivers/net/irda/litelink.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Stable
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Fri May  7 12:50:33 1999
- * Modified at:   Mon May 10 15:12:18 1999
+ * Modified at:   Wed May 19 07:25:15 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -33,19 +33,19 @@
X #include <linux/tty.h>
X #include <linux/sched.h>
X #include <linux/init.h>
-#include <asm/ioctls.h>
-#include <asm/uaccess.h>
X 
X #include <net/irda/irda.h>
X #include <net/irda/irmod.h>
X #include <net/irda/irda_device.h>
X #include <net/irda/dongle.h>
X 
-static void litelink_reset(struct irda_device *dev, int unused);
+#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000   /* 1 ms */
+
X static void litelink_open(struct irda_device *idev, int type);
X static void litelink_close(struct irda_device *dev);
-static void litelink_change_speed( struct irda_device *dev, int baudrate);
-static void litelink_reset(struct irda_device *dev, int unused);
+static void litelink_change_speed(struct irda_device *dev, int baudrate);
+static void litelink_reset(struct irda_device *dev);
X static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos);
X 
X /* These are the baudrates supported */
@@ -105,13 +105,13 @@
X 	irda_device_set_dtr_rts(idev, TRUE, FALSE);
X 
X 	/* Sleep a minimum of 15 us */
-	udelay(15);
+	udelay(MIN_DELAY);
X 
X 	/* Go back to normal mode */
X 	irda_device_set_dtr_rts(idev, TRUE, TRUE);
X 	
X 	/* Sleep a minimum of 15 us */
-	udelay(15);
+	udelay(MIN_DELAY);
X 	
X 	/* Cycle through avaiable baudrates until we reach the correct one */
X 	for (i=0; i<5 && baud_rates[i] != baudrate; i++) {
@@ -120,13 +120,13 @@
X 		irda_device_set_dtr_rts(idev, FALSE, TRUE);
X 		
X 		/* Sleep a minimum of 15 us */
-		udelay(15);
+		udelay(MIN_DELAY);
X 		
X 		/* Set DTR, Set RTS */
X 		irda_device_set_dtr_rts(idev, TRUE, TRUE);
X 		
X 		/* Sleep a minimum of 15 us */
-		udelay(15);
+		udelay(MIN_DELAY);
X         }
X }
X 
@@ -137,11 +137,8 @@
X  *      called with a process context!
X  *
X  */
-static void litelink_reset(struct irda_device *idev, int unused)
+static void litelink_reset(struct irda_device *idev)
X {
-	struct irtty_cb *self;
-        struct tty_struct *tty;
-
X 	ASSERT(idev != NULL, return;);
X 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
X 	
@@ -149,19 +146,19 @@
X 	irda_device_set_dtr_rts(idev, TRUE, TRUE);
X 
X 	/* Sleep a minimum of 15 us */
-	udelay(15);
+	udelay(MIN_DELAY);
X 
X 	/* Clear RTS to reset dongle */
X 	irda_device_set_dtr_rts(idev, TRUE, FALSE);
X 
X 	/* Sleep a minimum of 15 us */
-	udelay(15);
+	udelay(MIN_DELAY);
X 
X 	/* Go back to normal mode */
X 	irda_device_set_dtr_rts(idev, TRUE, TRUE);
X 	
X 	/* Sleep a minimum of 15 us */
-	udelay(15);
+	udelay(MIN_DELAY);
X 
X 	/* This dongles speed defaults to 115200 bps */
X 	idev->qos.baud_rate.value = 115200;
@@ -173,7 +170,7 @@
X  *    Initialize QoS capabilities
X  *
X  */
-static void litelink_init_qos( struct irda_device *idev, struct qos_info *qos)
+static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos)
X {
X 	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
X 	qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
diff -u --recursive --new-file v2.3.5/linux/drivers/net/irda/pc87108.c linux/drivers/net/irda/pc87108.c
--- v2.3.5/linux/drivers/net/irda/pc87108.c	Mon May 31 22:28:05 1999
+++ linux/drivers/net/irda/pc87108.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Sun May  9 12:57:46 1999
+ * Modified at:   Mon May 24 15:19:21 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>
@@ -72,7 +72,7 @@
X #define CHIP_IO_EXTENT 8
X 
X static unsigned int io[]  = { 0x2f8, ~0, ~0, ~0 };
-static unsigned int io2[] = { 0x150, 0, 0, 0};
+static unsigned int io2[] = { 0x150, 0, 0, 0 };
X static unsigned int irq[] = { 3, 0, 0, 0 };
X static unsigned int dma[] = { 0, 0, 0, 0 };
X 
@@ -98,28 +98,28 @@
X };
X 
X /* Some prototypes */
-static int  pc87108_open( int i, unsigned int iobase, unsigned int board_addr, 
-			  unsigned int irq, unsigned int dma);
+static int  pc87108_open(int i, unsigned int iobase, unsigned int board_addr, 
+			 unsigned int irq, unsigned int dma);
X #ifdef MODULE
-static int  pc87108_close( struct irda_device *idev);
+static int  pc87108_close(struct irda_device *idev);
X #endif /* MODULE */
-static int  pc87108_probe( int iobase, int board_addr, int irq, int dma);
-static void pc87108_pio_receive( struct irda_device *idev);
-static int  pc87108_dma_receive( struct irda_device *idev); 
+static int  pc87108_probe(int iobase, int board_addr, int irq, int dma);
+static void pc87108_pio_receive(struct irda_device *idev);
+static int  pc87108_dma_receive(struct irda_device *idev); 
X static int  pc87108_dma_receive_complete(struct irda_device *idev, int iobase);
-static int  pc87108_hard_xmit( struct sk_buff *skb, struct device *dev);
-static int  pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size);
-static void pc87108_dma_write( struct irda_device *idev, int iobase);
-static void pc87108_change_speed( struct irda_device *idev, int baud);
+static int  pc87108_hard_xmit(struct sk_buff *skb, struct device *dev);
+static int  pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void pc87108_dma_write(struct irda_device *idev, int iobase);
+static void pc87108_change_speed(struct irda_device *idev, int baud);
X static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void pc87108_wait_until_sent( struct irda_device *idev);
-static int  pc87108_is_receiving( struct irda_device *idev);
-static int  pc87108_read_dongle_id ( int iobase);
-static void pc87108_init_dongle_interface ( int iobase, int dongle_id);
-
-static int  pc87108_net_init( struct device *dev);
-static int  pc87108_net_open( struct device *dev);
-static int  pc87108_net_close( struct device *dev);
+static void pc87108_wait_until_sent(struct irda_device *idev);
+static int  pc87108_is_receiving(struct irda_device *idev);
+static int  pc87108_read_dongle_id (int iobase);
+static void pc87108_init_dongle_interface (int iobase, int dongle_id);
+
+static int  pc87108_net_init(struct device *dev);
+static int  pc87108_net_open(struct device *dev);
+static int  pc87108_net_close(struct device *dev);
X 
X /*
X  * Function pc87108_init ()
@@ -131,11 +131,11 @@
X {
X 	int i;
X 
-	for ( i=0; (io[i] < 2000) && (i < 4); i++) {
+	for (i=0; (io[i] < 2000) && (i < 4); i++) {
X 		int ioaddr = io[i];
X 		if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
X 			continue;
-		if (pc87108_open( i, io[i], io2[i], irq[i], dma[i]) == 0)
+		if (pc87108_open(i, io[i], io2[i], irq[i], dma[i]) == 0)
X 			return 0;
X 	}
X 	return -ENODEV;
@@ -167,29 +167,29 @@
X  *    Open driver instance
X  *
X  */
-static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr, 
-			 unsigned int irq, unsigned int dma)
+static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr, 
+			unsigned int irq, unsigned int dma)
X {
X 	struct pc87108 *self;
X 	struct irda_device *idev;
X 	int ret;
X 	int dongle_id;
X 
-	DEBUG( 0, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
X 
-	if (( dongle_id = pc87108_probe( iobase, board_addr, irq, dma)) == -1)
+	if ((dongle_id = pc87108_probe(iobase, board_addr, irq, dma)) == -1)
X 		return -1;
X 
X 	/*
X 	 *  Allocate new instance of the driver
X 	 */
-	self = kmalloc( sizeof(struct pc87108), GFP_KERNEL);
-	if ( self == NULL) {
-		printk( KERN_ERR "IrDA: Can't allocate memory for "
-			"IrDA control block!\n");
+	self = kmalloc(sizeof(struct pc87108), GFP_KERNEL);
+	if (self == NULL) {
+		printk(KERN_ERR "IrDA: Can't allocate memory for "
+		       "IrDA control block!\n");
X 		return -ENOMEM;
X 	}
-	memset( self, 0, sizeof(struct pc87108));
+	memset(self, 0, sizeof(struct pc87108));
X    
X 	/* Need to store self somewhere */
X 	dev_self[i] = self;
@@ -204,24 +204,24 @@
X         idev->io.fifo_size = 32;
X 
X 	/* Lock the port that we need */
-	ret = check_region( idev->io.iobase, idev->io.io_ext);
-	if ( ret < 0) { 
-		DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-		       idev->io.iobase);
+	ret = check_region(idev->io.iobase, idev->io.io_ext);
+	if (ret < 0) { 
+		DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+		      idev->io.iobase);
X 		/* pc87108_cleanup( self->idev);  */
X 		return -ENODEV;
X 	}
-	request_region( idev->io.iobase, idev->io.io_ext, idev->name);
+	request_region(idev->io.iobase, idev->io.io_ext, idev->name);
X 
X 	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies( &idev->qos);
+	irda_init_max_qos_capabilies(&idev->qos);
X 	
X 	/* The only value we must override it the baudrate */
X 	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
X 		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
X 	
X 	idev->qos.min_turn_time.bits = qos_mtt_bits;
-	irda_qos_bits_to_value( &idev->qos);
+	irda_qos_bits_to_value(&idev->qos);
X 	
X 	idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
X 
@@ -245,10 +245,10 @@
X 	idev->netdev.stop            = pc87108_net_close;
X 
X 	idev->io.dongle_id = dongle_id;
-	pc87108_init_dongle_interface( iobase, dongle_id);
+	pc87108_init_dongle_interface(iobase, dongle_id);
X 
X 	/* Open the IrDA device */
-	irda_device_open( idev, driver_name, self);
+	irda_device_open(idev, driver_name, self);
X 	
X 	return 0;
X }
@@ -267,15 +267,14 @@
X 
X 	DEBUG( 4, __FUNCTION__ "()\n");
X 
-	ASSERT( idev != NULL, return -1;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+	ASSERT(idev != NULL, return -1;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
X 
X         iobase = idev->io.iobase;
X 	self = (struct pc87108 *) idev->priv;
X 
X 	/* Release the PORT that this driver is using */
-	DEBUG( 4, __FUNCTION__ "(), Releasing Region %03x\n", 
-	       idev->io.iobase);
+	DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
X 	release_region(idev->io.iobase, idev->io.io_ext);
X 
X 	irda_device_close(idev);
@@ -292,22 +291,22 @@
X  *    Returns non-negative on success.
X  *
X  */
-static int pc87108_probe( int iobase, int board_addr, int irq, int dma) 
+static int pc87108_probe(int iobase, int board_addr, int irq, int dma) 
X {
X 	int version;
X 	__u8 temp=0;
X 	int dongle_id;
X 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 
X 	/* Base Address and Interrupt Control Register BAIC */
X 	outb(0, board_addr);
-	switch ( iobase) {
-	case 0x3E8: outb( 0x14, board_addr+1); break;
-	case 0x2E8: outb( 0x15, board_addr+1); break;
-	case 0x3F8: outb( 0x16, board_addr+1); break;
-	case 0x2F8: outb( 0x17, board_addr+1); break;
-	default:    DEBUG(0, __FUNCTION__ "(), invalid base_address");
+	switch (iobase) {
+	case 0x3E8: outb(0x14, board_addr+1); break;
+	case 0x2E8: outb(0x15, board_addr+1); break;
+	case 0x3F8: outb(0x16, board_addr+1); break;
+	case 0x2F8: outb(0x17, board_addr+1); break;
+	default:    ERROR(__FUNCTION__ "(), invalid base_address");
X 	}
X 	
X 	/* Control Signal Routing Register CSRT */
@@ -319,74 +318,73 @@
X 	case 9:  temp = 0x05; break;
X 	case 11: temp = 0x06; break;
X 	case 15: temp = 0x07; break;
-	default: DEBUG( 0, __FUNCTION__ "(), invalid irq");
+	default: ERROR(__FUNCTION__ "(), invalid irq");
X 	}
-	outb( 1, board_addr);
-
+	outb(1, board_addr);
+	
X 	switch (dma) {	
-	case 0: outb( 0x08+temp, board_addr+1); break;
-	case 1: outb( 0x10+temp, board_addr+1); break;
-	case 3: outb( 0x18+temp, board_addr+1); break;
+	case 0: outb(0x08+temp, board_addr+1); break;
+	case 1: outb(0x10+temp, board_addr+1); break;
+	case 3: outb(0x18+temp, board_addr+1); break;
X 	default: DEBUG( 0, __FUNCTION__ "(), invalid dma");
X 	}
X 
X 	/* Mode Control Register MCTL */
-	outb( 2, board_addr);
-	outb( 0x03, board_addr+1);
+	outb(2, board_addr);
+	outb(0x03, board_addr+1);
X 		
X 	/* read the Module ID */
-	switch_bank( iobase, BANK3);
-	version =  inb( iobase+MID);
+	switch_bank(iobase, BANK3);
+	version = inb(iobase+MID);
X 	
X 	/* should be 0x2? */
-	if (0x20 != (version & 0xf0))
-	{
-		DEBUG( 0, __FUNCTION__ "(), Wrong chip version");	
+	if (0x20 != (version & 0xf0)) {
+		ERROR(__FUNCTION__ "(), Wrong chip version %02x\n", version);
X 		return -1;
X 	}
X 	
X 	/* Switch to advanced mode */
X 	switch_bank( iobase, BANK2);
-	outb( ECR1_EXT_SL, iobase+ECR1);
-	switch_bank( iobase, BANK0);
+	outb(ECR1_EXT_SL, iobase+ECR1);
+	switch_bank(iobase, BANK0);
X 
-	dongle_id = pc87108_read_dongle_id( iobase);
-	DEBUG( 0, __FUNCTION__ "(), Found dongle: %s\n", 
-	       dongle_types[ dongle_id]);
+	dongle_id = pc87108_read_dongle_id(iobase);
+	DEBUG(0, __FUNCTION__ "(), Found dongle: %s\n", 
+	      dongle_types[ dongle_id]);
X 	
X 	/* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
-	switch_bank( iobase, BANK0);	
-	outb( FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
+	switch_bank(iobase, BANK0);	
+	outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
X 	
X 	/* Set FIFO size to 32 */
-	switch_bank( iobase, BANK2);
-	outb( EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);	
+	switch_bank(iobase, BANK2);
+	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);	
X 
X 	/* IRCR2: FEND_MD is set */
-	switch_bank( iobase, BANK5);
-	outb( 0x2a, iobase+4);
+	switch_bank(iobase, BANK5);
+	outb(0x2a, iobase+4);
X 
X 	/* Make sure that some defaults are OK */
-	switch_bank( iobase, BANK6);
-	outb( 0x20, iobase+0); /* Set 32 bits FIR CRC */
-	outb( 0x0a, iobase+1); /* Set MIR pulse width */
-	outb( 0x0d, iobase+2); /* Set SIR pulse width */
-	outb( 0x2a, iobase+4); /* Set beginning frag, and preamble length */
+	switch_bank(iobase, BANK6);
+	outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
+	outb(0x0a, iobase+1); /* Set MIR pulse width */
+	outb(0x0d, iobase+2); /* Set SIR pulse width */
+	outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
X 
X 	/* Receiver frame length */
-	switch_bank( iobase, BANK4);
-	outb( 2048 & 0xff, iobase+6);
-	outb(( 2048 >> 8) & 0x1f, iobase+7);
+	switch_bank(iobase, BANK4);
+	outb(2048 & 0xff, iobase+6);
+	outb((2048 >> 8) & 0x1f, iobase+7);
X 
X 	/* Transmitter frame length */
-	outb( 2048 & 0xff, iobase+4);
-	outb(( 2048 >> 8) & 0x1f, iobase+5);
+	outb(2048 & 0xff, iobase+4);
+	outb((2048 >> 8) & 0x1f, iobase+5);
X 	
-	DEBUG( 0, "PC87108 driver loaded. Version: 0x%02x\n", version);
+	DEBUG(0, "PC87108 driver loaded. Version: 0x%02x\n", version);
X 
X 	/* Enable receive interrupts */
-	switch_bank( iobase, BANK0);
-	outb( IER_RXHDL_IE, iobase+IER);
+	switch_bank(iobase, BANK0);
+	outb(IER_RXHDL_IE, iobase+IER);
X 
X 	return dongle_id;
X }
@@ -409,10 +407,10 @@
X 	bank = inb( iobase+BSR);
X 
X 	/* Select Bank 7 */
-	switch_bank( iobase, BANK7);
+	switch_bank(iobase, BANK7);
X 	
X 	/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
-	outb( 0x00, iobase+7);
+	outb(0x00, iobase+7);
X 	
X 	/* ID0, 1, and 2 are pulled up/down very slowly */
X 	udelay(50);
@@ -421,16 +419,16 @@
X 	dongle_id = inb( iobase+4) & 0x0f;
X 
X #ifdef BROKEN_DONGLE_ID
-	if ( dongle_id == 0x0a)
+	if (dongle_id == 0x0a)
X 		dongle_id = 0x09;
X #endif
-
+	
X 	/* Go back to  bank 0 before returning */
-	switch_bank( iobase, BANK0);
+	switch_bank(iobase, BANK0);
X 
-	DEBUG( 0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id);
+	DEBUG(0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id);
X 
-	outb( bank, iobase+BSR);
+	outb(bank, iobase+BSR);
X 
X 	return dongle_id;
X }
@@ -443,7 +441,7 @@
X  *     power-on/reset. It also needs to be used whenever you suspect that
X  *     the dongle is changed. 
X  */
-static void pc87108_init_dongle_interface ( int iobase, int dongle_id)
+static void pc87108_init_dongle_interface (int iobase, int dongle_id)
X {
X 	int bank;
X 
@@ -818,11 +816,11 @@
X 	      iobase+ECR1);
X 	
X 	/* Enable DMA */
- 	switch_bank( iobase, BANK0);	
-	outb( inb( iobase+MCR)|MCR_DMA_EN, iobase+MCR);
+ 	switch_bank(iobase, BANK0);	
+	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
X 
X 	/* Restore bank register */
-	outb( bsr, iobase+BSR);
+	outb(bsr, iobase+BSR);
X }
X 
X /*
@@ -832,7 +830,7 @@
X  *    got transfered
X  *
X  */
-static int pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size)
+static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
X {
X 	int actual = 0;
X 	__u8 bank;
@@ -851,16 +849,16 @@
X 	}
X 
X 	/* Fill FIFO with current frame */
-	while (( fifo_size-- > 0) && (actual < len)) {
+	while ((fifo_size-- > 0) && (actual < len)) {
X 		/* Transmit next byte */
-		outb( buf[actual++], iobase+TXD);
+		outb(buf[actual++], iobase+TXD);
X 	}
X         
-	DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-	       fifo_size, actual, len);
+	DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
+	      fifo_size, actual, len);
X 
X 	/* Restore bank */
-	outb( bank, iobase+BSR);
+	outb(bank, iobase+BSR);
X 
X 	return actual;
X }
@@ -1466,6 +1464,9 @@
X MODULE_DESCRIPTION("NSC PC87108 IrDA Device Driver");
X 
X MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(io2, "1-4i");
+MODULE_PARM(irq, "1-4i");
X 
X /*
X  * Function init_module (void)
diff -u --recursive --new-file v2.3.5/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- v2.3.5/linux/drivers/net/irda/smc-ircc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/smc-ircc.c	Mon Jun  7 16:18:58 1999
@@ -0,0 +1,969 @@
+/*********************************************************************
+ *                
+ * Filename:      smc-ircc.c
+ * Version:       0.1
+ * Description:   Driver for the SMC Infrared Communications Controller (SMC)
+ * Status:        Experimental.
+ * Author:        Thomas Davis (tad...@jps.net)
+ * Created at:    
+ * Modified at:   Wed May 19 15:30:08 1999
+ * Modified by:   Dag Brattli <da...@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-1999 Thomas Davis, All Rights Reserved.
+ *      
+ *     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.
+ *  
+ *     I, Thomas Davis, admit no liability nor provide warranty for any
+ *     of this software. This material is provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Fujitsu Lifebook 635t
+ *			   Sony PCG-505TX (gets DMA wrong.)
+ *
+ ********************************************************************/
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irlap_frame.h>
+#include <net/irda/irda_device.h>
+
+#include <net/irda/smc-ircc.h>
+#include <net/irda/irport.h>
+
+static char *driver_name = "smc-ircc";
+
+#define CHIP_IO_EXTENT 8
+
+static unsigned int io[]  = { 0x2e8, 0x140, ~0, ~0 };
+static unsigned int io2[] = { 0x2f8, 0x3e8, 0, 0};
+
+static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL};
+
+/* Some prototypes */
+static int  ircc_open( int i, unsigned int iobase, unsigned int board_addr);
+static int  ircc_close( struct irda_device *idev);
+static int  ircc_probe( int iobase, int board_addr);
+static int  ircc_dma_receive( struct irda_device *idev); 
+static int  ircc_dma_receive_complete(struct irda_device *idev, int iobase);
+static int  ircc_hard_xmit( struct sk_buff *skb, struct device *dev);
+static void ircc_dma_write( struct irda_device *idev, int iobase);
+static void ircc_change_speed( struct irda_device *idev, int baud);
+static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void ircc_wait_until_sent( struct irda_device *idev);
+static int  ircc_is_receiving( struct irda_device *idev);
+
+static int  ircc_net_init( struct device *dev);
+static int  ircc_net_open( struct device *dev);
+static int  ircc_net_close( struct device *dev);
+
+static int ircc_debug=3;
+static int ircc_irq=255;
+static int ircc_dma=255;
+
+static inline void register_bank(int port, int bank)
+{
+        outb(((inb(port+UART_MASTER) & 0xF0) | (bank & 0x07)),
+             port+UART_MASTER);
+}
+
+static inline unsigned int serial_in(int port, int offset)
+{
+        return inb(port+offset);
+}
+
+static inline void serial_out(int port, int offset, int value)
+{
+        outb(value, port+offset);
+}
+
+/*
+ * Function ircc_init ()
+ *
+ *    Initialize chip. Just try to find out how many chips we are dealing with
+ *    and where they are
+ */
+__initfunc(int ircc_init(void))
+{
+	int i;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	for ( i=0; (io[i] < 2000) && (i < 4); i++) {
+		int ioaddr = io[i];
+		if (check_region(ioaddr, CHIP_IO_EXTENT))
+			continue;
+		if (ircc_open( i, io[i], io2[i]) == 0)
+			return 0;
+	}
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+	return -ENODEV;
+}
+
+/*
+ * Function ircc_cleanup ()
+ *
+ *    Close all configured chips
+ *
+ */
+#ifdef MODULE
+static void ircc_cleanup(void)
+{
+	int i;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	for ( i=0; i < 4; i++) {
+		if ( dev_self[i])
+			ircc_close( &(dev_self[i]->idev));
+	}
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+#endif /* MODULE */
+
+/*
+ * Function ircc_open (iobase, irq)
+ *
+ *    Open driver instance
+ *
+ */
+static int ircc_open( int i, unsigned int iobase, unsigned int iobase2)
+{
+	struct ircc_cb *self;
+	struct irda_device *idev;
+	int ret;
+	int config;
+
+	DEBUG( ircc_debug, __FUNCTION__ " -->\n");
+
+	if ((config = ircc_probe( iobase, iobase2)) == -1) {
+	        DEBUG(ircc_debug, 
+		      __FUNCTION__ ": addr 0x%04x - no device found!\n", iobase);
+		return -1;
+	}
+	
+	/*
+	 *  Allocate new instance of the driver
+	 */
+	self = kmalloc( sizeof(struct ircc_cb), GFP_KERNEL);
+	if ( self == NULL) {
+		printk( KERN_ERR "IrDA: Can't allocate memory for "
+			"IrDA control block!\n");
+		return -ENOMEM;
+	}
+	memset(self, 0, sizeof(struct ircc_cb));
+   
+	/* Need to store self somewhere */
+	dev_self[i] = self;
+
+	idev = &self->idev;
+
+	/* Initialize IO */
+	idev->io.iobase    = iobase;
+        idev->io.iobase2   = iobase2; /* Used by irport */
+        idev->io.irq       = config >> 4 & 0x0f;
+	if (ircc_irq < 255) {
+	        printk(KERN_INFO "smc: Overriding IRQ - chip says %d, using %d\n",
+		      idev->io.irq, ircc_irq);
+		idev->io.irq = ircc_irq;
+	}
+        idev->io.io_ext    = CHIP_IO_EXTENT;
+        idev->io.io_ext2   = 8;       /* Used by irport */
+        idev->io.dma       = config & 0x0f;
+	if (ircc_dma < 255) {
+	        printk(KERN_INFO "smc: Overriding DMA - chip says %d, using %d\n",
+		      idev->io.dma, ircc_dma);
+		idev->io.dma = ircc_dma;
+	}
+        idev->io.fifo_size = 16;
+
+	/* Lock the port that we need */
+	ret = check_region( idev->io.iobase, idev->io.io_ext);
+	if ( ret < 0) { 
+		DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
+		       idev->io.iobase);
+		/* ircc_cleanup( self->idev);  */
+		return -ENODEV;
+	}
+	ret = check_region( idev->io.iobase2, idev->io.io_ext2);
+	if ( ret < 0) { 
+		DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
+		       idev->io.iobase2);
+		/* ircc_cleanup( self->idev);  */
+		return -ENODEV;
+	}
+	request_region( idev->io.iobase, idev->io.io_ext, idev->name);
+        request_region( idev->io.iobase2, idev->io.io_ext2, idev->name);
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies( &idev->qos);
+	
+#if 1
+	/* The only value we must override it the baudrate */
+	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
+#else
+	/* The only value we must override it the baudrate */
+	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+		IR_115200;
+#endif
+
+	idev->qos.min_turn_time.bits = 0x07;
+	irda_qos_bits_to_value( &idev->qos);
+
+	idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO;
+	
+	/* Specify which buffer allocation policy we need */
+	idev->rx_buff.flags = GFP_KERNEL | GFP_DMA;
+	idev->tx_buff.flags = GFP_KERNEL | GFP_DMA;
+
+	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+	idev->rx_buff.truesize = 4000; 
+	idev->tx_buff.truesize = 4000;
+	
+	/* Initialize callbacks */
+	idev->change_speed    = ircc_change_speed;
+	idev->wait_until_sent = ircc_wait_until_sent;
+	idev->is_receiving    = ircc_is_receiving;
+     
+	/* Override the network functions we need to use */
+	idev->netdev.init            = ircc_net_init;
+	idev->netdev.hard_start_xmit = ircc_hard_xmit;
+	idev->netdev.open            = ircc_net_open;
+	idev->netdev.stop            = ircc_net_close;
+
+	irport_start(idev, iobase2);
+
+	/* Open the IrDA device */
+	irda_device_open( idev, driver_name, self);
+	
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return 0;
+}
+
+/*
+ * Function ircc_close (idev)
+ *
+ *    Close driver instance
+ *
+ */
+static int ircc_close( struct irda_device *idev)
+{
+	int iobase;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	ASSERT( idev != NULL, return -1;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+        iobase = idev->io.iobase;
+
+	irport_stop(idev, idev->io.iobase2);
+
+	register_bank(iobase, 0);
+	serial_out(iobase, UART_IER, 0);
+	serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+
+	register_bank(iobase, 1);
+
+        serial_out(iobase, UART_SCE_CFGA, 
+		   UART_CFGA_IRDA_SIR_A | UART_CFGA_TX_POLARITY);
+        serial_out(iobase, UART_SCE_CFGB, UART_CFGB_IR);
+ 
+	/* Release the PORT that this driver is using */
+	DEBUG( ircc_debug, 
+	       __FUNCTION__ ": releasing 0x%03x\n", idev->io.iobase);
+
+	release_region( idev->io.iobase, idev->io.io_ext);
+
+	if ( idev->io.iobase2) {
+		DEBUG( ircc_debug, __FUNCTION__ ": releasing 0x%03x\n", 
+		       idev->io.iobase2);
+		release_region( idev->io.iobase2, idev->io.io_ext2);
+	}
+
+	irda_device_close( idev);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return 0;
+}
+
+/*
+ * Function ircc_probe (iobase, board_addr, irq, dma)
+ *
+ *    Returns non-negative on success.
+ *
+ */
+static int ircc_probe( int iobase, int iobase2) 
+{
+	int version = 1;
+	int low, high, chip, config, dma, irq;
+	
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	register_bank(iobase, 3);
+	high = serial_in(iobase, UART_ID_HIGH);
+	low = serial_in(iobase, UART_ID_LOW);
+	chip = serial_in(iobase, UART_CHIP_ID);
+	version = serial_in(iobase, UART_VERSION);
+	config = serial_in(iobase, UART_INTERFACE);
+	irq = config >> 4 & 0x0f;
+	dma = config & 0x0f;
+
+	if (high == 0x10 && low == 0xb8 && chip == 0xf1) {
+		DEBUG(0, "SMC IrDA Controller found; version = %d, "
+		      "port 0x%04x, dma %d, interrupt %d\n",
+		      version, iobase, dma, irq);
+	} else {
+		return -1;
+	}
+
+	serial_out(iobase, UART_MASTER, 0);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+	return config;
+}
+
+/*
+ * Function ircc_change_speed (idev, baud)
+ *
+ *    Change the speed of the device
+ *
+ */
+static void ircc_change_speed( struct irda_device *idev, int speed)
+{
+	struct ircc_cb *self;
+	int iobase, ir_mode, select, fast; 
+
+	DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+	self = idev->priv;
+	iobase = idev->io.iobase;
+
+	/* Update accounting for new speed */
+	idev->io.baudrate = speed;
+
+	switch ( speed) {
+	case 9600:
+	case 19200:
+	case 37600:
+	case 57600:
+	case 115200:
+	        DEBUG(ircc_debug+1, 
+		      __FUNCTION__ ": using irport to change speed to %d\n",
+		      speed);
+		register_bank(iobase, 0);
+		serial_out(iobase, UART_IER, 0);
+		serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+		serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+		irport_start(idev, idev->io.iobase2);
+		irport_change_speed( idev, speed);
+		return;
+		break;
+
+	case 576000:		
+		ir_mode = UART_CFGA_IRDA_HDLC;
+		select = 0;
+		fast = 0;
+		DEBUG( ircc_debug, __FUNCTION__ ": handling baud of 576000\n");
+		break;
+	case 1152000:
+		ir_mode = UART_CFGA_IRDA_HDLC;
+		select = UART_1152;
+		fast = 0;
+		DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 1152000\n");
+		break;
+	case 4000000:
+		ir_mode = UART_CFGA_IRDA_4PPM;
+		select = 0;
+		fast = UART_LCR_A_FAST;
+		DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 4000000\n");
+		break;
+	default:
+		DEBUG( 0, __FUNCTION__ ": unknown baud rate of %d\n", speed);
+		return;
+	}
+
+#if 0
+	serial_out(idev->io.iobase2, 4, 0x08);
+#endif
+
+	serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+
+	register_bank(iobase, 0);
+	serial_out(iobase, UART_IER, 0);
+	
+       	irport_stop(idev, idev->io.iobase2);
+
+	idev->netdev.tbusy = 0;
+	
+	register_bank(iobase, 1);
+
+	serial_out(iobase, UART_SCE_CFGA, 
+		   ((serial_in(iobase, UART_SCE_CFGA) & 0x87) | ir_mode));
+
+	serial_out(iobase, UART_SCE_CFGB,
+		   ((serial_in(iobase, UART_SCE_CFGB) & 0x3f) | UART_CFGB_IR));
+
+	(void) serial_in(iobase, UART_FIFO_THRESHOLD);
+	serial_out(iobase, UART_FIFO_THRESHOLD, 64);
+
+	register_bank(iobase, 4);
+
+	serial_out(iobase, UART_CONTROL,
+		   (serial_in(iobase, UART_CONTROL) & 0x30) 
+		   | select | UART_CRC );
+
+	register_bank(iobase, 0);
+
+	serial_out(iobase, UART_LCR_A, fast);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_hard_xmit (skb, dev)
+ *
+ *    Transmit the frame!
+ *
+ */
+static int ircc_hard_xmit( struct sk_buff *skb, struct device *dev)
+{
+	struct irda_device *idev;
+	int iobase;
+	int mtt;
+
+	DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+	idev = (struct irda_device *) dev->priv;
+
+	ASSERT( idev != NULL, return 0;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+	iobase = idev->io.iobase;
+
+	DEBUG(ircc_debug+1, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len);
+
+	/* Use irport for SIR speeds */
+	if (idev->io.baudrate <= 115200) {
+		DEBUG(ircc_debug+1, __FUNCTION__ ": calling irport_hard_xmit\n");
+		return irport_hard_xmit(skb, dev);
+	}
+	
+	DEBUG(ircc_debug, __FUNCTION__ ": using dma; len=%d\n", skb->len);
+
+	/* Lock transmit buffer */
+	if (irda_lock((void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+
+	memcpy( idev->tx_buff.head, skb->data, skb->len);
+
+	/* Make sure that the length is a multiple of 16 bits */
+	if ( skb->len & 0x01)
+		skb->len++;
+
+	idev->tx_buff.len = skb->len;
+	idev->tx_buff.data = idev->tx_buff.head;
+#if 0
+	idev->tx_buff.offset = 0;
+#endif
+	
+	mtt = irda_get_mtt( skb);
+	
+	/* Use udelay for delays less than 50 us. */
+	if (mtt)
+		udelay( mtt);
+	
+	ircc_dma_write( idev, iobase);
+	
+	dev_kfree_skb( skb);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return 0;
+}
+
+/*
+ * Function ircc_dma_xmit (idev, iobase)
+ *
+ *    Transmit data using DMA
+ *
+ */
+static void ircc_dma_write( struct irda_device *idev, int iobase)
+{
+	struct ircc_cb *self;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	ASSERT( idev != NULL, return;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+	self = idev->priv;
+	iobase = idev->io.iobase;
+
+	setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
+		   DMA_MODE_WRITE);
+	
+	idev->io.direction = IO_XMIT;
+
+	serial_out(idev->io.iobase2, 4, 0x08);
+
+	register_bank(iobase, 4);
+	serial_out(iobase, UART_CONTROL, 
+		   (serial_in(iobase, UART_CONTROL) & 0xF0));
+
+	serial_out(iobase, UART_BOF_COUNT_LO, 2);
+	serial_out(iobase, UART_BRICKWALL_CNT_LO, 0);
+#if 1
+	serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, idev->tx_buff.len >> 8);
+	serial_out(iobase, UART_TX_SIZE_LO, idev->tx_buff.len & 0xff);
+#else
+	serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0);
+	serial_out(iobase, UART_TX_SIZE_LO, 0);
+#endif
+
+	register_bank(iobase, 1);
+	serial_out(iobase, UART_SCE_CFGB,
+		   serial_in(iobase, UART_SCE_CFGB) | UART_CFGB_DMA_ENABLE);
+
+	register_bank(iobase, 0);
+
+	serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME | UART_IER_EOM);
+	serial_out(iobase, UART_LCR_B,
+		   UART_LCR_B_SCE_TRANSMIT|UART_LCR_B_SIP_ENABLE);
+
+	serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_dma_xmit_complete (idev)
+ *
+ *    The transfer of a frame in finished. This function will only be called 
+ *    by the interrupt handler
+ *
+ */
+static void ircc_dma_xmit_complete( struct irda_device *idev, int underrun)
+{
+	struct ircc_cb *self;
+	int iobase, d;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	ASSERT( idev != NULL, return;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+	register_bank(idev->io.iobase, 1);
+
+	serial_out(idev->io.iobase, UART_SCE_CFGB,
+		   serial_in(idev->io.iobase, UART_SCE_CFGB) &
+		   ~UART_CFGB_DMA_ENABLE);
+
+	d = get_dma_residue(idev->io.dma);
+
+	DEBUG(ircc_debug, __FUNCTION__ ": dma residue = %d, len=%d, sent=%d\n", 
+	      d, idev->tx_buff.len, idev->tx_buff.len - d);
+
+	self = idev->priv;
+
+	iobase = idev->io.iobase;
+
+	/* Check for underrrun! */
+	if ( underrun) {
+		idev->stats.tx_errors++;
+		idev->stats.tx_fifo_errors++;		
+	} else {
+		idev->stats.tx_packets++;
+		idev->stats.tx_bytes +=  idev->tx_buff.len;
+	}
+
+	/* Unlock tx_buff and request another frame */
+	idev->netdev.tbusy = 0; /* Unlock */
+	idev->media_busy = FALSE;
+	
+	/* Tell the network layer, that we can accept more frames */
+	mark_bh( NET_BH);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_dma_receive (idev)
+ *
+ *    Get ready for receiving a frame. The device will initiate a DMA
+ *    if it starts to receive a frame.
+ *
+ */
+static int ircc_dma_receive( struct irda_device *idev) 
+{
+	struct ircc_cb *self;
+	int iobase;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	ASSERT( idev != NULL, return -1;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+	self = idev->priv;
+	iobase= idev->io.iobase;
+
+	setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, 
+		   DMA_MODE_READ);
+	
+	/* driver->media_busy = FALSE; */
+	idev->io.direction = IO_RECV;
+	idev->rx_buff.data = idev->rx_buff.head;
+#if 0
+	idev->rx_buff.offset = 0;
+#endif
+
+	register_bank(iobase, 4);
+	serial_out(iobase, UART_CONTROL, 
+		   (serial_in(iobase, UART_CONTROL) &0xF0));
+	serial_out(iobase, UART_BOF_COUNT_LO, 2);
+	serial_out(iobase, UART_BRICKWALL_CNT_LO, 0);
+	serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0);
+	serial_out(iobase, UART_TX_SIZE_LO, 0);
+	serial_out(iobase, UART_RX_SIZE_HI, 0);
+	serial_out(iobase, UART_RX_SIZE_LO, 0);
+
+	register_bank(iobase, 0);
+	serial_out(iobase, 
+		   UART_LCR_B, UART_LCR_B_SCE_RECEIVE | UART_LCR_B_SIP_ENABLE);
+	
+	register_bank(iobase, 1);
+	serial_out(iobase, UART_SCE_CFGB,
+		   serial_in(iobase, UART_SCE_CFGB) | 
+		   UART_CFGB_DMA_ENABLE | UART_CFGB_DMA_BURST);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return 0;
+}
+
+/*
+ * Function ircc_dma_receive_complete (idev)
+ *
+ *    Finished with receiving frames
+ *
+ *    
+ */
+static int ircc_dma_receive_complete( struct irda_device *idev, int iobase)
+{
+	struct sk_buff *skb;
+	struct ircc_cb *self;
+	int len, msgcnt;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	self = idev->priv;
+
+	msgcnt = serial_in(idev->io.iobase, UART_LCR_B) & 0x08;
+
+	DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
+	      get_dma_residue(idev->io.dma));
+
+	len = idev->rx_buff.truesize - get_dma_residue(idev->io.dma) - 4;
+
+	DEBUG(ircc_debug, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
+
+	skb = dev_alloc_skb( len+1);
+
+	if (skb == NULL)  {
+		printk( KERN_INFO __FUNCTION__ 
+			": memory squeeze, dropping frame.\n");
+		return FALSE;
+	}
+			
+	/* Make sure IP header gets aligned */
+	skb_reserve( skb, 1); 
+	skb_put( skb, len);
+
+	memcpy(skb->data, idev->rx_buff.data, len);
+	idev->stats.rx_packets++;
+
+	skb->dev = &idev->netdev;
+	skb->mac.raw  = skb->data;
+	skb->protocol = htons(ETH_P_IRDA);
+	netif_rx( skb);
+
+	register_bank(idev->io.iobase, 1);
+	serial_out(idev->io.iobase, UART_SCE_CFGB,
+		   serial_in(idev->io.iobase, UART_SCE_CFGB) &
+		   ~UART_CFGB_DMA_ENABLE);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return TRUE;
+}
+
+/*
+ * Function ircc_interrupt (irq, dev_id, regs)
+ *
+ *    An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int iobase, iir;
+
+	struct irda_device *idev = (struct irda_device *) dev_id;
+
+	DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+
+	if (idev == NULL) {
+		printk( KERN_WARNING "%s: irq %d for unknown device.\n", 
+			driver_name, irq);
+		return;
+	}
+	
+	if (idev->io.baudrate <= 115200) {
+		DEBUG(ircc_debug+1, __FUNCTION__ 
+		      ": routing interrupt to irport_interrupt\n");
+		return irport_interrupt( irq, dev_id, regs);
+	}
+
+	iobase = idev->io.iobase;
+
+	idev->netdev.interrupt = 1;
+
+	serial_out(iobase, UART_MASTER, 0);
+
+	register_bank(iobase, 0);
+
+	iir = serial_in(iobase, UART_IIR);
+
+	serial_out(iobase, UART_IER, 0);
+
+	DEBUG(ircc_debug, __FUNCTION__ ": iir = 0x%02x\n", iir);
+
+	if (iir & UART_IIR_EOM) {
+	        DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_EOM\n");
+		if (idev->io.direction == IO_RECV) {
+			ircc_dma_receive_complete(idev, iobase);
+		} else {
+			ircc_dma_xmit_complete(idev, iobase);
+		}
+		ircc_dma_receive(idev);
+	}
+
+	if (iir & UART_IIR_ACTIVE_FRAME) {
+	        DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_ACTIVE_FRAME\n");
+		idev->rx_buff.state = INSIDE_FRAME;
+#if 0
+		ircc_dma_receive(idev);
+#endif
+	}
+
+	if (iir & UART_IIR_RAW_MODE) {
+		DEBUG(ircc_debug, __FUNCTION__ ": IIR RAW mode interrupt.\n");
+	}
+
+	idev->netdev.interrupt = 0;
+
+	register_bank(iobase, 0);
+	serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME|UART_IER_EOM);
+	serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_wait_until_sent (idev)
+ *
+ *    This function should put the current thread to sleep until all data 
+ *    have been sent, so it is safe to change the speed.
+ */
+static void ircc_wait_until_sent( struct irda_device *idev)
+{
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	/* Just delay 60 ms */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(6);
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_is_receiving (idev)
+ *
+ *    Return TRUE is we are currently receiving a frame
+ *
+ */
+static int ircc_is_receiving( struct irda_device *idev)
+{
+	int status = FALSE;
+	/* int iobase; */
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	ASSERT( idev != NULL, return FALSE;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+
+	DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
+	      get_dma_residue(idev->io.dma));
+
+	status = ( idev->rx_buff.state != OUTSIDE_FRAME);
+	
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+	return status;
+}
+
+/*
+ * Function ircc_net_init (dev)
+ *
+ *    Initialize network device
+ *
+ */
+static int ircc_net_init( struct device *dev)
+{
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+	/* Setup to be a normal IrDA network device driver */
+	irda_device_setup( dev);
+
+	/* Insert overrides below this line! */
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return 0;
+}
+
+
+/*
+ * Function ircc_net_open (dev)
+ *
+ *    Start the device
+ *
+ */
+static int ircc_net_open( struct device *dev)
+{
+	struct irda_device *idev;
+	int iobase;
+	
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	
+	ASSERT( dev != NULL, return -1;);
+	idev = (struct irda_device *) dev->priv;
+	
+	ASSERT( idev != NULL, return 0;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+	
+	iobase = idev->io.iobase;
+
+	if (request_irq( idev->io.irq, ircc_interrupt, 0, idev->name, 
+			 (void *) idev)) {
+		return -EAGAIN;
+	}
+	/*
+	 * Always allocate the DMA channel after the IRQ,
+	 * and clean up on failure.
+	 */
+	if (request_dma(idev->io.dma, idev->name)) {
+		free_irq( idev->io.irq, idev);
+		return -EAGAIN;
+	}
+		
+	/* Ready to play! */
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* turn on interrupts */
+	
+	MOD_INC_USE_COUNT;
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return 0;
+}
+
+/*
+ * Function ircc_net_close (dev)
+ *
+ *    Stop the device
+ *
+ */
+static int ircc_net_close(struct device *dev)
+{
+	struct irda_device *idev;
+	int iobase;
+
+	DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+	
+	/* Stop device */
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	ASSERT( dev != NULL, return -1;);
+	idev = (struct irda_device *) dev->priv;
+	
+	ASSERT( idev != NULL, return 0;);
+	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+	
+	iobase = idev->io.iobase;
+
+	disable_dma( idev->io.dma);
+
+	/* Disable interrupts */
+       
+	free_irq( idev->io.irq, idev);
+	free_dma( idev->io.dma);
+
+	MOD_DEC_USE_COUNT;
+
+	DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Thomas Davis <tad...@jps.net>");
+MODULE_DESCRIPTION("SMC IrCC controller driver");
+MODULE_PARM(ircc_debug,"1i");
+MODULE_PARM(ircc_dma, "1i");
+MODULE_PARM(ircc_irq, "1i");
+
+/*
+ * Function init_module (void)
+ *
+ *    
+ *
+ */
+int init_module(void)
+{
+	return ircc_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    
+ *
+ */
+void cleanup_module(void)
+{
+	ircc_cleanup();
+}
+
+#endif
diff -u --recursive --new-file v2.3.5/linux/drivers/net/irda/tekram.c linux/drivers/net/irda/tekram.c
--- v2.3.5/linux/drivers/net/irda/tekram.c	Mon May 31 22:28:05 1999
+++ linux/drivers/net/irda/tekram.c	Mon Jun  7 16:18:58 1999
@@ -1,12 +1,12 @@
X /*********************************************************************
X  *                
X  * Filename:      tekram.c
- * Version:       1.1
+ * Version:       1.2
X  * Description:   Implementation of the Tekram IrMate IR-210B dongle
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Mon May 10 16:10:17 1999
+ * Modified at:   Sun May 16 14:33:42 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -28,16 +28,12 @@
X #include <linux/sched.h>
X #include <linux/init.h>
X 
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
X #include <net/irda/irda.h>
X #include <net/irda/irda_device.h>
X #include <net/irda/irtty.h>
X #include <net/irda/dongle.h>
X 
-static void tekram_reset(struct irda_device *dev, int unused);
+static void tekram_reset(struct irda_device *dev);
X static void tekram_open(struct irda_device *dev, int type);
X static void tekram_close(struct irda_device *dev);
X static void tekram_change_speed(struct irda_device *dev, int baud);
@@ -49,7 +45,7 @@
X #define TEKRAM_19200  0x03
X #define TEKRAM_9600   0x04
X 
-#define TEKRAM_PW 0x10 /* Pulse select bit */
+#define TEKRAM_PW     0x10 /* Pulse select bit */
X 
X static struct dongle dongle = {
X 	TEKRAM_DONGLE,
@@ -112,7 +108,7 @@
X 
X 	ASSERT(idev != NULL, return;);
X 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-	
+
X 	switch (baud) {
X 	default:
X 	case 9600:
@@ -121,7 +117,7 @@
X 	case 19200:
X 		byte = TEKRAM_PW|TEKRAM_19200;
X 		break;
-	case 34800:
+	case 38400:
X 		byte = TEKRAM_PW|TEKRAM_38400;
X 		break;
X 	case 57600:
@@ -132,6 +128,9 @@
X 		break;
X 	}
X 
+	/* Need to reset the dongle and go to 9600 bps before programming */
+	tekram_reset(idev);
+	
X 	/* Set DTR, Clear RTS */
X 	irda_device_set_dtr_rts(idev, TRUE, FALSE);
X 	
@@ -162,7 +161,7 @@
X  *        3. clear DTR to SPACE state, wait at least 50 us for further 
X  *         operation
X  */
-void tekram_reset(struct irda_device *idev, int unused)
+void tekram_reset(struct irda_device *idev)
X {
X 	ASSERT(idev != NULL, return;);
X 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
@@ -185,8 +184,10 @@
X 	irda_device_set_dtr_rts(idev, TRUE, TRUE);
X 	
X 	udelay(50);
-
-	/* Finished! */
+	
+	/* Make sure the IrDA chip also goes to defalt speed */
+	if (idev->change_speed)
+		idev->change_speed(idev, 9600);
X }
X 
X /*
diff -u --recursive --new-file v2.3.5/linux/drivers/net/irda/uircc.c linux/drivers/net/irda/uircc.c
--- v2.3.5/linux/drivers/net/irda/uircc.c	Mon May 31 22:28:06 1999
+++ linux/drivers/net/irda/uircc.c	Mon Jun  7 16:18:58 1999
@@ -7,7 +7,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sat Dec 26 10:59:03 1998
- * Modified at:   Mon May 10 22:11:09 1999
+ * Modified at:   Wed May 19 15:29:56 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -216,7 +216,7 @@
X 	idev->netdev.open            = uircc_net_open;
X 	idev->netdev.stop            = uircc_net_close;
X 
-	irport_start(iobase2);
+	irport_start(idev, iobase2);
X 
X 	/* Open the IrDA device */
X 	irda_device_open(idev, driver_name, self);
@@ -251,7 +251,7 @@
X 	/* Disable modem */
X 	outb(0x00, iobase+UIRCC_CR10);
X 
-	irport_stop(idev->io.iobase2);
+	irport_stop(idev, idev->io.iobase2);
X 
X 	/* Release the PORT that this driver is using */
X 	DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
@@ -350,7 +350,7 @@
X 	case 37600:
X 	case 57600:
X 	case 115200:
- 		irport_start(idev->io.iobase2);
+ 		irport_start(idev, idev->io.iobase2);
X 		irport_change_speed(idev, speed);
X 
X 		/* Some magic to disable FIR and enable SIR */
@@ -367,7 +367,7 @@
X 		DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
X 		break;
X 	case 4000000:
-		irport_stop(idev->io.iobase2);
+		irport_stop(idev, idev->io.iobase2);
X 
X 		/* Some magic to disable SIR and enable FIR */
X 		uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001);
diff -u --recursive --new-file v2.3.5/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- v2.3.5/linux/drivers/net/irda/w83977af_ir.c	Mon May 31 22:28:06 1999
+++ linux/drivers/net/irda/w83977af_ir.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Paul VanderSpek
X  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Thu May 13 08:03:27 1999
+ * Modified at:   Fri May 21 22:18:19 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>
@@ -80,8 +80,6 @@
X 
X static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};
X 
-static struct st_fifo_entry prev;
-
X /* Some prototypes */
X static int  w83977af_open(int i, unsigned int iobase, unsigned int irq, 
X                           unsigned int dma);
@@ -112,8 +110,6 @@
X         int i;
X 
X 	DEBUG(0, __FUNCTION__ "()\n");
-
-	prev.status = 0;
X 
X 	for (i=0; (io[i] < 2000) && (i < 4); i++) { 
X 		int ioaddr = io[i];
diff -u --recursive --new-file v2.3.5/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.3.5/linux/drivers/net/myri_sbus.c	Fri Mar 26 13:57:41 1999
+++ linux/drivers/net/myri_sbus.c	Wed Jun  9 14:45:36 1999
@@ -756,6 +756,7 @@
X 	eth->h_proto = type;
X 	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
X 	memcpy(eth->h_dest, neigh->ha, dev->addr_len);
+	hh->hh_len = 16;
X 	return 0;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.3.5/linux/drivers/net/ni52.c	Wed Oct  7 15:51:45 1998
+++ linux/drivers/net/ni52.c	Tue Jun  8 10:27:18 1999
@@ -5,7 +5,7 @@
X  * same Gnu Public License that covers that work.
X  *
X  * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (Michae...@student.uni-tuebingen.de)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hi...@informatik.uni-tuebingen.de)
X  *    [feel free to mail ....]
X  *
X  * when using as module: (no autoprobing!)
diff -u --recursive --new-file v2.3.5/linux/drivers/net/ni52.h linux/drivers/net/ni52.h
--- v2.3.5/linux/drivers/net/ni52.h	Thu Apr 11 23:49:38 1996
+++ linux/drivers/net/ni52.h	Tue Jun  8 10:27:18 1999
@@ -4,7 +4,7 @@
X  * This is an extension to the Linux operating system, and is covered by the
X  * same Gnu Public License that covers that work.
X  *
- * copyrights (c) 1994 by Michael Hipp (mh...@student.uni-tuebingen.de)
+ * copyrights (c) 1994 by Michael Hipp (hi...@informatik.uni-tuebingen.de)
X  *
X  * I have done a look in the following sources:
X  *   crynwr-packet-driver by Russ Nelson
diff -u --recursive --new-file v2.3.5/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.3.5/linux/drivers/net/ni65.c	Fri Oct  9 11:56:59 1998
+++ linux/drivers/net/ni65.c	Tue Jun  8 10:27:18 1999
@@ -16,7 +16,7 @@
X  *
X  * comments/bugs/suggestions can be sent to:
X  *   Michael Hipp
- *   email: Michae...@student.uni-tuebingen.de
+ *   email: hi...@informatik.uni-tuebingen.de
X  *
X  * sources:
X  *   some things are from the 'ni6510-packet-driver for dos by Russ Nelson'
@@ -45,6 +45,7 @@
X  */
X 
X /*
+ * 99.Jun.8: added support for /proc/net/dev byte count for xosview (HK)
X  * 96.Sept.29: virt_to_bus stuff added for new memory modell
X  * 96.April.29: Added Harald Koenig's Patches (MH)
X  * 96.April.13: enhanced error handling .. more tests (MH)
@@ -966,8 +967,10 @@
X 				p->stats.tx_errors++;
X 			tmdp->status2 = 0;
X 		}
-		else
+		else {
+			p->stats.tx_bytes -= (short)(tmdp->blen);
X 			p->stats.tx_packets++;
+		}
X 
X #ifdef XMT_VIA_SKB
X 		if(p->tmd_skb[p->tmdlast]) {
@@ -1054,6 +1057,7 @@
X 				eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
X #endif
X 				p->stats.rx_packets++;
+				p->stats.rx_bytes += len;
X 				skb->protocol=eth_type_trans(skb,dev);
X 				netif_rx(skb);
X 			}
diff -u --recursive --new-file v2.3.5/linux/drivers/net/ptifddi.c linux/drivers/net/ptifddi.c
--- v2.3.5/linux/drivers/net/ptifddi.c	Wed Jun  2 14:44:39 1999
+++ linux/drivers/net/ptifddi.c	Wed Jun  9 14:45:36 1999
@@ -1,4 +1,4 @@
-/* $Id: ptifddi.c,v 1.5 1997/04/16 10:27:27 jj Exp $
+/* $Id: ptifddi.c,v 1.7 1999/06/09 08:19:01 davem Exp $
X  * ptifddi.c: Network driver for Performance Technologies single-attach
X  *            and dual-attach FDDI sbus cards.
X  *
diff -u --recursive --new-file v2.3.5/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c
--- v2.3.5/linux/drivers/net/sdladrv.c	Thu Jan  7 09:21:53 1999
+++ linux/drivers/net/sdladrv.c	Wed Jun  2 14:40:22 1999
@@ -13,6 +13,7 @@
X *		as published by the Free Software Foundation; either version
X *		2 of the License, or (at your option) any later version.
X * ============================================================================
+* May 19, 1999	Arnaldo Melo	wanpipe_init belongs to sdlamain.c
X * Dec 20, 1996	Gene Kozin	Version 3.0.0. Complete overhaul.
X * Jul 12, 1996	Gene Kozin	Changes for Linux 2.0 compatibility.
X * Jun 12, 1996	Gene Kozin 	Added support for S503 card.
@@ -89,7 +90,6 @@
X #include <linux/sched.h>	/* for jiffies, HZ, etc. */
X #include <linux/sdladrv.h>	/* API definitions */
X #include <linux/sdlasfm.h>	/* SDLA firmware module definitions */
-#include <linux/init.h>
X #include <asm/io.h>		/* for inb(), outb(), etc. */
X #define _INB(port)		(inb(port))
X #define _OUTB(port, byte)	(outb((byte),(port)))
@@ -288,9 +288,6 @@
X 
X #ifdef MODULE
X int init_module (void)
-#else
-__initfunc(int wanpipe_init(void))
-#endif
X {
X 	printk(KERN_INFO "%s v%u.%u %s\n",
X 		fullname, MOD_VERSION, MOD_RELEASE, copyright);
@@ -301,7 +298,6 @@
X 	return 0;
X }
X 
-#ifdef MODULE
X /*============================================================================
X  * Module 'remove' entry point.
X  * o release all remaining system resources
diff -u --recursive --new-file v2.3.5/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c
--- v2.3.5/linux/drivers/net/sdlamain.c	Mon Dec 28 11:05:14 1998
+++ linux/drivers/net/sdlamain.c	Wed Jun  2 14:40:22 1999
@@ -11,6 +11,7 @@
X *		as published by the Free Software Foundation; either version
X *		2 of the License, or (at your option) any later version.
X * ============================================================================
+* May 19, 1999  Arnaldo Melo    __initfunc for wanpipe_init
X * Nov 28, 1997	Jaspreet Singh	Changed DRV_RELEASE to 1
X * Nov 10, 1997	Jaspreet Singh	Changed sti() to restore_flags();
X * Nov 06, 1997 	Jaspreet Singh	Changed DRV_VERSION to 4 and DRV_RELEASE to 0
@@ -42,6 +43,7 @@
X #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
X #include <asm/uaccess.h>	/* kernel <-> user copy */
X #include <asm/io.h>		/* phys_to_virt() */
+#include <linux/init.h>         /* __initfunc (when not using as a module) */
X 
X 
X /****** Defines & Macros ****************************************************/
@@ -122,7 +124,7 @@
X #ifdef MODULE
X int init_module (void)
X #else
-int wanpipe_init(void)
+__initfunc(int wanpipe_init(void))
X #endif
X {
X 	int cnt, err = 0;
diff -u --recursive --new-file v2.3.5/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c
--- v2.3.5/linux/drivers/net/sk_mca.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sk_mca.c	Mon Jun  7 14:34:46 1999
@@ -0,0 +1,1143 @@
+/* 
+net-3-driver for the SKNET MCA-based cards
+
+This is an extension to the Linux operating system, and is covered by the
+same Gnu Public License that covers that work.
+
+Copyright 1999 by Alfred Arnold (alf...@ccac.rwth-aachen.de, aar...@elsa.de)
+
+This driver is based both on the 3C523 driver and the SK_G16 driver.
+
+paper sources:
+  'PC Hardware: Aufbau, Funktionsweise, Programmierung' by 
+  Hans-Peter Messmer for the basic Microchannel stuff
+  
+  'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
+  for help on Ethernet driver programming
+
+  'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
+  for documentation on the AM7990 LANCE
+
+  'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
+  for documentation on the Junior board
+
+  'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
+  documentation on the MC2 bord
+  
+  A big thank you to the S&K support for providing me so quickly with
+  documentation!
+
+  Also see http://www.syskonnect.com/
+
+  Missing things:
+
+  -> set debug level via ioctl instead of compile-time switches
+  -> I didn't follow the development of the 2.1.x kernels, so my
+     assumptions about which things changed with which kernel version 
+     are probably nonsense
+
+History:
+  May 16th, 1999
+  	startup
+  May 22st, 1999
+	added private structure, methods
+        begun building data structures in RAM
+  May 23nd, 1999
+	can receive frames, send frames
+  May 24th, 1999
+        modularized intialization of LANCE
+        loadable as module
+	still Tx problem :-(
+  May 26th, 1999
+  	MC2 works
+  	support for multiple devices
+  	display media type for MC2+
+  May 28th, 1999
+	fixed problem in GetLANCE leaving interrupts turned off
+        increase TX queue to 4 packets to improve send performance
+  May 29th, 1999
+	a few corrections in statistics, caught rcvr overruns 
+        reinitialization of LANCE/board in critical situations
+        MCA info implemented
+	implemented LANCE multicast filter
+  Jun 6th, 1999
+	additions for Linux 2.2
+
+ *************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/mca.h>
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 10'
echo 'File patch-2.3.6 is continued in part 11'
echo 11 > _shar_seq_.tmp
exit 0
#!/bin/sh
# this is part 14 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 14; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+      if (sc->device_flags[i] & CFSYNCHISULTRA)
+      {
+        p->ultraenb |= mask;
+      }
X     }
X     else if (sc->adapter_control & CFULTRAEN)
X     {
@@ -8364,18 +8829,54 @@
X       p->ultraenb &= ~mask;
X       p->transinfo[i].user_offset = 0;
X       p->transinfo[i].user_period = 0;
+      p->transinfo[i].user_options = 0;
X       p->transinfo[i].cur_offset = 0;
X       p->transinfo[i].cur_period = 0;
+      p->transinfo[i].cur_options = 0;
X       p->needsdtr_copy &= ~mask;
X     }
X     else
X     {
-      if (p->features & AHC_ULTRA2)
+      if (p->features & AHC_ULTRA3)
+      {
+        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
+        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+        if( (sc->device_flags[i] & CFXFER) < 0x03 )
+        {
+          scsirate = (sc->device_flags[i] & CFXFER);
+          p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
+          if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
+          {
+            p->transinfo[i].cur_options = 
+              ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
+                 MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
+          }
+          else
+          {
+            p->transinfo[i].cur_options = 0;
+          }
+        }
+        else
+        {
+          scsirate = (sc->device_flags[i] & CFXFER) |
+                     ((p->ultraenb & mask) ? 0x18 : 0x10);
+          p->transinfo[i].user_options = 0;
+          p->transinfo[i].cur_options = 0;
+        }
+        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
+                                       AHC_SYNCRATE_ULTRA3);
+        p->transinfo[i].cur_period = aic7xxx_find_period(p,
+                                       aic_inb(p, TARG_SCSIRATE + i),
+                                       AHC_SYNCRATE_ULTRA3);
+      }
+      else if (p->features & AHC_ULTRA2)
X       {
X         p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
X         p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
X         scsirate = (sc->device_flags[i] & CFXFER) |
X                    ((p->ultraenb & mask) ? 0x18 : 0x10);
+        p->transinfo[i].user_options = 0;
+        p->transinfo[i].cur_options = 0;
X         p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
X                                        AHC_SYNCRATE_ULTRA2);
X         p->transinfo[i].cur_period = aic7xxx_find_period(p,
@@ -8385,10 +8886,9 @@
X       else
X       {
X         scsirate = (sc->device_flags[i] & CFXFER) << 4;
-        if (sc->device_flags[i] & CFWIDEB)
-          p->transinfo[i].user_offset = MAX_OFFSET_16BIT;
-        else
-          p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
+        p->transinfo[i].user_options = 0;
+        p->transinfo[i].cur_options = 0;
+        p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
X         if (p->features & AHC_ULTRA)
X         {
X           short ultraenb;
@@ -8427,9 +8927,10 @@
X   }
X   aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
X   aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+  p->needppr = p->needppr_copy = p->needdv = 0;
X   p->needwdtr = p->needwdtr_copy;
X   p->needsdtr = p->needsdtr_copy;
-  p->wdtr_pending = p->sdtr_pending = 0;
+  p->dtr_pending = 0;
X 
X   /*
X    * We set the p->ultraenb from the SEEPROM to begin with, but now we make
@@ -8453,6 +8954,7 @@
X     {
X       case AHC_AIC7895:
X       case AHC_AIC7896:
+      case AHC_AIC7899:
X         if (p->adapter_control & CFBPRIMARY)
X           p->flags |= AHC_CHANNEL_B_PRIMARY;
X       default:
@@ -8783,6 +9285,14 @@
X       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
X        AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
X        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
X       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
X        AHC_AIC7860_FE,                                       7,
@@ -8825,6 +9335,18 @@
X       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
X        AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
X        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
X       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
X        AHC_AIC7895_FE,                                      19,
@@ -8833,30 +9355,66 @@
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
X        AHC_AIC7890_FE,                                      20,
X        32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_78902, AHC_AIC7890,
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
X        AHC_AIC7890_FE,                                      20,
X        32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
X        AHC_AIC7890_FE,                                      21,
X        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      22,
+       32, C46 },
X       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      22,
+       AHC_AIC7896_FE,                                      23,
X        32, C56_66 },
X       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      23,
+       AHC_AIC7896_FE,                                      24,
X        32, C56_66 },
X       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      24,
+       AHC_AIC7896_FE,                                      25,
X        32, C56_66 },
X       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
X        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                      25,
+       AHC_AIC7860_FE,                                      26,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
X        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
X     };
X 
X     unsigned short command;
@@ -8926,11 +9484,11 @@
X           }
X #ifdef AIC7XXX_STRICT_PCI_SETUP
X           command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
-            PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
-            PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
X #else
X           command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
X #endif
+          command &= ~PCI_COMMAND_INVALIDATE;
X           if (aic7xxx_pci_parity == 0)
X             command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
X           pci_write_config_word(pdev, PCI_COMMAND, command);
@@ -8940,15 +9498,7 @@
X           {
X             printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
X           }
-          devconfig |= 0x80000000;
-          if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
-          {
-            devconfig &= ~(0x00000008);
-          }
-          else
-          {
-            devconfig |= 0x00000008;
-          }
+          devconfig |= 0x80000040;
X           pci_write_config_dword(pdev, DEVCONFIG, devconfig);
X #endif /* AIC7XXX_STRICT_PCI_SETUP */
X #else  /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
@@ -8976,11 +9526,11 @@
X           }
X #ifdef AIC7XXX_STRICT_PCI_SETUP
X           command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
-            PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
-            PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
X #else
X           command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
X #endif
+          command &= ~PCI_COMMAND_INVALIDATE;
X           if (aic7xxx_pci_parity == 0)
X             command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
X           pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command);
@@ -8990,15 +9540,7 @@
X           {
X             printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
X           }
-          devconfig |= 0x80000000;
-          if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
-          {
-            devconfig &= ~(0x00000008);
-          }
-          else
-          {
-            devconfig |= 0x00000008;
-          }
+          devconfig |= 0x80000040;
X           pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, devconfig);
X #endif /* AIC7XXX_STRICT_PCI_SETUP */
X #endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
@@ -9137,6 +9679,7 @@
X 
X             case AHC_AIC7895: /* 7895 */
X             case AHC_AIC7896: /* 7896/7 */
+            case AHC_AIC7899: /* 7899 */
X #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
X               if (PCI_FUNC(temp_p->pdev->devfn) != 0)
X               {
@@ -9185,43 +9728,38 @@
X            */
X           switch (temp_p->chip & AHC_CHIPID_MASK)
X           {
-            case AHC_AIC7890:
-            case AHC_AIC7896:
+            case AHC_AIC7892:
+            case AHC_AIC7899:
X               aic_outb(temp_p, 0, SCAMCTL);
X               /*
-               * We used to set DPARCKEN in this register, but after talking
-               * to a tech from Adaptec, I found out they don't use that
-               * particular bit in their own register settings, and when you
-               * combine that with the fact that I determined that we were
-               * seeing Data-Path Parity Errors on things we shouldn't see
-               * them on, I think there is a bug in the silicon and the way
-               * to work around it is to disable this particular check.  Also
-               * This bug only showed up on certain commands, so it seems to
-               * be pattern related or some such.  The commands we would
-               * typically send as a linux TEST_UNIT_READY or INQUIRY command
-               * could cause it to be triggered, while regular commands that
-               * actually made reasonable use of the SG array capabilities
-               * seemed not to cause the problem.
+               * Switch to the alt mode of the chip...
+               */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
+              /*
+               * Set our options...the last two items set our CRC after x byte
+	       * count in target mode...
X                */
+              aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
+	      aic_outb(temp_p, 0x00, 0x0b);
+	      aic_outb(temp_p, 0x10, 0x0a);
X               /*
-              aic_outb(temp_p, aic_inb(temp_p, DSCOMMAND0) |
-                               CACHETHEN | DPARCKEN | MPARCKEN |
-                               USCBSIZE32 | CIOPARCKEN,
-                               DSCOMMAND0);
+               * switch back to normal mode...
X                */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
+              aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
+			       TARGCRCENDEN | TARGCRCCNTEN,
+                       CRCCONTROL1);
+              aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
+                                 MPARCKEN | CIOPARCKEN | CACHETHEN) & 
+                               ~DPARCKEN), DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7890:
+            case AHC_AIC7896:
+              aic_outb(temp_p, 0, SCAMCTL);
X               aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
X                                 CACHETHEN | MPARCKEN | USCBSIZE32 |
X                                 CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
-              /* FALLTHROUGH */
-            default:
-              /*
-               * We attempt to read a SEEPROM on *everything*.  If we fail,
-               * then we fail, but this covers things like 2910c cards that
-               * now have SEEPROMs with their 7856 chipset that we would
-               * otherwise ignore.  They still don't have a BIOS, but they
-               * have a SEEPROM that the SCSISelect utility on the Adaptec
-               * diskettes can configure.
-               */
X               aic7xxx_load_seeprom(temp_p, &sxfrctl1);
X               break;
X             case AHC_AIC7850:
@@ -9233,14 +9771,13 @@
X               aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
X                                 CACHETHEN | MPARCKEN) & ~DPARCKEN,
X                        DSCOMMAND0);
+              /* FALLTHROUGH */
+            default:
X               aic7xxx_load_seeprom(temp_p, &sxfrctl1);
X               break;
X             case AHC_AIC7880:
X               /*
-               * Only set the DSCOMMAND0 register if this is a Rev B.
-               * chipset.  For those, we also enable Ultra mode by
-               * force due to brain-damage on the part of some BIOSes
-               * We overload the devconfig variable here since we can.
+               * Check the rev of the chipset before we change DSCOMMAND0
X                */
X #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
X               pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
@@ -9272,6 +9809,7 @@
X           {
X             case AHC_AIC7895:
X             case AHC_AIC7896:
+            case AHC_AIC7899:
X               current_p = list_p;
X               while(current_p != NULL)
X               {
@@ -9315,6 +9853,7 @@
X               break;
X             case AHC_AIC7895:
X             case AHC_AIC7896:
+            case AHC_AIC7899:
X #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
X               pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
X #else
@@ -9364,7 +9903,7 @@
X            */
X           if (temp_p->features & AHC_ULTRA2)
X           {
-            aic_outb(temp_p, RD_DFTHRSH_75 | WR_DFTHRSH_75, DFF_THRSH);
+            aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
X           }
X           else
X           {
@@ -9512,7 +10051,7 @@
X               }
X             }
X             /*
-             * Are we dealing with a 7985 where we need to sort the
+             * Are we dealing with a 7895/6/7/9 where we need to sort the
X              * channels as well, if so, the bios_address values should
X              * be the same
X              */
@@ -9603,7 +10142,54 @@
X   return (found);
X }
X 
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
+                                           Scsi_Cmnd *old_cmd, int tindex);
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_allocate_negotiation_command
+ *
+ * Description:
+ *   allocate the actual command struct and fill in the gaps...
+ *-F*************************************************************************/
+static Scsi_Cmnd *
+aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
+                                     Scsi_Cmnd *old_cmd, int tindex)
+{
+  Scsi_Cmnd *cmd;
+  char *buffer;
+
+  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+  {
+    return(NULL);
+  }
+  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
+  {
+    kfree(p->dev_dtr_cmnd[tindex]);
+    p->dev_dtr_cmnd[tindex] = NULL;
+    return(NULL);
+  }
+  cmd = p->dev_dtr_cmnd[tindex];
+  memset(cmd, 0, sizeof(Scsi_Cmnd));
+  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
+  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
+  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
+  cmd->lun = 0;
+  cmd->request_bufflen = 255;
+  cmd->request_buffer = buffer;
+  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
+  cmd->bufflen = 0;
+  cmd->buffer = NULL;
+  cmd->underflow = 0;
+  cmd->cmd_len = 6;
+  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
+  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
+  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
+  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
+  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
+  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
+  return(cmd);
+}
X 
X /*+F*************************************************************************
X  * Function:
@@ -9616,6 +10202,117 @@
X static void
X aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
X {
+  unsigned int checksum;
+  int i;
+  int *ibuffer;
+  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_syncrate *syncrate;
+
+  /*
+   * perform our minimalistic domain validation
+   */
+  if(p->dev_flags[tindex] & DEVICE_SCANNED)
+  {
+    ibuffer = (int *)cmd->request_buffer;
+    checksum = 0;
+    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
+    {
+      checksum += ibuffer[i];
+    }
+    if( (checksum != p->dev_checksum[tindex]) &&
+        (p->transinfo[tindex].cur_offset != 0) )
+    {
+      unsigned int period = p->transinfo[tindex].cur_period;
+      unsigned char options = p->transinfo[tindex].cur_options;
+
+      if (p->needdv & (1<<tindex))
+      {
+        /*
+         * oops, we had a failure, lower the transfer rate and try again.  It's
+         * worth noting here that it might be wise to also check for typical
+         * wide setting on narrow cable type problems and try disabling wide
+         * instead of slowing down if those exist.  That's hard to do with simple
+         * checksums though.
+         */
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION) 
+        {
+          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
+                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
+        }
+        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+        {
+          syncrate++;
+          if( (syncrate->rate[0] != NULL) &&
+              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+          {
+            p->transinfo[tindex].goal_period = syncrate->period;
+            if( !(syncrate->sxfr_ultra2 & 0x40) )
+            {
+              p->transinfo[tindex].goal_options = 0;
+            }
+          }
+          else
+          {
+            p->transinfo[tindex].goal_offset = 0;
+            p->transinfo[tindex].goal_period = 0;
+            p->transinfo[tindex].goal_options = 0;
+          }
+          p->needppr |= (p->needppr_copy & (1<<tindex));
+          p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+          p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+        }
+        p->needdv &= ~(1<<tindex);
+      }
+      else
+      {
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION) 
+        {
+          printk(INFO_LEAD "Performing Domain validation.\n",
+                 p->host_no, CTL_OF_CMD(cmd));
+        }
+        /*
+         * Update the checksum in case the INQUIRY data has changed, maybe
+         * in relation to a change in the mode pages, or whatever.
+         */
+        p->dev_checksum[tindex] = checksum;
+        /*
+         * Signal that we are trying out the domain validation
+         */
+        p->needdv |= (1<<tindex);
+        /*
+         * Signal that we need to re-negotiate things, this also gets us our
+         * INQUIRY command to re-checksum off of.
+         */
+        p->needppr |= (p->needppr_copy & (1<<tindex));
+        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+      }
+    } 
+    else
+    {
+      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+          (p->needdv & (1<<tindex)) )
+      {
+        printk(INFO_LEAD "Successfully completed Domain validation.\n",
+               p->host_no, CTL_OF_CMD(cmd));
+      }
+      /*
+       * We successfully did our checksum, so don't leave the needdv flag set
+       * in case we might have set it last time through.
+       */
+      p->needdv &= ~(1<<tindex);
+    }
+  }
+
+  p->dtr_pending &= ~(0x01 << tindex);
+  /*
+   * This looks recursive in the extreme, but if this was a WDTR negotiation
+   * and we didn't follow up with SDTR yet, then this will get it started.
+   * For all other cases, this should work out to be a no-op, unless we are
+   * doing domain validation and happen to need a new negotiation command.
+   */
+  aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
X   return;
X }
X 
@@ -9632,81 +10329,63 @@
X   int tindex)
X {
X 
-  if ( (p->needwdtr & (1<<tindex)) && !(p->wdtr_pending & (1<<tindex)) )
+  if ( !(p->dtr_pending & (1<<tindex)) &&
+       ( (p->needppr & (1<<tindex)) ||
+         (p->needwdtr & (1<<tindex)) ||
+         (p->needsdtr & (1<<tindex)) ) )
X   {
-    if(p->dev_wdtr_cmnd[tindex] == NULL)
+    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
+         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
X     {
-      Scsi_Cmnd *cmd;
-
-      if (!(p->dev_wdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
-      {
-        return;
-      }
-      cmd = p->dev_wdtr_cmnd[tindex];
-      memset(cmd, 0, sizeof(Scsi_Cmnd));
-      memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-      memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-      memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-      cmd->lun = 0;
-      cmd->request_bufflen = 0;
-      cmd->request_buffer = NULL;
-      cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-      cmd->bufflen = 0;
-      cmd->buffer = NULL;
-      cmd->underflow = 0;
-      cmd->cmd_len = 6;
+      return;
X     }
X     /*
-     * Before sending this thing out, we also amke the cmd->next pointer
+     * Before sending this thing out, we also make the cmd->next pointer
X      * point to the real command so we can stuff any possible SENSE data
-     * intp the real command instead of this fake command.  This has to be
+     * into the real command instead of this fake command.  This has to be
X      * done each time the command is built, not just the first time, hence
X      * it's outside of the above if()...
X      */
-    p->dev_wdtr_cmnd[tindex]->next = old_cmd;
-    aic7xxx_queue(p->dev_wdtr_cmnd[tindex], 
-                  aic7xxx_negotiation_complete);
-  }
-  else if ( (p->needsdtr & (1<<tindex)) && !(p->sdtr_pending & (1<<tindex)) &&
-            !(p->wdtr_pending & (1<<tindex)) )
-  {
-    if(p->dev_sdtr_cmnd[tindex] == NULL)
+    p->dev_dtr_cmnd[tindex]->next = old_cmd;
+    /*
+     * Clear the buffer so checksums come out right....
+     */
+    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
+           p->dev_dtr_cmnd[tindex]->request_bufflen);
+    /*
+     * Remove any commands for this particular device that might be on the
+     * waiting_scbs queue or qinfifo so that this command goes out first.
+     * This is vital for our implementation of domain validation.
+     */
+    pause_sequencer(p);
+    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
+                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
+    unpause_sequencer(p, FALSE);
X     {
-      Scsi_Cmnd *cmd;
+      struct aic7xxx_scb *scb, *next;
X 
-      if (!(p->dev_sdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+      scb = p->waiting_scbs.head;
+      while(scb != NULL)
X       {
-        return;
+        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
+                              ALL_LUNS, SCB_LIST_NULL) )
+        {
+          next = scb->q_next;
+          scbq_remove(&p->waiting_scbs, scb);
+          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+          scb = next;
+        }
+        else
+        {
+          scb = scb->q_next;
+        }
X       }
-      cmd = p->dev_sdtr_cmnd[tindex];
-      memset(cmd, 0, sizeof(Scsi_Cmnd));
-      memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-      memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-      memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-      cmd->lun = 0;
-      cmd->request_bufflen = 0;
-      cmd->request_buffer = NULL;
-      cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-      cmd->bufflen = 0;
-      cmd->buffer = NULL;
-      cmd->underflow = 0;
-      cmd->cmd_len = 6;
X     }
-    /*
-     * Before sending this thing out, we also amke the cmd->next pointer
-     * point to the real command so we can stuff any possible SENSE data
-     * intp the real command instead of this fake command.  This has to be
-     * done each time the command is built, not just the first time, hence
-     * it's outside of the above if()...
-     */
-    p->dev_sdtr_cmnd[tindex]->next = old_cmd;
-    aic7xxx_queue(p->dev_sdtr_cmnd[tindex], 
+    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
X                   aic7xxx_negotiation_complete);
X   }
X }
X 
-#endif
-
X #ifdef AIC7XXX_VERBOSE_DEBUGGING
X /*+F*************************************************************************
X  * Function:
@@ -9744,8 +10423,9 @@
X {
X   unsigned short mask;
X   struct aic7xxx_hwscb *hscb;
+  unsigned char tindex = TARGET_INDEX(cmd);
X 
-  mask = (0x01 << TARGET_INDEX(cmd));
+  mask = (0x01 << tindex);
X   hscb = scb->hscb;
X 
X   /*
@@ -9757,11 +10437,12 @@
X   if (p->discenable & mask)
X   {
X     hscb->control |= DISCENB;
-    if (p->tagenable & mask)
+    if ( (p->tagenable & mask) &&
+         (cmd->cmnd[0] != TEST_UNIT_READY) )
X     {
X       cmd->tag = hscb->tag;
-      p->dev_commands_sent[TARGET_INDEX(cmd)]++;
-      if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
+      p->dev_commands_sent[tindex]++;
+      if (p->dev_commands_sent[tindex] < 200)
X       {
X         hscb->control |= MSG_SIMPLE_Q_TAG;
X         scb->tag_action = MSG_SIMPLE_Q_TAG;
@@ -9778,74 +10459,38 @@
X           hscb->control |= MSG_SIMPLE_Q_TAG;
X           scb->tag_action = MSG_SIMPLE_Q_TAG;
X         }
-        p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
+        p->dev_commands_sent[tindex] = 0;
X       }
X     }
X   }
-  if (p->dev_flags[TARGET_INDEX(cmd)] & DEVICE_SCANNED)
+  if ( cmd == p->dev_dtr_cmnd[tindex] )
X   {
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
-    if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) )
+    p->dtr_pending |= mask;
+    scb->tag_action = 0;
+    if (p->dev_flags[tindex] & DEVICE_SCANNED)
X     {
-      if (cmd == p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
+      hscb->control &= DISCENB;
+      hscb->control |= MK_MESSAGE;
+      if(p->needppr & mask)
X       {
-        p->wdtr_pending |= mask;
-        scb->flags |= SCB_MSGOUT_WDTR;
- hscb->control &= DISCENB;
-        hscb->control |= MK_MESSAGE;
-        scb->tag_action = 0;
+        scb->flags |= SCB_MSGOUT_PPR;
X       }
-      else
+      else if(p->needwdtr & mask)
X       {
-        aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
+        scb->flags |= SCB_MSGOUT_WDTR;
X       }
-    }
-    else if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) &&
-              !(p->wdtr_pending & mask) )
-    {
-      if (cmd == p->dev_sdtr_cmnd[TARGET_INDEX(cmd)])
+      else if(p->needsdtr & mask)
X       {
-        p->sdtr_pending |= mask;
X         scb->flags |= SCB_MSGOUT_SDTR;
- hscb->control &= DISCENB;
-        hscb->control |= MK_MESSAGE;
-        scb->tag_action = 0;
-      }
-      else if (cmd != p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
-      {
-        aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
X       }
X     }
-#else
-    if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) &&
-         !(p->sdtr_pending & mask) && (cmd->lun == 0) )
-    {
-      p->wdtr_pending |= mask;
-      scb->flags |= SCB_MSGOUT_WDTR;
- hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Building WDTR command.\n", p->host_no,
-               CTL_OF_CMD(cmd));
-#endif
-    }
-    else if ( (p->needsdtr & mask) && !(p->wdtr_pending & mask) &&
-              !(p->sdtr_pending & mask) && (cmd->lun == 0) )
-    {
-      p->sdtr_pending |= mask;
-      scb->flags |= SCB_MSGOUT_SDTR;
- hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Building SDTR command.\n", p->host_no,
-               CTL_OF_CMD(cmd));
-#endif
-    }
-#endif
+  }
+  if ( !(p->dtr_pending & mask) &&
+        ( (p->needppr & mask) ||
+          (p->needwdtr & mask) ||
+          (p->needsdtr & mask) ) )
+  {
+    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
X   }
X   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
X         ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -9897,7 +10542,6 @@
X     scb->sg_count = cmd->use_sg;
X     hscb->SG_segment_count = cmd->use_sg;
X     hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
-
X   }
X   else
X   {
@@ -9922,12 +10566,6 @@
X       hscb->data_pointer = 0;
X     }
X   }
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  if((cmd->cmnd[0] == TEST_UNIT_READY) && (aic7xxx_verbose & VERBOSE_PROBE2))
-  {
-    aic7xxx_print_scb(p, scb);
-  }
-#endif
X }
X 
X /*+F*************************************************************************
@@ -10262,13 +10900,14 @@
X     if(p->dev_flags[i] & DEVICE_PRESENT)
X     {
X       mask = (0x01 << i);
-      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
-             " q_depth=%d:%d\n",
+      printk(INFO_LEAD "dev_flags=0x%x, Pending:%c, PPR:%c/%c, WDTR:%c/%c, "
+             "SDTR:%c/%c, q_depth=%d:%d\n",
X         p->host_no, 0, i, 0, p->dev_flags[i],
-        (p->wdtr_pending & mask) ? 'Y' : 'N',
+        (p->dtr_pending & mask) ? 'Y' : 'N',
+        (p->needppr & mask) ? 'Y' : 'N',
+        (p->needppr_copy & mask) ? 'Y' : 'N',
X         (p->needwdtr & mask) ? 'Y' : 'N',
X         (p->needwdtr_copy & mask) ? 'Y' : 'N',
-        (p->sdtr_pending & mask) ? 'Y' : 'N',
X         (p->needsdtr & mask) ? 'Y' : 'N',
X         (p->needsdtr_copy & mask) ? 'Y' : 'N',
X         p->dev_active_cmds[i],
@@ -10347,13 +10986,13 @@
X      * We haven't found the offending SCB yet, and it should be around
X      * somewhere, so go look for it in the cards SCBs.
X      */
-    printk("SCBPTR CONTROL TAG PREV NEXT\n");
+    printk("SCBPTR CONTROL TAG NEXT\n");
X     for(i=0; i<p->scb_data->maxhscbs; i++)
X     {
X       aic_outb(p, i, SCBPTR);
-      printk("   %3d      %02x  %02x   %02x   %02x\n", i,
+      printk("   %3d      %02x  %02x   %02x\n", i,
X              aic_inb(p, SCB_CONTROL), aic_inb(p, SCB_TAG),
-             aic_inb(p, SCB_PREV), aic_inb(p, SCB_NEXT));
+             aic_inb(p, SCB_NEXT));
X     }
X   }
X   
@@ -10569,21 +11208,13 @@
X   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
X   {
X     int tindex = TARGET_INDEX(cmd);
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
X     unsigned short mask;
X 
X     mask = (1 << tindex);
X 
-    if (p->wdtr_pending & mask)
-    {
-      if (p->dev_wdtr_cmnd[tindex]->next != cmd)
-        found = 1;
-      else
-        found = 0;
-    }
-    else if (p->sdtr_pending & mask)
+    if (p->dtr_pending & mask)
X     {
-      if (p->dev_sdtr_cmnd[tindex]->next != cmd)
+      if (p->dev_dtr_cmnd[tindex]->next != cmd)
X         found = 1;
X       else
X         found = 0;
@@ -10606,7 +11237,6 @@
X       DRIVER_UNLOCK
X       return(SCSI_ABORT_PENDING);
X     }
-#endif
X     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
X       printk(INFO_LEAD "SCB found on waiting list and "
X           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -10864,6 +11494,8 @@
X       if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
X         printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
X           CTL_OF_SCB(scb));
+      aic7xxx_run_done_queue(p, TRUE);
+      aic7xxx_run_waiting_queues(p);
X       unpause_sequencer(p, FALSE);
X       DRIVER_UNLOCK
X       return(SCSI_RESET_NOT_RUNNING);
@@ -11034,16 +11666,21 @@
X int
X aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
X {
-  int heads, sectors, cylinders;
+  int heads, sectors, cylinders, ret;
X   struct aic7xxx_host *p;
+  struct buffer_head *bh;
X 
X   p = (struct aic7xxx_host *) disk->device->host->hostdata;
+  bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
X 
-  /*
-   * XXX - if I could portably find the card's configuration
-   *       information, then this could be autodetected instead
-   *       of left to a boot-time switch.
-   */
+  if ( bh )
+  {
+    ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
+    brelse(bh);
+    if ( ret != -1 )
+      return(ret);
+  }
+  
X   heads = 64;
X   sectors = 32;
X   cylinders = disk->capacity / (heads * sectors);
@@ -11150,6 +11787,12 @@
X           0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
X           0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
X           0xfe, 0xff} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
X   };
X #ifdef CONFIG_PCI
X   static struct register_ranges cards_ns[] = {
@@ -11164,6 +11807,10 @@
X     { 5, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3} },
X     { 6, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47,
X           0xdc, 0xe3} },
+    { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+          0xff, 0xff} },
+    { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+          0xff, 0xff} },
X     { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
X           0xff, 0xff} }
X   };
diff -u --recursive --new-file v2.3.5/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.3.5/linux/drivers/scsi/aic7xxx_proc.c	Mon Jan  4 12:57:44 1999
+++ linux/drivers/scsi/aic7xxx_proc.c	Wed Jun  9 16:59:15 1999
@@ -160,21 +160,17 @@
X   size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
X   size += sprintf(BLS, "\n");
X   size += sprintf(BLS, "Compile Options:\n");
-#ifdef AIC7XXX_RESET_DELAY
-  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
+#else
+  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
X #endif
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
-  size += sprintf(BLS, "                             Check below to see "
-                       "which\n"
-                       "                             devices use tagged "
-                       "queueing\n");
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled (This is no longer "
-                       "an option)\n");
X #ifdef AIC7XXX_PROC_STATS
X   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
X #else
X   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
X #endif
+  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
X   size += sprintf(BLS, "\n");
X   size += sprintf(BLS, "Adapter Configuration:\n");
X   size += sprintf(BLS, "           SCSI Adapter: %s\n",
@@ -194,8 +190,21 @@
X     }
X     if (p->features & AHC_WIDE)
X       wide = "Wide ";
-    if (p->features & AHC_ULTRA2)
- ultra = "Ultra2-LVD/SE ";
+    if (p->features & AHC_ULTRA3)
+    {
+      switch(p->chip & AHC_CHIPID_MASK)
+      {
+        case AHC_AIC7892:
+        case AHC_AIC7899:
+          ultra = "Ultra-160/m LVD/SE ";
+          break;
+        default:
+          ultra = "Ultra-3 LVD/SE ";
+          break;
+      }
+    }
+    else if (p->features & AHC_ULTRA2)
+ ultra = "Ultra-2 LVD/SE ";
X     else if (p->features & AHC_ULTRA)
X       ultra = "Ultra ";
X     size += sprintf(BLS, "                           %s%sController%s\n",
@@ -250,11 +259,7 @@
X   }
X   size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
X   size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
-#ifdef AIC7XXX_CMDS_PER_LUN
-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
-#else
-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
-#endif
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
X   size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
X                        "instance %d:\n", p->instance);
X   size += sprintf(BLS, "      {");
@@ -295,11 +300,12 @@
X     if (p->transinfo[target].cur_offset != 0)
X     {
X       struct aic7xxx_syncrate *sync_rate;
+      unsigned char options = p->transinfo[target].cur_options;
X       int period = p->transinfo[target].cur_period;
X       int rate = (p->transinfo[target].cur_width ==
X                   MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
X 
-      sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
+      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
X       if (sync_rate != NULL)
X       {
X         size += sprintf(BLS, "%s MByte/sec, offset %d\n",
@@ -313,18 +319,21 @@
X       }
X     }
X     size += sprintf(BLS, "  Transinfo settings: ");
-    size += sprintf(BLS, "current(%d/%d/%d), ",
+    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
X                     p->transinfo[target].cur_period,
X                     p->transinfo[target].cur_offset,
-                    p->transinfo[target].cur_width);
-    size += sprintf(BLS, "goal(%d/%d/%d), ",
+                    p->transinfo[target].cur_width,
+                    p->transinfo[target].cur_options);
+    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
X                     p->transinfo[target].goal_period,
X                     p->transinfo[target].goal_offset,
-                    p->transinfo[target].goal_width);
-    size += sprintf(BLS, "user(%d/%d/%d)\n",
+                    p->transinfo[target].goal_width,
+                    p->transinfo[target].goal_options);
+    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
X                     p->transinfo[target].user_period,
X                     p->transinfo[target].user_offset,
-                    p->transinfo[target].user_width);
+                    p->transinfo[target].user_width,
+                    p->transinfo[target].user_options);
X #ifdef AIC7XXX_PROC_STATS
X     size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
X         sp->r_total + sp->w_total, sp->r_total, sp->w_total);
diff -u --recursive --new-file v2.3.5/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v2.3.5/linux/drivers/scsi/aic7xxx_reg.h	Thu Oct  8 08:07:34 1998
+++ linux/drivers/scsi/aic7xxx_reg.h	Wed Jun  9 16:59:15 1999
@@ -63,6 +63,16 @@
X 
X #define	STCNT           		0x08
X 
+#define	OPTIONMODE      		0x08
+#define		AUTORATEEN      	0x80
+#define		AUTOACKEN       	0x40
+#define		ATNMGMNTEN      	0x20
+#define		BUSFREEREV      	0x10
+#define		EXPPHASEDIS     	0x08
+#define		SCSIDATL_IMGEN  	0x04
+#define		AUTO_MSGOUT_DE  	0x02
+#define		DIS_MSGIN_DUALEDGE	0x01
+
X #define	CLRSINT0        		0x0b
X #define		CLRSELDO        	0x40
X #define		CLRSELDI        	0x20
@@ -102,8 +112,14 @@
X 
X #define	SSTAT2          		0x0d
X #define		OVERRUN         	0x80
+#define		SHVALID         	0x40
+#define		WIDE_RES        	0x20
X #define		SFCNT           	0x1f
X #define		EXP_ACTIVE      	0x10
+#define		CRCVALERR       	0x08
+#define		CRCENDERR       	0x04
+#define		CRCREQERR       	0x02
+#define		DUAL_EDGE_ERROR 	0x01
X 
X #define	SSTAT3          		0x0e
X #define		SCSICNT         	0xf0
@@ -412,6 +428,7 @@
X #define		DPARERR         	0x10
X #define		SQPARERR        	0x08
X #define		ILLOPCODE       	0x04
+#define		DSCTMOUT        	0x02
X #define		ILLSADDR        	0x02
X #define		ILLHADDR        	0x01
X 
@@ -436,11 +453,30 @@
X 
X #define	QINCNT          		0x9c
X 
+#define	SCSIDATL_IMG    		0x9c
+
X #define	QOUTFIFO        		0x9d
X 
+#define	CRCCONTROL1     		0x9d
+#define		CRCONSEEN       	0x80
+#define		TARGCRCCNTEN    	0x40
+#define		CRCVALCHKEN     	0x40
+#define		CRCENDCHKEN     	0x20
+#define		CRCREQCHKEN     	0x10
+#define		TARGCRCENDEN    	0x08
+
+#define	SCSIPHASE       		0x9e
+#define		SP_STATUS       	0x20
+#define		SP_COMMAND      	0x10
+#define		SP_MSG_IN       	0x08
+#define		SP_MSG_OUT      	0x04
+#define		SP_DATA_IN      	0x02
+#define		SP_DATA_OUT     	0x01
+
X #define	QOUTCNT         		0x9e
X 
X #define	SFUNCT          		0x9f
+#define		ALT_MODE        	0x80
X 
X #define	SCB_CONTROL     		0xa0
X #define		MK_MESSAGE      	0x80
@@ -525,14 +561,20 @@
X 
X #define	HNSCB_QOFF      		0xf4
X 
+#define	HESCB_QOFF      		0xf5
+
X #define	SNSCB_QOFF      		0xf6
X 
+#define	SESCB_QOFF      		0xf7
+
X #define	SDSCB_QOFF      		0xf8
X 
X #define	QOFF_CTLSTA     		0xfa
+#define		ESTABLISH_SCB_AVAIL	0x80
X #define		SCB_AVAIL       	0x40
X #define		SNSCB_ROLLOVER  	0x20
X #define		SDSCB_ROLLOVER  	0x10
+#define		SESCB_ROLLOVER  	0x08
X #define		SCB_QSIZE       	0x07
X #define		SCB_QSIZE_256   	0x06
X 
diff -u --recursive --new-file v2.3.5/linux/drivers/scsi/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_seq.c
--- v2.3.5/linux/drivers/scsi/aic7xxx_seq.c	Thu Oct  8 08:07:34 1998
+++ linux/drivers/scsi/aic7xxx_seq.c	Wed Jun  9 16:59:16 1999
@@ -3,38 +3,44 @@
X   */
X static unsigned char seqprog[] = {
X 	0xff, 0x6a, 0x06, 0x08,
+	0x7f, 0x02, 0x04, 0x08,
X 	0x32, 0x6a, 0x00, 0x00,
X 	0x12, 0x6a, 0x00, 0x00,
X 	0xff, 0x6a, 0xd6, 0x09,
X 	0xff, 0x6a, 0xdc, 0x09,
-	0x00, 0x65, 0x38, 0x59,
+	0x00, 0x65, 0x42, 0x59,
X 	0xf7, 0x01, 0x02, 0x08,
X 	0xff, 0x4e, 0xc8, 0x08,
X 	0xbf, 0x60, 0xc0, 0x08,
-	0x60, 0x0b, 0x7c, 0x68,
+	0x60, 0x0b, 0x86, 0x68,
X 	0x40, 0x00, 0x0e, 0x68,
X 	0x08, 0x1f, 0x3e, 0x10,
-	0x60, 0x0b, 0x7c, 0x68,
+	0x60, 0x0b, 0x86, 0x68,
X 	0x40, 0x00, 0x0e, 0x68,
X 	0x08, 0x1f, 0x3e, 0x10,
-	0xff, 0x3e, 0x3e, 0x60,
-	0x40, 0xfa, 0x10, 0x78,
+	0xff, 0x3e, 0x4a, 0x60,
+	0x40, 0xfa, 0x12, 0x78,
X 	0xff, 0xf6, 0xd4, 0x08,
X 	0x01, 0x4e, 0x9c, 0x18,
X 	0x40, 0x60, 0xc0, 0x00,
-	0x00, 0x4d, 0x10, 0x70,
+	0x00, 0x4d, 0x12, 0x70,
X 	0x01, 0x4e, 0x9c, 0x18,
X 	0xbf, 0x60, 0xc0, 0x08,
-	0x00, 0x6a, 0x72, 0x5c,
+	0x00, 0x6a, 0x92, 0x5c,
X 	0xff, 0x4e, 0xc8, 0x18,
-	0x02, 0x6a, 0x88, 0x5b,
+	0x02, 0x6a, 0xa8, 0x5b,
X 	0xff, 0x52, 0x20, 0x09,
X 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x52, 0xfe, 0x5b,
+	0x00, 0x52, 0x1e, 0x5c,
+	0x03, 0xb0, 0x52, 0x31,
+	0xff, 0xb0, 0x52, 0x09,
+	0xff, 0xb1, 0x54, 0x09,
+	0xff, 0xb2, 0x56, 0x09,
+	0xff, 0xa3, 0x50, 0x09,
X 	0xff, 0x3e, 0x74, 0x09,
X 	0xff, 0x90, 0x7c, 0x08,
X 	0xff, 0x3e, 0x20, 0x09,
-	0x00, 0x65, 0x44, 0x58,
+	0x00, 0x65, 0x50, 0x58,
X 	0x00, 0x65, 0x0e, 0x40,
X 	0xf7, 0x1f, 0xca, 0x08,
X 	0x08, 0xa1, 0xc8, 0x08,
@@ -47,51 +53,50 @@
X 	0x0f, 0x05, 0x0a, 0x08,
X 	0x00, 0x05, 0x0a, 0x00,
X 	0x5a, 0x6a, 0x00, 0x04,
-	0x12, 0x65, 0xc8, 0x00,
-	0x00, 0x01, 0x02, 0x00,
+	0x12, 0x65, 0x02, 0x00,
X 	0x31, 0x6a, 0xca, 0x00,
-	0x80, 0x37, 0x64, 0x68,
+	0x80, 0x37, 0x6e, 0x68,
X 	0xff, 0x65, 0xca, 0x18,
X 	0xff, 0x37, 0xdc, 0x08,
X 	0xff, 0x6e, 0xc8, 0x08,
-	0x00, 0x6c, 0x6c, 0x78,
+	0x00, 0x6c, 0x76, 0x78,
X 	0x20, 0x01, 0x02, 0x00,
X 	0x4c, 0x37, 0xc8, 0x28,
-	0x08, 0x1f, 0x74, 0x78,
+	0x08, 0x1f, 0x7e, 0x78,
X 	0x08, 0x37, 0x6e, 0x00,
X 	0x08, 0x64, 0xc8, 0x00,
X 	0x70, 0x64, 0xca, 0x18,
X 	0xff, 0x6c, 0x0a, 0x08,
X 	0x20, 0x64, 0xca, 0x18,
X 	0xff, 0x6c, 0x08, 0x0c,
-	0x40, 0x0b, 0x04, 0x69,
-	0x80, 0x0b, 0xf6, 0x78,
+	0x40, 0x0b, 0x0e, 0x69,
+	0x80, 0x0b, 0x00, 0x79,
X 	0xa4, 0x6a, 0x06, 0x00,
X 	0x40, 0x6a, 0x16, 0x00,
-	0x10, 0x03, 0xf2, 0x78,
+	0x10, 0x03, 0xfc, 0x78,
X 	0xff, 0x50, 0xc8, 0x08,
X 	0x88, 0x6a, 0xcc, 0x00,
-	0x49, 0x6a, 0xee, 0x5b,
+	0x49, 0x6a, 0x0e, 0x5c,
X 	0x01, 0x6a, 0x26, 0x01,
X 	0xff, 0x6a, 0xca, 0x08,
X 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0x92, 0x78,
+	0x02, 0x0b, 0x9c, 0x78,
X 	0xf7, 0x01, 0x02, 0x08,
X 	0xff, 0x06, 0xcc, 0x08,
X 	0xff, 0x66, 0x32, 0x09,
X 	0x01, 0x65, 0xca, 0x18,
-	0x80, 0x66, 0xa0, 0x78,
+	0x80, 0x66, 0xaa, 0x78,
X 	0xff, 0x66, 0xa2, 0x08,
-	0x10, 0x03, 0x90, 0x68,
+	0x10, 0x03, 0x9a, 0x68,
X 	0xfc, 0x65, 0xc8, 0x18,
-	0x00, 0x65, 0xa8, 0x48,
+	0x00, 0x65, 0xb2, 0x48,
X 	0xff, 0x6a, 0x32, 0x01,
X 	0x01, 0x64, 0x18, 0x19,
X 	0xff, 0x6a, 0x1a, 0x09,
X 	0xff, 0x6a, 0x1c, 0x09,
X 	0x84, 0x6a, 0x06, 0x00,
X 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0xb2, 0x78,
+	0x02, 0x0b, 0xbc, 0x78,
X 	0xff, 0x06, 0xc8, 0x08,
X 	0xff, 0x64, 0x32, 0x09,
X 	0xff, 0x6a, 0xca, 0x08,
@@ -105,33 +110,33 @@
X 	0x0b, 0x65, 0xca, 0x18,
X 	0xff, 0x65, 0xc8, 0x08,
X 	0x00, 0x8c, 0x18, 0x19,
-	0x02, 0x0b, 0xce, 0x78,
-	0x01, 0x65, 0xd4, 0x60,
+	0x02, 0x0b, 0xd8, 0x78,
+	0x01, 0x65, 0xde, 0x60,
X 	0xf7, 0x01, 0x02, 0x08,
X 	0xff, 0x06, 0x32, 0x09,
X 	0xff, 0x65, 0xca, 0x18,
-	0xff, 0x65, 0xce, 0x68,
+	0xff, 0x65, 0xd8, 0x68,
X 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x64, 0x5c,
-	0x40, 0x51, 0xe6, 0x78,
+	0x00, 0x65, 0x84, 0x5c,
+	0x40, 0x51, 0xf0, 0x78,
X 	0xe4, 0x6a, 0x06, 0x00,
X 	0x08, 0x01, 0x02, 0x00,
-	0x04, 0x6a, 0x18, 0x5b,
+	0x04, 0x6a, 0x40, 0x5b,
X 	0x01, 0x50, 0xa0, 0x18,
-	0x00, 0x50, 0xec, 0xe0,
+	0x00, 0x50, 0xf6, 0xe0,
X 	0xff, 0x6a, 0xa0, 0x08,
X 	0xff, 0x6a, 0x3a, 0x01,
X 	0x02, 0x6a, 0x22, 0x01,
-	0x40, 0x51, 0xf2, 0x68,
+	0x40, 0x51, 0xfc, 0x68,
X 	0xff, 0x6a, 0x06, 0x08,
X 	0x00, 0x65, 0x0e, 0x40,
X 	0x20, 0x6a, 0x16, 0x00,
X 	0xf0, 0x19, 0x6e, 0x08,
X 	0x08, 0x6a, 0x18, 0x00,
X 	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x5a, 0x58,
+	0x08, 0x6a, 0x66, 0x58,
X 	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0x18, 0x41,
+	0x00, 0x65, 0x22, 0x41,
X 	0x12, 0x6a, 0x00, 0x00,
X 	0x40, 0x6a, 0x16, 0x00,
X 	0xff, 0x3e, 0x20, 0x09,
@@ -139,362 +144,373 @@
X 	0xff, 0xa1, 0x6e, 0x08,
X 	0x08, 0x6a, 0x18, 0x00,
X 	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x5a, 0x58,
+	0x08, 0x6a, 0x66, 0x58,
X 	0x80, 0x6a, 0x68, 0x00,
X 	0x80, 0x36, 0x6c, 0x00,
-	0x00, 0x65, 0xd2, 0x5b,
+	0x00, 0x65, 0xf2, 0x5b,
X 	0xff, 0x3d, 0xc8, 0x08,
-	0xbf, 0x64, 0x48, 0x79,
-	0x80, 0x64, 0xf0, 0x71,
-	0xa0, 0x64, 0x0e, 0x72,
-	0xc0, 0x64, 0x08, 0x72,
-	0xe0, 0x64, 0x52, 0x72,
+	0xbf, 0x64, 0x58, 0x79,
+	0x80, 0x64, 0x0e, 0x72,
+	0xa0, 0x64, 0x3a, 0x72,
+	0xc0, 0x64, 0x32, 0x72,
+	0xe0, 0x64, 0x7a, 0x72,
X 	0x01, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x18, 0x41,
+	0x00, 0x65, 0x22, 0x41,
X 	0xf7, 0x11, 0x22, 0x08,
-	0x00, 0x65, 0x38, 0x59,
+	0x00, 0x65, 0x42, 0x59,
X 	0xff, 0x06, 0xd4, 0x08,
X 	0xf7, 0x01, 0x02, 0x08,
-	0x09, 0x0c, 0x32, 0x79,
+	0x09, 0x0c, 0x3c, 0x79,
X 	0x08, 0x0c, 0x0e, 0x68,
X 	0x01, 0x6a, 0x22, 0x01,
X 	0xff, 0x6a, 0x26, 0x09,
+	0x02, 0x6a, 0x08, 0x30,
X 	0xff, 0x6a, 0x08, 0x08,
X 	0xdf, 0x01, 0x02, 0x08,
X 	0x01, 0x6a, 0x7a, 0x00,
-	0x03, 0x36, 0x6c, 0x0c,
+	0xff, 0x6a, 0x6c, 0x0c,
+	0x03, 0xa9, 0x18, 0x31,
+	0x03, 0xa9, 0x10, 0x30,
X 	0x08, 0x6a, 0xcc, 0x00,
-	0xa9, 0x6a, 0xe8, 0x5b,
-	0x00, 0x65, 0x66, 0x41,
+	0xa9, 0x6a, 0x08, 0x5c,
+	0x00, 0x65, 0x78, 0x41,
X 	0xa8, 0x6a, 0x6a, 0x00,
X 	0x79, 0x6a, 0x6a, 0x00,
-	0x40, 0x3d, 0x50, 0x69,
+	0x40, 0x3d, 0x60, 0x69,
X 	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x3a, 0x5b,
+	0x00, 0x65, 0x62, 0x5b,
X 	0x80, 0x6a, 0xd4, 0x01,
-	0x10, 0x36, 0x42, 0x69,
+	0x10, 0x36, 0x4e, 0x69,
X 	0x10, 0x36, 0x6c, 0x00,
X 	0x07, 0xac, 0x10, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0x05, 0xa3, 0x70, 0x30,
X 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0xe0, 0x5b,
-	0x00, 0x65, 0xda, 0x5b,
-	0xff, 0xa3, 0x70, 0x08,
-	0x39, 0x6a, 0xcc, 0x00,
-	0xa4, 0x6a, 0xe6, 0x5b,
-	0xff, 0x38, 0x74, 0x69,
+	0xac, 0x6a, 0x00, 0x5c,
+	0x00, 0x65, 0xfa, 0x5b,
+	0x38, 0x6a, 0xcc, 0x00,
+	0xa3, 0x6a, 0x04, 0x5c,
+	0xff, 0x38, 0x88, 0x69,
X 	0x80, 0x02, 0x04, 0x00,
X 	0xe7, 0x35, 0x6a, 0x08,
X 	0x03, 0x69, 0x18, 0x31,
+	0x03, 0x69, 0x10, 0x30,
X 	0xff, 0x6a, 0x10, 0x00,
X 	0xff, 0x6a, 0x12, 0x00,
X 	0xff, 0x6a, 0x14, 0x00,
-	0x01, 0x38, 0x7a, 0x61,
-	0x02, 0xfc, 0xf8, 0x01,
+	0x01, 0x38, 0x8c, 0x61,
X 	0xbf, 0x35, 0x6a, 0x08,
X 	0xff, 0x69, 0xca, 0x08,
X 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x7e, 0x69,
-	0x04, 0x0b, 0x8a, 0x69,
-	0x10, 0x0c, 0x80, 0x79,
-	0x04, 0x0b, 0x88, 0x69,
+	0x04, 0x0b, 0x90, 0x69,
+	0x04, 0x0b, 0x9c, 0x69,
+	0x10, 0x0c, 0x92, 0x79,
+	0x04, 0x0b, 0x9a, 0x69,
X 	0xff, 0x6a, 0xca, 0x08,
-	0x00, 0x35, 0x22, 0x5b,
-	0x80, 0x02, 0xd6, 0x69,
-	0xff, 0x65, 0xc8, 0x79,
+	0x00, 0x35, 0x4a, 0x5b,
+	0x80, 0x02, 0xf0, 0x69,
+	0xff, 0x65, 0xe0, 0x79,
X 	0xff, 0x38, 0x70, 0x18,
-	0xff, 0x38, 0xc8, 0x79,
-	0x80, 0xea, 0xaa, 0x61,
+	0xff, 0x38, 0xe0, 0x79,
+	0x80, 0xea, 0xbc, 0x61,
X 	0xef, 0x38, 0xc8, 0x18,
X 	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0x9c, 0x49,
+	0x00, 0x65, 0xae, 0x49,
X 	0x33, 0x38, 0xc8, 0x28,
X 	0xff, 0x64, 0xd0, 0x09,
X 	0x04, 0x39, 0xc0, 0x31,
X 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0xa2, 0x79,
+	0x80, 0xeb, 0xb4, 0x79,
X 	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0xa6, 0x69,
+	0x08, 0xeb, 0xb8, 0x69,
X 	0x01, 0x6a, 0xd6, 0x01,
X 	0x08, 0xe9, 0x10, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
X 	0x88, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0xe6, 0x5b,
+	0x39, 0x6a, 0x06, 0x5c,
X 	0x08, 0x6a, 0x18, 0x01,
X 	0xff, 0x6a, 0x1a, 0x09,
X 	0xff, 0x6a, 0x1c, 0x09,
X 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x64, 0x5c,
-	0x88, 0x6a, 0x54, 0x5c,
-	0x00, 0x65, 0xda, 0x5b,
+	0x00, 0x65, 0x84, 0x5c,
+	0x88, 0x6a, 0x74, 0x5c,
+	0x00, 0x65, 0xfa, 0x5b,
X 	0xff, 0x6a, 0xc8, 0x08,
X 	0x08, 0x39, 0x72, 0x18,
X 	0x00, 0x3a, 0x74, 0x20,
-	0x10, 0x0c, 0x66, 0x79,
-	0x80, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xe0, 0x59,
+	0x01, 0x0c, 0xd8, 0x79,
+	0x10, 0x0c, 0x78, 0x79,
+	0xff, 0x35, 0x26, 0x09,
+	0x04, 0x0b, 0xde, 0x69,
+	0x00, 0x65, 0xf8, 0x59,
+	0x03, 0x08, 0x52, 0x31,
+	0xff, 0x38, 0x50, 0x09,
X 	0xff, 0x08, 0x52, 0x09,
X 	0xff, 0x09, 0x54, 0x09,
X 	0xff, 0x0a, 0x56, 0x09,
X 	0xff, 0x38, 0x50, 0x09,
-	0x12, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0x18, 0x41,
-	0x00, 0x65, 0xe0, 0x59,
-	0x12, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0x22, 0x41,
+	0x00, 0x65, 0xf8, 0x59,
X 	0x7f, 0x02, 0x04, 0x08,
X 	0xe1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x18, 0x41,
-	0x04, 0x93, 0xea, 0x69,
+	0x00, 0x65, 0x22, 0x41,
+	0x04, 0x93, 0x02, 0x6a,
X 	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0xe4, 0x69,
+	0x20, 0x93, 0xfc, 0x69,
X 	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0xe6, 0x79,
+	0x01, 0x94, 0xfe, 0x79,
X 	0xd7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0xec, 0x69,
+	0x08, 0x93, 0x04, 0x6a,
+	0x03, 0x08, 0x52, 0x31,
+	0xff, 0x38, 0x50, 0x09,
+	0x12, 0x01, 0x02, 0x00,
X 	0xff, 0x6a, 0xd4, 0x0c,
-	0x00, 0x65, 0x3a, 0x5b,
-	0x02, 0xfc, 0xf8, 0x01,
+	0x00, 0x65, 0x62, 0x5b,
X 	0x05, 0xb4, 0x10, 0x31,
X 	0x02, 0x6a, 0x1a, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
X 	0x88, 0x6a, 0xcc, 0x00,
-	0xb4, 0x6a, 0xe4, 0x5b,
+	0xb4, 0x6a, 0x04, 0x5c,
X 	0xff, 0x6a, 0x1a, 0x09,
X 	0xff, 0x6a, 0x1c, 0x09,
-	0x00, 0x65, 0xda, 0x5b,
-	0x3d, 0x6a, 0x22, 0x5b,
-	0xac, 0x6a, 0x22, 0x5b,
-	0x00, 0x65, 0x18, 0x41,
-	0x00, 0x65, 0x3a, 0x5b,
+	0x00, 0x65, 0xfa, 0x5b,
+	0x3d, 0x6a, 0x4a, 0x5b,
+	0xac, 0x6a, 0x26, 0x01,
+	0x04, 0x0b, 0x24, 0x6a,
+	0x01, 0x0b, 0x2a, 0x6a,
+	0x10, 0x0c, 0x26, 0x7a,
+	0xd7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x2c, 0x6a,
+	0x12, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0x22, 0x41,
+	0x00, 0x65, 0x62, 0x5b,
X 	0xff, 0x06, 0x44, 0x09,
-	0x00, 0x65, 0x18, 0x41,
+	0x00, 0x65, 0x22, 0x41,
+	0x10, 0x3d, 0x06, 0x00,
X 	0xff, 0x34, 0xca, 0x08,
-	0x80, 0x65, 0x32, 0x62,
+	0x80, 0x65, 0x5e, 0x62,
X 	0x0f, 0xa1, 0xca, 0x08,
X 	0x07, 0xa1, 0xca, 0x08,
X 	0x40, 0xa0, 0xc8, 0x08,
X 	0x00, 0x65, 0xca, 0x00,
X 	0x80, 0x65, 0xca, 0x00,
-	0x80, 0xa0, 0x22, 0x7a,
+	0x80, 0xa0, 0x4e, 0x7a,
X 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x34, 0x42,
-	0x20, 0xa0, 0x3a, 0x7a,
+	0x00, 0x65, 0x60, 0x42,
+	0x20, 0xa0, 0x66, 0x7a,
X 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0xd2, 0x5b,
-	0xa0, 0x3d, 0x46, 0x62,
+	0x00, 0x65, 0xf2, 0x5b,
+	0xa0, 0x3d, 0x6e, 0x62,
X 	0x23, 0xa0, 0x0c, 0x08,
-	0x00, 0x65, 0xd2, 0x5b,
-	0xa0, 0x3d, 0x46, 0x62,
-	0x00, 0xb9, 0x3a, 0x42,
-	0xff, 0x65, 0x3a, 0x62,
+	0x00, 0x65, 0xf2, 0x5b,
+	0xa0, 0x3d, 0x6e, 0x62,
+	0x00, 0xb9, 0x66, 0x42,
+	0xff, 0x65, 0x66, 0x62,
X 	0xa1, 0x6a, 0x22, 0x01,
X 	0xff, 0x6a, 0xd4, 0x08,
-	0x10, 0x51, 0x46, 0x72,
+	0x10, 0x51, 0x6e, 0x72,
X 	0x40, 0x6a, 0x18, 0x00,
X 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0xd2, 0x5b,
-	0xa0, 0x3d, 0x46, 0x62,
-	0x10, 0x3d, 0x06, 0x00,
-	0x00, 0x65, 0x0e, 0x42,
+	0x00, 0x65, 0xf2, 0x5b,
+	0xa0, 0x3d, 0x38, 0x72,
X 	0x40, 0x6a, 0x18, 0x00,
X 	0xff, 0x34, 0xa6, 0x08,
-	0x80, 0x34, 0x4e, 0x62,
+	0x80, 0x34, 0x76, 0x62,
X 	0x7f, 0xa0, 0x40, 0x09,
X 	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0x18, 0x41,
-	0x64, 0x6a, 0x12, 0x5b,
-	0x80, 0x64, 0xbe, 0x6a,
-	0x04, 0x64, 0xa4, 0x72,
-	0x02, 0x64, 0xaa, 0x72,
-	0x00, 0x6a, 0x6c, 0x72,
-	0x03, 0x64, 0xba, 0x72,
-	0x01, 0x64, 0xa0, 0x72,
-	0x07, 0x64, 0x00, 0x73,
-	0x08, 0x64, 0x68, 0x72,
+	0x00, 0x65, 0x22, 0x41,
+	0x64, 0x6a, 0x3a, 0x5b,
+	0x80, 0x64, 0xea, 0x6a,
+	0x04, 0x64, 0xcc, 0x72,
+	0x02, 0x64, 0xd2, 0x72,
+	0x00, 0x6a, 0x94, 0x72,
+	0x03, 0x64, 0xe6, 0x72,
+	0x01, 0x64, 0xc8, 0x72,
+	0x07, 0x64, 0x28, 0x73,
+	0x08, 0x64, 0x90, 0x72,
X 	0x11, 0x6a, 0x22, 0x01,
-	0x07, 0x6a, 0x04, 0x5b,
+	0x07, 0x6a, 0x2c, 0x5b,
X 	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0x18, 0x41,
-	0xff, 0xa8, 0x70, 0x6a,
-	0xff, 0xa2, 0x88, 0x7a,
+	0x00, 0x65, 0x22, 0x41,
+	0xff, 0xa8, 0x98, 0x6a,
+	0xff, 0xa2, 0xb0, 0x7a,
X 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xfe, 0x5b,
-	0xff, 0xa2, 0x88, 0x7a,
+	0x00, 0xb9, 0x1e, 0x5c,
+	0xff, 0xa2, 0xb0, 0x7a,
X 	0x71, 0x6a, 0x22, 0x01,
X 	0xff, 0x6a, 0xd4, 0x08,
-	0x40, 0x51, 0x88, 0x62,
+	0x40, 0x51, 0xb0, 0x62,
X 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xfe, 0x5b,
+	0x00, 0xb9, 0x1e, 0x5c,
X 	0xff, 0x3e, 0x74, 0x09,
X 	0xff, 0x90, 0x7c, 0x08,
-	0x00, 0x65, 0x44, 0x58,
-	0x00, 0x65, 0x2a, 0x41,
-	0x20, 0xa0, 0x90, 0x6a,
+	0x00, 0x65, 0x50, 0x58,
+	0x00, 0x65, 0x34, 0x41,
+	0x20, 0xa0, 0xb8, 0x6a,
X 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0xa8, 0x5b,
-	0xff, 0x6a, 0xbe, 0x5b,
+	0x00, 0x6a, 0xc8, 0x5b,
+	0xff, 0x6a, 0xde, 0x5b,
X 	0xff, 0xf8, 0xc8, 0x08,
X 	0xff, 0x4f, 0xc8, 0x08,
-	0x01, 0x6a, 0xa8, 0x5b,
-	0x00, 0xb9, 0xbe, 0x5b,
+	0x01, 0x6a, 0xc8, 0x5b,
+	0x00, 0xb9, 0xde, 0x5b,
X 	0x01, 0x4f, 0x9e, 0x18,
X 	0x02, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x6c, 0x5c,
-	0x00, 0x65, 0x2a, 0x41,
+	0x00, 0x65, 0x8c, 0x5c,
+	0x00, 0x65, 0x34, 0x41,
X 	0x41, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x18, 0x41,
+	0x00, 0x65, 0x22, 0x41,
X 	0x04, 0xa0, 0x40, 0x01,
-	0x00, 0x65, 0x84, 0x5c,
-	0x00, 0x65, 0x2a, 0x41,
-	0x10, 0x36, 0x68, 0x7a,
-	0xff, 0x38, 0x46, 0x09,
-	0xa4, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0xe6, 0x5b,
+	0x00, 0x65, 0xa4, 0x5c,
+	0x00, 0x65, 0x34, 0x41,
+	0x10, 0x36, 0x90, 0x7a,
+	0x05, 0x38, 0x46, 0x31,
+	0x04, 0x14, 0x58, 0x31,
+	0x03, 0xa9, 0x60, 0x31,
+	0xa3, 0x6a, 0xcc, 0x00,
+	0x38, 0x6a, 0x04, 0x5c,
X 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xe6, 0x5b,
-	0xa9, 0x6a, 0xe8, 0x5b,
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 14'
echo 'File patch-2.3.6 is continued in part 15'
echo 15 > _shar_seq_.tmp
#!/bin/sh
# this is part 16 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 16; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+    if(schp->use_sg > 0) {
+        int k, mem_src;
+        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+        for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
X             mem_src = (int)(long)sclp->alt_address;
X             SCSI_LOG_TIMEOUT(5, 
-                printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n", 
+                printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", 
X                        k, sclp->address, sclp->length, mem_src));
-            sg_free(srp, sclp->address, sclp->length, mem_src);
+            sg_free(sclp->address, sclp->length, mem_src);
+            sclp->address = NULL;
+            sclp->length = 0;
+        }
+        sg_free(schp->buffer, schp->sglist_len, schp->mem_src);
+    }
+    else if (schp->buffer)
+        sg_free(schp->buffer, schp->b_malloc_len, schp->mem_src);
+    schp->buffer = NULL;
+    schp->bufflen = 0;
+    schp->use_sg = 0;
+    schp->sglist_len = 0;
+}
+
+static void sg_read_xfer(Sg_scatter_hold * schp, char * outp,
+                         int num_read_xfer)
+{
+    SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_read_xfer=%d\n", 
+                               num_read_xfer)); 
+    if ((! outp) || (num_read_xfer <= 0))
+        return;
+    if(schp->use_sg > 0) {
+        int k, num;
+        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+        for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
+            num = (int)sclp->length;
+            if (num > num_read_xfer) {
+                __copy_to_user(outp, sclp->address, num_read_xfer);
+                break;
+            }
+            else {
+                __copy_to_user(outp, sclp->address, num);
+                num_read_xfer -= num;
+                if (num_read_xfer <= 0)
+                    break;
+                outp += num;
+            }
X         }
-        sg_free(srp, srp->data.buffer, srp->data.sglist_len, 
-                srp->data.mem_src);
+    }
+    else
+        __copy_to_user(outp, schp->buffer, num_read_xfer);
+}
+
+static void sg_build_reserve(Sg_fd * sfp, int req_size)
+{
+    Sg_scatter_hold * schp = &sfp->reserve;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size)); 
+    do {
+        if (req_size < PAGE_SIZE)
+            req_size = PAGE_SIZE;
+        if (0 == sg_build_scat(schp, req_size, sfp))
+            return;
+        else
+            sg_remove_scat(schp);
+        req_size >>= 1; /* divide by 2 */
+    } while (req_size >  (PAGE_SIZE / 2));
+}
+
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
+{
+    Sg_scatter_hold * req_schp = &srp->data;
+    Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); 
+    if (rsv_schp->use_sg > 0) {
+        int k, num;
+        int rem = size;
+        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+        for (k = 0; k < rsv_schp->use_sg; ++k, ++sclp) {
+            num = (int)sclp->length;
+            if (rem <= num) {
+                sfp->save_scat_len = num;
+                sclp->length = (unsigned)rem;
+                break;
+            }
+            else
+                rem -= num;
+        }
+        if (k < rsv_schp->use_sg) {
+            req_schp->use_sg = k + 1;   /* adjust scatter list length */
+            req_schp->bufflen = size;
+            req_schp->sglist_len = rsv_schp->sglist_len;
+            req_schp->buffer = rsv_schp->buffer;
+            req_schp->mem_src = rsv_schp->mem_src;
+            req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+        }
+        else
+            SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n")); 
X     }
X     else {
-        if (num_read_xfer > 0) 
-            __copy_to_user(outp, srp->data.buffer, num_read_xfer);
-        sg_free(srp, srp->data.buffer, srp->data.b_malloc_len, 
-                srp->data.mem_src);
-    }
-    if (0 == sg_remove_request(srp->parentfp, srp)) {
-        SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n", 
-                                   srp));
+        req_schp->use_sg = 0;
+        req_schp->bufflen = size;
+        req_schp->buffer = rsv_schp->buffer;
+        req_schp->mem_src = rsv_schp->mem_src;
+        req_schp->use_sg = rsv_schp->use_sg;
+        req_schp->b_malloc_len = rsv_schp->b_malloc_len;
X     }
-    return 0;
+    srp->res_used = 1;
+}
+
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
+{
+    Sg_scatter_hold * req_schp = &srp->data;
+    Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+    SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->use_sg=%d\n",
+                               (int)req_schp->use_sg)); 
+    if (rsv_schp->use_sg > 0) {
+        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+        if (sfp->save_scat_len > 0) 
+            (sclp + (req_schp->use_sg - 1))->length = 
+                                        (unsigned)sfp->save_scat_len;
+        else
+            SCSI_LOG_TIMEOUT(1, printk(
+                        "sg_unlink_reserve: BAD save_scat_len\n")); 
+    }
+    req_schp->use_sg = 0;
+    req_schp->bufflen = 0;
+    req_schp->buffer = NULL;
+    req_schp->sglist_len = 0;
+    sfp->save_scat_len = 0;
+    srp->res_used = 0;
X }
X 
X static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id)
@@ -1292,7 +1449,7 @@
X     if (resp) {
X         resp->parentfp = sfp;
X         resp->nextrp = NULL;
-        resp->fb_used = 0;
+        resp->res_used = 0;
X         memset(&resp->data, 0, sizeof(Sg_scatter_hold));
X         memset(&resp->header, 0, sizeof(struct sg_header));
X         resp->my_cmdp = NULL;
@@ -1347,13 +1504,6 @@
X                    sdp->device->host->unchecked_isa_dma : 1;
X     sfp->cmd_q = SG_DEF_COMMAND_Q;
X     sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG;
-    if (get_reserved)
-        sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, 
-                                     SG_HEAP_PAGE, &sfp->fb_size);
-    else
-        sfp->fst_buf = NULL;
-    if (! sfp->fst_buf)
-        sfp->fb_size = 0;
X     sfp->parentdp = sdp;
X     if (! sdp->headfp)
X         sdp->headfp = sfp;
@@ -1363,11 +1513,14 @@
X            pfp = pfp->nextfp;
X         pfp->nextfp = sfp;
X     }
-    sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */
X     SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
X                                sfp, (int)sfp->my_mem_src));
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   fb_sz=%d, fst_buf=0x%p\n",
-                               sfp->fb_size, sfp->fst_buf));
+    if (get_reserved) {
+        sg_build_reserve(sfp, SG_DEF_RESERVED_SIZE);
+        sg_big_buff = sfp->reserve.bufflen; /* sysctl shows most recent size */
+        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, use_sg=%d\n",
+                               sfp->reserve.bufflen, sfp->reserve.use_sg));
+    }
X     return sfp;
X }
X 
@@ -1388,7 +1541,7 @@
X         while (srp) {
X             tsrp = srp->nextrp;
X             if (! srp->my_cmdp)
-                sg_sc_undo_rem(srp, NULL, 0);
+                sg_finish_rem_req(srp, NULL, 0);
X             else
X                 ++dirty;
X             srp = tsrp;
@@ -1409,12 +1562,12 @@
X                 prev_fp = fp;
X             }
X         }
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    fb_sz=%d, fst_buf=0x%p\n",
-                 sfp->fb_size, sfp->fst_buf));
-        sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
+        if (sfp->reserve.bufflen > 0) {
+SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    bufflen=%d, use_sg=%d\n",
+                 (int)sfp->reserve.bufflen, (int)sfp->reserve.use_sg));
+            sg_remove_scat(&sfp->reserve);
+        }
X         sfp->parentdp = NULL;
-        sfp->fst_buf = NULL;
-        sfp->fb_size = 0;
X     SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%p\n", sfp));
X         sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src);
X         res = 1;
@@ -1427,12 +1580,12 @@
X     return res;
X }
X 
-static int sg_fb_in_use(const Sg_fd * sfp)
+static int sg_res_in_use(const Sg_fd * sfp)
X {
X     const Sg_request * srp = sfp->headrp;
X 
X     while (srp) {
-        if (srp->fb_used)
+        if (srp->res_used)
X             return 1;
X         srp = srp->nextrp;
X     }
@@ -1511,7 +1664,7 @@
X     return resp;
X }
X 
-static char * sg_malloc(Sg_request * srp, int size, int * retSzp, 
+static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, 
X                         int * mem_srcp)
X {
X     char * resp = NULL;
@@ -1520,26 +1673,16 @@
X     if (size <= 0)
X         ;
X     else {
-        Sg_fd * sfp = srp->parentfp;
X         int low_dma = sfp->low_dma;
X         int l_ms = -1;  /* invalid value */
X 
X         switch (*mem_srcp) 
X         {
X         case SG_HEAP_PAGE:
-        case SG_HEAP_FB:
X             l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
X             resp = sg_low_malloc(size, low_dma, l_ms, 0);
X             if (resp)
X                 break;
-            if ((size <= sfp->fb_size) && (0 == sg_fb_in_use(sfp))) {
-                SCSI_LOG_TIMEOUT(6,
-                    printk("sg_malloc: scsi_malloc failed, get fst_buf\n"));
-                resp = sfp->fst_buf;
-                srp->fb_used = 1;
-                l_ms = SG_HEAP_FB;
-                break;
-            }
X             resp = sg_low_malloc(size, low_dma, l_ms, &size);
X             if (! resp) {
X                 l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
@@ -1595,18 +1738,12 @@
X                mem_src, buff, size);
X }
X 
-static void sg_free(Sg_request * srp, char * buff, int size, int mem_src)
+static void sg_free(char * buff, int size, int mem_src)
X {
-    Sg_fd * sfp = srp->parentfp;
-
X     SCSI_LOG_TIMEOUT(6, 
X         printk("sg_free: buff=0x%p, size=%d\n", buff, size));
-    if ((! sfp) || (! buff) || (size <= 0))
+    if ((! buff) || (size <= 0))
X         ;
-    else if (sfp->fst_buf == buff) {
-        srp->fb_used = 0;
-        SCSI_LOG_TIMEOUT(6, printk("sg_free:   left cause fst_buf\n"));
-    }
X     else
X         sg_low_free(buff, size, mem_src);
X }
diff -u --recursive --new-file v2.3.5/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.3.5/linux/drivers/sound/dmasound.c	Fri May 14 18:55:22 1999
+++ linux/drivers/sound/dmasound.c	Mon Jun  7 12:12:22 1999
@@ -784,6 +784,7 @@
X 
X struct sound_mixer {
X     int busy;
+    int modify_counter;
X };
X 
X static struct sound_mixer mixer;
@@ -3811,10 +3812,23 @@
X 		       u_long arg)
X {
X 	int data;
+	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+	    mixer.modify_counter++;
+	if (cmd == OSS_GETVERSION)
+	    return IOCTL_OUT(arg, SOUND_VERSION);
X 	switch (sound.mach.type) {
X #ifdef CONFIG_ATARI
X 	case DMASND_FALCON:
X 		switch (cmd) {
+		case SOUND_MIXER_INFO: {
+		    mixer_info info;
+		    strncpy(info.id, "FALCON", sizeof(info.id));
+		    strncpy(info.name, "FALCON", sizeof(info.name));
+		    info.name[sizeof(info.name)-1] = 0;
+		    info.modify_counter = mixer.modify_counter;
+		    copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
+		    return 0;
+		}
X 		case SOUND_MIXER_READ_DEVMASK:
X 			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
X 		case SOUND_MIXER_READ_RECMASK:
@@ -3866,6 +3880,15 @@
X 
X 	case DMASND_TT:
X 		switch (cmd) {
+		case SOUND_MIXER_INFO: {
+		    mixer_info info;
+		    strncpy(info.id, "TT", sizeof(info.id));
+		    strncpy(info.name, "TT", sizeof(info.name));
+		    info.name[sizeof(info.name)-1] = 0;
+		    info.modify_counter = mixer.modify_counter;
+		    copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
+		    return 0;
+		}
X 		case SOUND_MIXER_READ_DEVMASK:
X 			return IOCTL_OUT(arg,
X 					 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
@@ -3927,6 +3950,15 @@
X #ifdef CONFIG_AMIGA
X 	case DMASND_AMIGA:
X 		switch (cmd) {
+		case SOUND_MIXER_INFO: {
+		    mixer_info info;
+		    strncpy(info.id, "AMIGA", sizeof(info.id));
+		    strncpy(info.name, "AMIGA", sizeof(info.name));
+		    info.name[sizeof(info.name)-1] = 0;
+		    info.modify_counter = mixer.modify_counter;
+		    copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
+		    return 0;
+		}
X 		case SOUND_MIXER_READ_DEVMASK:
X 			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
X 		case SOUND_MIXER_READ_RECMASK:
@@ -3953,6 +3985,16 @@
X 	case DMASND_AWACS:
X 		if (awacs_revision<AWACS_BURGUNDY) { /* Different IOCTLS for burgundy*/
X 			switch (cmd) {
+			case SOUND_MIXER_INFO: {
+			    mixer_info info;
+			    strncpy(info.id, "AWACS", sizeof(info.id));
+			    strncpy(info.name, "AWACS", sizeof(info.name));
+			    info.name[sizeof(info.name)-1] = 0;
+			    info.modify_counter = mixer.modify_counter;
+			    copy_to_user_ret((int *)arg, &info, 
+					     sizeof(info), -EFAULT);
+			    return 0;
+			}
X 			case SOUND_MIXER_READ_DEVMASK:
X 				data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
X 					| SOUND_MASK_LINE | SOUND_MASK_MIC
@@ -4066,6 +4108,16 @@
X 		} else {
X 			/* We are, we are, we are... Burgundy or better */
X 			switch(cmd) {
+			case SOUND_MIXER_INFO: {
+			    mixer_info info;
+			    strncpy(info.id, "AWACS", sizeof(info.id));
+			    strncpy(info.name, "AWACS", sizeof(info.name));
+			    info.name[sizeof(info.name)-1] = 0;
+			    info.modify_counter = mixer.modify_counter;
+			    copy_to_user_ret((int *)arg, &info, 
+					     sizeof(info), -EFAULT);
+			    return 0;
+			}
X 			case SOUND_MIXER_READ_DEVMASK:
X 				data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
X 					SOUND_MASK_LINE | SOUND_MASK_MIC |
diff -u --recursive --new-file v2.3.5/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.3.5/linux/drivers/sound/sound_core.c	Mon May 31 22:28:06 1999
+++ linux/drivers/sound/sound_core.c	Mon Jun  7 11:06:10 1999
@@ -52,6 +52,22 @@
X 	struct sound_unit *next;
X };
X 
+#ifdef CONFIG_SOUND_SONICVIBES
+extern int init_sonicvibes(void);
+#endif
+#ifdef CONFIG_SOUND_ES1370
+extern int init_es1370(void);
+#endif
+#ifdef CONFIG_SOUND_ES1371
+extern int init_es1371(void);
+#endif
+#ifdef CONFIG_SOUND_MSNDCLAS
+extern int msnd_classic_init(void);
+#endif
+#ifdef CONFIG_SOUND_MSNDPIN
+extern int msnd_pinnacle_init(void);
+#endif
+
X /*
X  *	Low level list operator. Scan the ordered list, find a hole and
X  *	join into it. Called with the lock asserted
@@ -132,7 +148,7 @@
X  *	This lock guards the sound loader list.
X  */
X 
-static spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
X 
X /*
X  *	Allocate the controlling structure and add it to the sound driver
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS
--- v2.3.5/linux/drivers/usb/CREDITS	Tue May 11 10:04:03 1999
+++ linux/drivers/usb/CREDITS	Tue Jun  8 10:52:26 1999
@@ -8,6 +8,7 @@
X   Johannes Erdfelt <jerd...@sventech.com>
X   ham <h...@unsuave.com>
X   Bradley M Keryan <ker...@andrew.cmu.edu>
+  Paul Mackerras <pau...@cs.anu.edu.au>
X   Vojtech Pavlik <voj...@twilight.ucw.cz>
X   Gregory P. Smith <gr...@electricrain.com>
X   Linus Torvalds <torv...@transmeta.com>
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.5/linux/drivers/usb/Config.in	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/Config.in	Mon Jun  7 20:04:01 1999
@@ -29,7 +29,11 @@
X   dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
X   dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
X   dep_tristate 'USB Abstract Control Model support' CONFIG_USB_ACM $CONFIG_USB
-  dep_tristate 'Preliminary USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+  dep_tristate 'USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+  dep_tristate 'USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
+  if [ "$CONFIG_USB_SCSI" != "n" ]; then
+	  dep_tristate '  USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
+  fi
X fi
X 
X endmenu
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.5/linux/drivers/usb/Makefile	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/Makefile	Tue Jun  8 10:52:26 1999
@@ -109,6 +109,13 @@
X   MIX_OBJS += cpia.o
X endif
X 
+ifeq ($(CONFIG_USB_SCSI),y)
+  L_OBJS += usb_scsi.o
+  ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
+    L_OBJS += usb_scsi_debug.o
+  endif
+endif
+
X include $(TOPDIR)/Rules.make
X 
X keymap.o: keymap.c
@@ -116,8 +123,17 @@
X keymap.c: maps/serial.map maps/usb.map maps/fixup.map
X 	./mkmap > $@
X 
+keymap-mac.o: keymap-mac.c
+keymap-mac.c: maps/mac.map maps/usb.map
+	./mkmap.adb > $@
+
+ifneq ($(CONFIG_MAC_KEYBOARD),y)
X usb-keyboard.o: keymap.o keyboard.o
X 	$(LD) $(LD_RFLAG) -r -o $@  keymap.o keyboard.o 
+else
+usb-keyboard.o: keymap-mac.o keyboard.o
+	$(LD) $(LD_RFLAG) -r -o $@  keymap-mac.o keyboard.o 
+endif
X 
X usb-uhci.o: uhci.o uhci-debug.o 
X 	$(LD) $(LD_RFLAG) -r -o $@  uhci.o uhci-debug.o 
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/README.ohci linux/drivers/usb/README.ohci
--- v2.3.5/linux/drivers/usb/README.ohci	Mon May 17 09:55:22 1999
+++ linux/drivers/usb/README.ohci	Tue Jun  8 10:52:26 1999
@@ -1,3 +1,9 @@
+June 08, 1999 01:23:34
+
+Paul Mackerras went through the OHCI (& USB code) to fix most of the
+endianness issues so that the code now works on Linux-PPC.  He also
+simplified add_td_to_ed to be simpler & atomic to the hardware.
+
X May 16, 1999 16:20:54
X 
X EDs are now allocated dynamically from their device's pool.  Root hub
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.5/linux/drivers/usb/acm.c	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/acm.c	Fri Jun  4 13:33:43 1999
@@ -198,7 +198,7 @@
X 	/*Now scan all configs for a ACM configuration*/
X 	for (cfgnum=0;cfgnum<dev->descriptor.bNumConfigurations;cfgnum++) {
X 		/* The first one should be Communications interface? */
-		interface = &dev->config[cfgnum].interface[0];
+		interface = &dev->config[cfgnum].altsetting[0].interface[0];
X 		if (interface->bInterfaceClass != 2 ||
X 		    interface->bInterfaceSubClass != 2 ||
X 		    interface->bInterfaceProtocol != 1 ||
@@ -212,7 +212,7 @@
X 			continue;
X 			
X 		/* The second one should be a Data interface? */
-		interface = &dev->config[cfgnum].interface[1];
+		interface = &dev->config[cfgnum].altsetting[0].interface[1];
X 		if (interface->bInterfaceClass != 10 ||
X 		    interface->bInterfaceSubClass != 0 ||
X 		    interface->bInterfaceProtocol != 0 ||
@@ -234,12 +234,12 @@
X 		printk("USB ACM found\n");
X 		usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
X 		acm->dev=dev;
-		acm->readendp=dev->config[cfgnum].interface[1].endpoint[0].bEndpointAddress;
-		acm->writeendp=dev->config[cfgnum].interface[1].endpoint[1].bEndpointAddress;
-		acm->ctrlendp=dev->config[cfgnum].interface[0].endpoint[0].bEndpointAddress;
+		acm->readendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].bEndpointAddress;
+		acm->writeendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].bEndpointAddress;
+		acm->ctrlendp=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bEndpointAddress;
X 		acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp);
X 		acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp);
-		usb_request_irq(dev,acm->ctrlpipe=usb_rcvctrlpipe(dev,acm->ctrlendp), acm_irq, dev->config[cfgnum].interface[0].endpoint[0].bInterval, &acm->ctrlbuffer);
+		usb_request_irq(dev,acm->ctrlpipe=usb_rcvctrlpipe(dev,acm->ctrlendp), acm_irq, dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bInterval, &acm->ctrlbuffer);
X 		acm->present = 1;
X 		acm->buffer=0;
X 		return 0;
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.5/linux/drivers/usb/audio.c	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/audio.c	Fri Jun  4 13:33:43 1999
@@ -42,7 +42,7 @@
X 	int i;
X 	int na=0;
X 	
-	interface = &dev->config[0].interface[0];
+	interface = &dev->config[0].altsetting[0].interface[0];
X 
X 	for(i=0;i<dev->config[0].bNumInterfaces;i++)
X 	{
@@ -133,7 +133,7 @@
X 	return usb_audio_init();
X }
X 
-void module_cleanup(void)
+void cleanup_module(void)
X {
X 	usb_deregister(&usb_audio_driver);
X }
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.5/linux/drivers/usb/cpia.c	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/cpia.c	Fri Jun  4 13:33:43 1999
@@ -1164,7 +1164,7 @@
X 		return -1;
X #endif
X 
-	interface = &dev->config[0].interface[0];
+	interface = &dev->config[0].altsetting[0].interface[0];
X 
X 	/* Is it a CPiA? */
X /*
@@ -1260,7 +1260,7 @@
X {
X 	return usb_cpia_init();
X }
-void module_cleanup(void)
+void cleanup_module(void)
X {
X }
X #endif
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.5/linux/drivers/usb/hub.c	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/hub.c	Tue Jun  8 10:52:26 1999
@@ -159,7 +159,7 @@
X 	if (dev->config[0].bNumInterfaces != 1)
X 		return -1;
X 
-	interface = &dev->config[0].interface[0];
+	interface = &dev->config[0].altsetting[0].interface[0];
X 
X 	/* Is it a hub? */
X 	if (interface->bInterfaceClass != 9)
@@ -241,8 +241,8 @@
X 		return;
X 	}
X 
-	portstatus = *((unsigned short *)buf + 0);
-	portchange = *((unsigned short *)buf + 1);
+	portstatus = le16_to_cpup((unsigned short *)buf + 0);
+	portchange = le16_to_cpup((unsigned short *)buf + 1);
X 
X 	if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
X 		(!(portstatus & USB_PORT_STAT_ENABLE))) {
@@ -294,8 +294,8 @@
X 				continue;
X 			}
X 
-			portstatus = *((unsigned short *)buf + 0);
-			portchange = *((unsigned short *)buf + 1);
+			portstatus = le16_to_cpup((unsigned short *)buf + 0);
+			portchange = le16_to_cpup((unsigned short *)buf + 1);
X 
X 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
X 				printk("hub: port %d connection change\n", i + 1);
@@ -421,7 +421,7 @@
X 	return usb_hub_init();
X }
X 
-void module_cleanup(void){
+void cleanup_module(void){
X 	usb_hub_cleanup();
X }
X #endif
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/keyboard.c linux/drivers/usb/keyboard.c
--- v2.3.5/linux/drivers/usb/keyboard.c	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/keyboard.c	Tue Jun  8 10:52:26 1999
@@ -56,10 +56,12 @@
X     int scancode = (int) usb_kbd_map[key];
X     if(scancode)
X     {
+#ifndef CONFIG_MAC_KEYBOARD
X         if(scancode & PCKBD_NEEDS_E0)
X         {
X             handle_scancode(0xe0, 1);
X         }
+#endif /* CONFIG_MAC_KEYBOARD */
X         handle_scancode((scancode & ~PCKBD_NEEDS_E0), down);
X     }
X }
@@ -171,7 +173,10 @@
X     struct usb_endpoint_descriptor *endpoint;
X     struct usb_keyboard *kbd;
X 
-    interface = &dev->config[0].interface[0];
+    if (dev->descriptor.bNumConfigurations < 1)
+	return -1;
+
+    interface = &dev->config[0].altsetting[0].interface[0];
X     endpoint = &interface->endpoint[0];
X 
X     if(interface->bInterfaceClass != 3
@@ -233,7 +238,7 @@
X 	return usb_kbd_init();
X }
X 
-void module_cleanup(void)
+void cleanup_module(void)
X {
X 	usb_deregister(&usb_kbd_driver);
X }
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/keymap-mac.c linux/drivers/usb/keymap-mac.c
--- v2.3.5/linux/drivers/usb/keymap-mac.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/keymap-mac.c	Tue Jun  8 10:52:26 1999
@@ -0,0 +1,50 @@
+unsigned char usb_kbd_map[256] = 
+{
+    0x00,  0x00,  0x00,  0x00,  0x80,  0x0b,  0x08,  0x02,
+    0x0e,  0x03,  0x05,  0x04,  0x22,  0x26,  0x28,  0x25,
+
+    0x2e,  0x2d,  0x1f,  0x23,  0x0c,  0x0f,  0x01,  0x11,
+    0x20,  0x09,  0x0d,  0x07,  0x10,  0x06,  0x12,  0x13,
+
+    0x14,  0x15,  0x17,  0x16,  0x1a,  0x1c,  0x19,  0x1d,
+    0x24,  0x35,  0x33,  0x30,  0x31,  0x1b,  0x18,  0x21,
+
+    0x1e,  0x2a,  0x00,  0x29,  0x27,  0x32,  0x2b,  0x2f,
+    0x2c,  0x39,  0x7a,  0x78,  0x63,  0x76,  0x60,  0x61,
+
+    0x62,  0x64,  0x65,  0x6d,  0x67,  0x6f,  0x69,  0x6b,
+    0x71,  0x72,  0x73,  0x74,  0x75,  0x77,  0x79,  0x3c,
+
+    0x3b,  0x3d,  0x3e,  0x47,  0x4b,  0x43,  0x4e,  0x45,
+    0x4c,  0x53,  0x54,  0x55,  0x56,  0x57,  0x58,  0x59,
+
+    0x5b,  0x5c,  0x52,  0x41,  0x00,  0x00,  0x00,  0x00,
+    0x69,  0x6b,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x36,  0x38,  0x3a,  0x37,  0x7d,  0x7b,  0x7c,  0x37,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+};
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/maps/mac.map linux/drivers/usb/maps/mac.map
--- v2.3.5/linux/drivers/usb/maps/mac.map	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/maps/mac.map	Tue Jun  8 10:52:26 1999
@@ -0,0 +1,350 @@
+# Kernel keymap for Macintoshes. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+#
+# Fixups:
+keycode 0x69 = Print_Screen
+keycode 0x6b = F14
+keycode 0x37 = Window_R
+#
+#keycode 0x00 = a
+# hack!
+keycode 0x80 = a
+	altgr   keycode 0x00 = Hex_A
+keycode 0x01 = s               
+keycode 0x02 = d
+	altgr   keycode 0x02 = Hex_D   
+keycode 0x03 = f
+	altgr   keycode 0x03 = Hex_F               
+keycode 0x04 = h               
+keycode 0x05 = g  
+keycode 0x06 = z
+keycode 0x07 = x               
+keycode 0x08 = c
+	altgr   keycode 0x08 = Hex_C   
+keycode 0x09 = v
+keycode 0x0a =
+keycode 0x0b = b
+	altgr   keycode 0x0b = Hex_B
+keycode 0x0c = q               
+keycode 0x0d = w               
+keycode 0x0e = e
+	altgr   keycode 0x0e = Hex_E   
+keycode 0x0f = r               
+keycode 0x10 = y               
+keycode 0x11 = t               
+keycode 0x12 = one              exclam          
+	alt     keycode 0x12 = Meta_one        
+keycode 0x13 = two              at               at              
+	control	keycode 0x13 = nul             
+	shift	control	keycode 0x13 = nul             
+	alt	keycode 0x13 = Meta_two        
+keycode 0x14 = three            numbersign      
+	control keycode 0x14 = Escape          
+	alt     keycode 0x14 = Meta_three      
+keycode 0x15 = four             dollar           dollar          
+	control keycode 0x15 = Control_backslash
+	alt     keycode 0x15 = Meta_four       
+keycode 0x16 = six              asciicircum     
+	control keycode 0x16 = Control_asciicircum
+	alt     keycode 0x16 = Meta_six        
+keycode 0x17 = five             percent         
+	control keycode 0x17 = Control_bracketright
+	alt     keycode 0x17 = Meta_five       
+keycode 0x18 = equal            plus            
+	alt     keycode 0x18 = Meta_equal      
+keycode 0x19 = nine             parenleft        bracketright    
+	alt     keycode 0x19 = Meta_nine       
+keycode 0x1a = seven            ampersand        braceleft       
+	control keycode 0x1a = Control_underscore
+	alt     keycode 0x1a = Meta_seven      
+keycode 0x1b = minus            underscore       backslash       
+	control	keycode 0x1b = Control_underscore
+	shift	control	keycode 0x1b = Control_underscore
+	alt	keycode 0x1b = Meta_minus      
+keycode 0x1c = eight            asterisk         bracketleft     
+	control keycode 0x1c = Delete          
+	alt     keycode 0x1c = Meta_eight      
+keycode 0x1d = zero             parenright       braceright      
+	alt     keycode 0x1d = Meta_zero       
+keycode 0x1e = bracketright     braceright       asciitilde      
+	control keycode 0x1e = Control_bracketright
+	alt     keycode 0x1e = Meta_bracketright
+keycode 0x1f = o               
+keycode 0x20 = u               
+keycode 0x21 = bracketleft      braceleft       
+	control keycode 0x21 = Escape          
+	alt     keycode 0x21 = Meta_bracketleft
+keycode 0x22 = i               
+keycode 0x23 = p               
+keycode 0x24 = Return          
+	alt     keycode 0x24 = Meta_Control_m  
+keycode 0x25 = l               
+keycode 0x26 = j               
+keycode 0x27 = apostrophe       quotedbl        
+	control keycode 0x27 = Control_g       
+	alt     keycode 0x27 = Meta_apostrophe 
+keycode 0x28 = k               
+keycode 0x29 = semicolon        colon           
+	alt     keycode 0x29 = Meta_semicolon  
+keycode 0x2a = backslash        bar             
+	control keycode 0x2a = Control_backslash
+	alt     keycode 0x2a = Meta_backslash  
+keycode 0x2b = comma            less            
+	alt     keycode 0x2b = Meta_comma      
+keycode 0x2c = slash            question        
+	control keycode 0x2c = Delete          
+	alt     keycode 0x2c = Meta_slash      
+keycode 0x2d = n
+keycode 0x2e = m               
+keycode 0x2f = period           greater         
+	control keycode 0x2f = Compose         
+	alt     keycode 0x2f = Meta_period     
+keycode 0x30 = Tab              Tab             
+	alt     keycode 0x30 = Meta_Tab        
+keycode 0x31 = space            space           
+	control keycode 0x31 = nul             
+	alt     keycode 0x31 = Meta_space      
+keycode 0x32 = grave            asciitilde      
+	control keycode 0x32 = nul             
+	alt     keycode 0x32 = Meta_grave      
+keycode 0x33 = Delete           Delete          
+	control keycode 0x33 = BackSpace
+	alt     keycode 0x33 = Meta_Delete     
+keycode 0x34 =
+keycode 0x35 = Escape           Escape          
+	alt     keycode 0x35 = Meta_Escape     
+keycode 0x36 = Control         
+keycode 0x37 = Window             
+keycode 0x38 = Shift
+keycode 0x39 = Caps_Lock       
+keycode 0x3a = Alt
+keycode 0x3b = Left            
+	alt     keycode 0x3b = Decr_Console
+keycode 0x3c = Right           
+	alt     keycode 0x3c = Incr_Console
+keycode 0x3d = Down            
+keycode 0x3e = Up              
+keycode 0x3f =
+keycode 0x40 =
+keycode 0x41 = KP_Period       
+keycode 0x42 =
+keycode 0x43 = KP_Multiply     
+keycode 0x44 =
+keycode 0x45 = KP_Add          
+keycode 0x46 =
+keycode 0x47 = Num_Lock
+#	shift   keycode 0x47 = Bare_Num_Lock
+keycode 0x48 =
+keycode 0x49 =
+keycode 0x4a =
+keycode 0x4b = KP_Divide       
+keycode 0x4c = KP_Enter        
+keycode 0x4d =
+keycode 0x4e = KP_Subtract     
+keycode 0x4f =
+keycode 0x50 =
+keycode 0x51 =
+#keycode 0x51 = KP_Equals
+keycode 0x52 = KP_0            
+	alt     keycode 0x52 = Ascii_0         
+	altgr   keycode 0x52 = Hex_0         
+keycode 0x53 = KP_1            
+	alt     keycode 0x53 = Ascii_1         
+	altgr   keycode 0x53 = Hex_1         
+keycode 0x54 = KP_2            
+	alt     keycode 0x54 = Ascii_2         
+	altgr   keycode 0x54 = Hex_2         
+keycode 0x55 = KP_3            
+	alt     keycode 0x55 = Ascii_3         
+	altgr   keycode 0x55 = Hex_3         
+keycode 0x56 = KP_4            
+	alt     keycode 0x56 = Ascii_4         
+	altgr   keycode 0x56 = Hex_4         
+keycode 0x57 = KP_5            
+	alt     keycode 0x57 = Ascii_5         
+	altgr   keycode 0x57 = Hex_5         
+keycode 0x58 = KP_6            
+	alt     keycode 0x58 = Ascii_6         
+	altgr   keycode 0x58 = Hex_6         
+keycode 0x59 = KP_7            
+	alt     keycode 0x59 = Ascii_7         
+	altgr   keycode 0x59 = Hex_7
+keycode 0x5b = KP_8            
+	alt     keycode 0x5b = Ascii_8         
+	altgr   keycode 0x5b = Hex_8         
+keycode 0x5c = KP_9            
+	alt     keycode 0x5c = Ascii_9         
+	altgr   keycode 0x5c = Hex_9         
+keycode 0x5d =
+keycode 0x5e =
+keycode 0x5f =
+keycode 0x60 = F5               F15              Console_17      
+	control keycode 0x60 = F5              
+	alt     keycode 0x60 = Console_5       
+	control alt     keycode 0x60 = Console_5       
+keycode 0x61 = F6               F16              Console_18      
+	control keycode 0x61 = F6              
+	alt     keycode 0x61 = Console_6       
+	control alt     keycode 0x61 = Console_6       
+keycode 0x62 = F7               F17              Console_19      
+	control keycode 0x62 = F7              
+	alt     keycode 0x62 = Console_7       
+	control alt     keycode 0x62 = Console_7       
+keycode 0x63 = F3               F13              Console_15      
+	control keycode 0x63 = F3              
+	alt     keycode 0x63 = Console_3       
+	control alt     keycode 0x63 = Console_3       
+keycode 0x64 = F8               F18              Console_20      
+	control keycode 0x64 = F8              
+	alt     keycode 0x64 = Console_8       
+	control alt     keycode 0x64 = Console_8       
+keycode 0x65 = F9               F19              Console_21      
+	control keycode 0x65 = F9              
+	alt     keycode 0x65 = Console_9       
+	control alt     keycode 0x65 = Console_9       
+keycode 0x66 =
+keycode 0x67 = F11              F11              Console_23      
+	control keycode 0x67 = F11             
+	alt     keycode 0x67 = Console_11      
+	control alt     keycode 0x67 = Console_11      
+keycode 0x68 =
+keycode 0x69 = F13             
+keycode 0x6a =
+keycode 0x6b = Scroll_Lock      Show_Memory      Show_Registers  
+	control keycode 0x6b = Show_State      
+	alt     keycode 0x6b = Scroll_Lock     
+keycode 0x6c =
+keycode 0x6d = F10              F20              Console_22      
+	control keycode 0x6d = F10             
+	alt     keycode 0x6d = Console_10      
+	control alt     keycode 0x6d = Console_10      
+keycode 0x6e =
+keycode 0x6f = F12              F12              Console_24      
+	control keycode 0x6f = F12             
+	alt     keycode 0x6f = Console_12      
+	control alt     keycode 0x6f = Console_12      
+keycode 0x70 =
+keycode 0x71 = Pause
+keycode 0x72 = Insert          
+keycode 0x73 = Home
+keycode 0x74 = Prior           
+	shift   keycode 0x74 = Scroll_Backward 
+keycode 0x75 = Remove          
+keycode 0x76 = F4               F14              Console_16      
+	control keycode 0x76 = F4              
+	alt     keycode 0x76 = Console_4       
+	control alt     keycode 0x76 = Console_4       
+keycode 0x77 = End
+keycode 0x78 = F2               F12              Console_14      
+	control keycode 0x78 = F2              
+	alt     keycode 0x78 = Console_2       
+	control alt     keycode 0x78 = Console_2       
+keycode 0x79 = Next            
+	shift   keycode 0x79 = Scroll_Forward  
+keycode 0x7a = F1               F11              Console_13      
+	control keycode 0x7a = F1              
+	alt     keycode 0x7a = Console_1       
+	control alt     keycode 0x7a = Console_1       
+keycode 0x7b = Shift_R
+keycode 0x7c = Alt_R
+keycode 0x7d = Control_R
+keycode 0x7e =
+keycode 0x7f =
+#keycode 0x7f = Power
+	control shift   keycode 0x7f = Boot
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/mkmap.adb linux/drivers/usb/mkmap.adb
--- v2.3.5/linux/drivers/usb/mkmap.adb	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/mkmap.adb	Tue Jun  8 10:52:26 1999
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+
+($ME = $0) =~ s|.*/||;
+
+$file = "maps/mac.map";
+$line = 1;
+open(PC, $file) || die("$!");
+while(<PC>)
+{
+    if(/^\s*keycode\s+(\d+|0x[0-9a-fA-F]+)\s*=\s*(\S+)/)
+    {
+        my($idx) = $1;
+        my($sym) = $2;
+        if ($idx =~ "0x.*") {
+            $idx = hex($idx);
+        } else {
+            $idx = int($idx);
+        }
+        if(defined($map{uc($sym)}))
+        {
+            # print STDERR "$file:$line: warning: `$sym' redefined\n";
+        }
+        $map{uc($sym)} = $idx;
+    }
+    $line++;
+}
+close(PC);
+
+# $file = "maps/fixup.map";
+# $line = 1;
+# open(FIXUP, $file) || die("$!");
+# while(<FIXUP>)
+# {
+#     if(/^\s*keycode\s+(\d+)\s*=\s*/)
+#     {
+#       my($idx) = int($1);
+#       for $sym (split(/\s+/, $'))
+#         {
+#           $map{uc($sym)} = $idx;
+#       }
+#     }
+#     $line++;
+# }
+# close(FIXUP);
+
+$file = "maps/usb.map";
+$line = 1;
+open(USB, $file) || die("$!");
+while(<USB>)
+{
+    if(/^\s*keycode\s+(\d+)\s*=\s*/)
+    {
+        my($idx) = int($1);
+        for $sym (split(/\s+/, $'))
+        {
+            my($val) = $map{uc($sym)};
+            $map[$idx] = $val;
+            if(!defined($val))
+            {
+                print STDERR "$file:$line: warning: `$sym' undefined\n";
+            }
+            else
+            {
+                last;
+            }
+        }
+    }
+    $line++;
+}
+close(USB);
+
+print "unsigned char usb_kbd_map[256] = \n{\n";
+for($x = 0; $x < 32; $x++)
+{
+    if($x && !($x % 2))
+    {
+        print "\n";
+    }
+    print "  ";
+    for($y = 0; $y < 8; $y++)
+    {
+        my($idx) = $x * 8 + $y;
+        print sprintf("  0x%02x,",
+                      int(defined($map[$idx]) ? $map[$idx]:0));
+    }
+    print "\n";
+}
+print "};\n";
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.3.5/linux/drivers/usb/mouse.c	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/mouse.c	Mon Jun  7 13:36:40 1999
@@ -75,7 +75,7 @@
X 	mouse->buttons = data[0] & 0x07;
X 	mouse->dx += data[1]; /* data[] is signed, so this works */
X 	mouse->dy -= data[2]; /* y-axis is reversed */
-	mouse->dz += data[3];
+	mouse->dz -= data[3];
X 	mouse->ready = 1;
X 
X 	add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + 
@@ -249,7 +249,7 @@
X 		return -1;
X 
X 	/* Is it a mouse interface? */
-	interface = &dev->config[0].interface[0];
+	interface = &dev->config[0].altsetting[0].interface[0];
X 	if (interface->bInterfaceClass != 3)
X 		return -1;
X 	if (interface->bInterfaceSubClass != 1)
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- v2.3.5/linux/drivers/usb/ohci-debug.c	Mon May 17 09:55:22 1999
+++ linux/drivers/usb/ohci-debug.c	Tue Jun  8 10:52:26 1999
@@ -67,7 +67,7 @@
X 
X void show_ohci_ed(struct ohci_ed *ed)
X {
-	int stat = ed->status;
+	int stat = le32_to_cpup(&ed->status);
X 	int skip = (stat & OHCI_ED_SKIP);
X 	int mps = (stat & OHCI_ED_MPS) >> 16;
X 	int isoc = (stat & OHCI_ED_F_ISOC);
@@ -75,8 +75,8 @@
X 	int dir = (stat & OHCI_ED_D);
X 	int endnum = (stat & OHCI_ED_EN) >> 7;
X 	int funcaddr = (stat & OHCI_ED_FA);
-	int halted = (ed->_head_td & 1);
-	int toggle = (ed->_head_td & 2) >> 1;
+	int halted = (le32_to_cpup(&ed->_head_td) & 1);
+	int toggle = (le32_to_cpup(&ed->_head_td) & 2) >> 1;
X 
X 	printk(KERN_DEBUG "   ohci ED:\n");
X 	printk(KERN_DEBUG "     status     =  0x%x\n", stat);
@@ -92,23 +92,24 @@
X 			endnum,
X 			funcaddr,
X 			(stat & ED_ALLOCATED) ? " Allocated" : "");
-	printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed->tail_td);
+	printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed_tail_td(ed));
X 	printk(KERN_DEBUG "     head_td    =  0x%x\n", ed_head_td(ed));
-	printk(KERN_DEBUG "     next_ed    =  0x%x\n", ed->next_ed);
+	printk(KERN_DEBUG "     next_ed    =  0x%x\n", le32_to_cpup(&ed->next_ed));
X } /* show_ohci_ed() */
X 
X 
X void show_ohci_td(struct ohci_td *td)
X {
-	int td_round = td->info & OHCI_TD_ROUND;
-	int td_dir = td->info & OHCI_TD_D;
-	int td_int_delay = (td->info & OHCI_TD_IOC_DELAY) >> 21;
-	int td_toggle = (td->info & OHCI_TD_DT) >> 24;
+	int info = le32_to_cpup(&td->info);
+	int td_round = info & OHCI_TD_ROUND;
+	int td_dir = info & OHCI_TD_D;
+	int td_int_delay = (info & OHCI_TD_IOC_DELAY) >> 21;
+	int td_toggle = (info & OHCI_TD_DT) >> 24;
X 	int td_errcnt = td_errorcount(*td);
-	int td_cc = OHCI_TD_CC_GET(td->info);
+	int td_cc = OHCI_TD_CC_GET(info);
X 
X 	printk(KERN_DEBUG "   ohci TD hardware fields:\n");
-	printk(KERN_DEBUG "      info     =  0x%x\n", td->info);
+	printk(KERN_DEBUG "      info     =  0x%x\n", info);
X 	printk(KERN_DEBUG "        %s%s%s%d %s %s%d\n",
X 		td_round ? "Rounding " : "",
X 		(td_dir == OHCI_TD_D_IN) ? "Input " :
@@ -125,9 +126,9 @@
X 
X 	printk(KERN_DEBUG "        %s\n", td_allocated(*td) ? "Allocated" : "Free");
X 
-	printk(KERN_DEBUG "      cur_buf  =  0x%x\n", td->cur_buf);
-	printk(KERN_DEBUG "      next_td  =  0x%x\n", td->next_td);
-	printk(KERN_DEBUG "      buf_end  =  0x%x\n", td->buf_end);
+	printk(KERN_DEBUG "      cur_buf  =  0x%x\n", le32_to_cpup(&td->cur_buf));
+	printk(KERN_DEBUG "      next_td  =  0x%x\n", le32_to_cpup(&td->next_td));
+	printk(KERN_DEBUG "      buf_end  =  0x%x\n", le32_to_cpup(&td->buf_end));
X 	printk(KERN_DEBUG "   ohci TD driver fields:\n");
X 	printk(KERN_DEBUG "      data     =  %p\n", td->data);
X 	printk(KERN_DEBUG "      dev_id   =  %p\n", td->dev_id);
@@ -169,11 +170,14 @@
X 	printk(KERN_DEBUG "  ohci_hcca\n");
X 
X 	for (idx=0; idx<NUM_INTS; idx++) {
-		printk(KERN_DEBUG "    int_table[%2d]  == %p\n", idx, hcca->int_table +idx);
+		printk(KERN_DEBUG "    int_table[%2d]  == %x\n", idx,
+		       le32_to_cpup(hcca->int_table + idx));
X 	}
X 
-	printk(KERN_DEBUG "    frame_no          == %d\n", hcca->frame_no);
-	printk(KERN_DEBUG "    donehead          == 0x%08x\n", hcca->donehead);
+	printk(KERN_DEBUG "    frame_no          == %d\n",
+	       le16_to_cpup(&hcca->frame_no));
+	printk(KERN_DEBUG "    donehead          == 0x%08x\n",
+	       le32_to_cpup(&hcca->donehead));
X } /* show_ohci_hcca() */
X 
X 
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.5/linux/drivers/usb/ohci.c	Mon May 31 22:28:06 1999
+++ linux/drivers/usb/ohci.c	Tue Jun  8 10:52:26 1999
@@ -71,60 +71,84 @@
X 
X static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
X 
+#define FIELDS_OF_ED(e)	le32_to_cpup(&e->status), le32_to_cpup(&e->tail_td), \
+			le32_to_cpup(&e->_head_td), le32_to_cpup(&e->next_ed)
+#define FIELDS_OF_TD(t)	le32_to_cpup(&t->info), le32_to_cpup(&t->cur_buf), \
+			le32_to_cpup(&t->next_td), le32_to_cpup(&t->buf_end)
+
+static const char *cc_names[16] = {
+	"no error",
+	"CRC error",
+	"bit stuff error",
+	"data toggle mismatch",
+	"stall",
+	"device not responding",
+	"PID check failed",
+	"unexpected PID",
+	"data overrun",
+	"data underrun",
+	"reserved (10)",
+	"reserved (11)",
+	"buffer overrun",
+	"buffer underrun",
+	"not accessed (14)",
+	"not accessed"
+};
+
X /*
- * Add a TD to the end of the TD list on a given ED.  This function
- * does NOT advance the ED's tail_td pointer beyond the given TD.  To
- * add multiple TDs, call this function once for each TD.  Do not
- * "simply" update tail_td yourself... This function does more than
- * that.
- * 
- * If this ED is on the controller, you MUST set its SKIP flag before
- * calling this function.
+ * Add a chain of TDs to the end of the TD list on a given ED.
+ *
+ * This function uses the first TD of the chain as the new dummy TD
+ * for the ED, and uses the old dummy TD instead of the first TD
+ * of the chain.  The reason for this is that this makes it possible
+ * to update the TD chain without needing any locking between the
+ * CPU and the OHCI controller.
X  *
- * Important!  This function needs locking and atomicity as it works
- * in parallel with the HC's DMA.  Locking ohci_edtd_lock while using
- * the function is a must.
+ * The return value is the pointer to the new first TD (the old
+ * dummy TD).
+ *
+ * Important!  This function is not re-entrant w.r.t. each ED.
+ * Locking ohci_edtd_lock while using the function is a must
+ * if there is any possibility of another CPU or an interrupt routine
+ * calling this function with the same ED.
X  *
X  * This function can be called by the interrupt handler.
X  */
-static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
+static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
+				struct ohci_td *last_td, struct ohci_ed *ed)
X {
-	struct ohci_td *dummy_td, *prev_td;
+	struct ohci_td *t, *dummy_td;
+	u32 new_dummy;
X 
X 	if (ed->tail_td == 0) {
X 		printk("eek! an ED without a dummy_td\n");
+		return td;
X 	}
X 
-	/* The ED's tail_td is constant, always pointing to the
-	 * dummy_td.  The reason the ED never processes the dummy is
-	 * that it stops processing TDs as soon as head_td == tail_td.
-	 * When it advances to this last dummy TD it conveniently stops. */
-	dummy_td = bus_to_virt(ed->tail_td);
-
-	/* Dummy's data pointer is used to point to the previous TD */
-	if (ed_head_td(ed) != ed->tail_td) {
-		prev_td = (struct ohci_td *) dummy_td->data;
-	} else {
-		/* if the ED is empty, previous is meaningless */
-		/* We'll be inserting into the head of the list */
-		prev_td = NULL;
-	}
-
-	/* Store the new back pointer and set up this TD's next */
-	dummy_td->data = td;
-	td->next_td = ed->tail_td;
-
-	/* Store the TD pointer back to the ED */
-	td->ed = ed;
-
-	if (!prev_td) { /* No previous TD? then insert us at the head */
-		if (ed_head_td(ed) != ed->tail_td)
-			printk(KERN_DEBUG "Suspicious ED...\n");
-		set_ed_head_td(ed, virt_to_bus(td));	/* put it on the ED */
-	} else {
-		/* add the TD to the end */
-		prev_td->next_td = virt_to_bus(td);
+	/* Get a pointer to the current dummy TD. */
+	dummy_td = bus_to_virt(ed_tail_td(ed));
+
+	for (t = td; ; t = bus_to_virt(le32_to_cpup(&t->next_td))) {
+		t->ed = ed;
+		if (t == last_td)
+			break;
X 	}
+
+	/* Make the last TD point back to the first, since it
+	 * will become the new dummy TD. */
+	new_dummy = cpu_to_le32(virt_to_bus(td));
+	last_td->next_td = new_dummy;
+
+	/* Copy the contents of the first TD into the dummy */
+	*dummy_td = *td;
+
+	/* Turn the first TD into a dummy */
+	make_dumb_td(td);
+
+	/* Set the HC's tail pointer to the new dummy */
+	ed->tail_td = new_dummy;
+
+	return dummy_td;	/* replacement head of chain */
X } /* ohci_add_td_to_ed() */
X 
X 
@@ -169,9 +193,7 @@
X 
X 	/* if the list is not empty, insert this ED at the front */
X 	/* XXX should they go on the end? */
-	if (listhead) {
-		ed->next_ed = listhead;
-	}
+	ed->next_ed = cpu_to_le32(listhead);
X 
X 	/* update the hardware listhead pointer */
X 	writel(virt_to_bus(ed), hw_listhead_p);
@@ -221,7 +243,7 @@
X 	 * Insert this ED at the front of the list.
X 	 */
X 	ed->next_ed = int_ed->next_ed;
-	int_ed->next_ed = virt_to_bus(ed);
+	int_ed->next_ed = cpu_to_le32(virt_to_bus(ed));
X 
X 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
X 
@@ -249,21 +271,21 @@
X  */
X void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type)
X {
-	__u32 hw_listcurrent;
+	__u32 *hw_listcurrent;
X 
X 	/* tell the controller to skip this ED */
-	ed->status |= OHCI_ED_SKIP;
+	ed->status |= cpu_to_le32(OHCI_ED_SKIP);
X 
X 	switch (ed_type) {
X 	case HCD_ED_CONTROL:
-		hw_listcurrent = readl(regs->ed_controlcurrent);
+		hw_listcurrent = ®s->ed_controlcurrent;
X 		break;
X 	case HCD_ED_BULK:
-		hw_listcurrent = readl(regs->ed_bulkcurrent);
+		hw_listcurrent = ®s->ed_bulkcurrent;
X 		break;
X 	case HCD_ED_ISOC:
X 	case HCD_ED_INT:
-		hw_listcurrent = readl(regs->ed_periodcurrent);
+		hw_listcurrent = ®s->ed_periodcurrent;
X 		break;
X 	default:
X 		return;
@@ -273,11 +295,11 @@
X 	 * If the HC is processing this ED we need to wait until the
X 	 * at least the next frame.
X 	 */
-	if (virt_to_bus(ed) == hw_listcurrent) {
+	if (virt_to_bus(ed) == readl(hw_listcurrent)) {
X 		DECLARE_WAITQUEUE(wait, current);
X 
X #ifdef OHCI_DEBUG
-		printk("Waiting a frame for OHC to finish with ED %p\n", ed);
+		printk("Waiting a frame for OHC to finish with ED %p [%x %x %x %x]\n", ed, FIELDS_OF_ED(ed));
X #endif
X 
X 		add_wait_queue(&start_of_frame_wakeup, &wait);
@@ -349,7 +371,7 @@
X 		/* walk the list and unlink the ED if found */
X 		do {
X 			prev = cur;
-			cur = bus_to_virt(cur->next_ed);
+			cur = bus_to_virt(le32_to_cpup(&cur->next_ed));
X 
X 			if (virt_to_bus(cur) == bus_ed) {
X 				/* unlink from the list */
@@ -401,7 +423,7 @@
X 		return;
X 
X 	/* set the "skip me bit" in this ED */
-	ed->status |= OHCI_ED_SKIP;
+	ed->status |= cpu_to_le32(OHCI_ED_SKIP);
X 
X 	/* XXX Assuming this list will never be circular */
X 
@@ -415,7 +437,7 @@
X 		/* FIXME: collapse this into a nice simple loop :) */
X 		if (head_td->next_td != 0) {
X 			prev_td = head_td;
-			cur_td = bus_to_virt(head_td->next_td);
+			cur_td = bus_to_virt(le32_to_cpup(&head_td->next_td));
X 			for (;;) {
X 				if (td == cur_td) {
X 					/* remove it */
@@ -425,7 +447,7 @@
X 				if (cur_td->next_td == 0)
X 					break;
X 				prev_td = cur_td;
-				cur_td = bus_to_virt(cur_td->next_td);
+				cur_td = bus_to_virt(le32_to_cpup(&cur_td->next_td));
X 			}
X 		}
X 	}
@@ -437,7 +459,7 @@
X 	ohci_free_td(td);
X 
X 	/* unset the "skip me bit" in this ED */
-	ed->status &= ~OHCI_ED_SKIP;
+	ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
X 
X 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
X } /* ohci_remove_td_from_ed() */
@@ -465,7 +487,7 @@
X 			/* zero out the TD */
X 			memset(new_td, 0, sizeof(*new_td));
X 			/* mark the new TDs as unaccessed */
-			new_td->info = OHCI_TD_CC_NEW;
+			new_td->info = cpu_to_le32(OHCI_TD_CC_NEW);
X 			/* mark it as allocated */
X 			allocate_td(new_td);
X 			return new_td;
@@ -492,7 +514,7 @@
X 			/* zero out the ED */
X 			memset(new_ed, 0, sizeof(*new_ed));
X 			/* all new EDs start with the SKIP bit set */
-			new_ed->status |= OHCI_ED_SKIP;
+			new_ed->status |= cpu_to_le32(OHCI_ED_SKIP);
X 			/* mark it as allocated */
X 			allocate_ed(new_ed);
X 			return new_ed;
@@ -509,12 +531,21 @@
X 	if (!ed)
X 		return;
X 
-	if (ed->tail_td == 0) {
-		printk("yikes! an ED without a dummy_td\n");
-	} else
-		ohci_free_td((struct ohci_td *)bus_to_virt(ed->tail_td));
+	if (ed_head_td(ed) != 0) {
+		struct ohci_td *td, *tail_td, *next_td;
X 
-	ed->status &= ~(__u32)ED_ALLOCATED;
+		td = bus_to_virt(ed_head_td(ed));
+		tail_td = bus_to_virt(ed_tail_td(ed));
+		for (;;) {
+			next_td = bus_to_virt(le32_to_cpup(&td->next_td));
+			ohci_free_td(td);
+			if (td == tail_td)
+				break;
+			td = next_td;
+		}
+	}
+
+	ed->status &= cpu_to_le32(~(__u32)ED_ALLOCATED);
X } /* ohci_free_ed() */
X 
X 
@@ -527,12 +558,13 @@
X inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
X {
X 	/* hardware fields */
-	td->info = OHCI_TD_CC_NEW |
-		(dir & OHCI_TD_D) |
-		(toggle & OHCI_TD_DT) |
-		flags;
-	td->cur_buf = (data == NULL) ? 0 : virt_to_bus(data);
-	td->buf_end = (len == 0) ? 0 : td->cur_buf + len - 1;
+	td->info = cpu_to_le32(OHCI_TD_CC_NEW |
+			       (dir & OHCI_TD_D) |
+			       (toggle & OHCI_TD_DT) |
+			       flags);
+	td->cur_buf = (data == NULL) ? 0 : cpu_to_le32(virt_to_bus(data));
+	td->buf_end = (len == 0) ? 0 :
+		cpu_to_le32(le32_to_cpup(&td->cur_buf) + len - 1);
X 
X 	/* driver fields */
X 	td->data = data;
@@ -555,11 +587,13 @@
X  *  not be any!).  This assumes that the ED is Allocated and will
X  *  force the Allocated bit on.
X  */
-struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed, int maxpacketsize, int lowspeed, int endp_id, int isoc_tds)
+struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
+			     int maxpacketsize, int lowspeed, int endp_id,
+			     int isoc_tds)
X {
X 	struct ohci_td *dummy_td;
X 
-	if (ed_head_td(ed) != ed->tail_td)
+	if (ed_head_td(ed) != ed_tail_td(ed))
X 		printk("Reusing a non-empty ED %p!\n", ed);
X 
X 	if (!ed->tail_td) {
@@ -569,9 +603,9 @@
X 			return NULL;	/* no dummy available! */
X 		}
X 		make_dumb_td(dummy_td);	/* flag it as a dummy */
-		ed->tail_td = virt_to_bus(dummy_td);
+		ed->tail_td = cpu_to_le32(virt_to_bus(dummy_td));
X 	} else {
-		dummy_td = bus_to_virt(ed->tail_td);
+		dummy_td = bus_to_virt(ed_tail_td(ed));
X 		if (!td_dummy(*dummy_td))
X 			printk("ED %p's dummy %p is screwy\n", ed, dummy_td);
X 	}
@@ -579,11 +613,11 @@
X 	/* set the head TD to the dummy and clear the Carry & Halted bits */
X 	ed->_head_td = ed->tail_td;
X 
-	ed->status = \
+	ed->status = cpu_to_le32(
X 		ed_set_maxpacket(maxpacketsize) |
X 		ed_set_speed(lowspeed) |
X 		(endp_id & 0x7ff) |
-		((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC);
+		((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC));
X 	allocate_ed(ed);
X 	ed->next_ed = 0;
X 
@@ -611,6 +645,7 @@
X 	struct ohci_device *dev = usb_to_ohci(usb);
X 	struct ohci_td *td;
X 	struct ohci_ed *interrupt_ed;	/* endpoint descriptor for this irq */
+	int maxps = usb_maxpacket(usb, pipe);
X 
X 	/* Get an ED and TD */
X 	interrupt_ed = ohci_get_free_ed(dev);
@@ -630,14 +665,16 @@
X 	 * Set the max packet size, device speed, endpoint number, usb
X 	 * device number (function address), and type of TD.
X 	 */
-	ohci_fill_ed(dev, interrupt_ed, usb_maxpacket(usb,pipe), usb_pipeslow(pipe),
-		usb_pipe_endpdev(pipe), 0 /* normal TDs */);
+	ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe),
+		     usb_pipe_endpdev(pipe), 0 /* normal TDs */);
X 
X 	/* Fill in the TD */
+	if (maxps > sizeof(dev->data))
+		maxps = sizeof(dev->data);
X 	ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
X 			TOGGLE_AUTO,
X 			OHCI_TD_ROUND,
-			&dev->data, DATA_BUF_LEN,
+			dev->data, maxps,
X 			dev_id, handler);
X 	/*
X 	 * TODO: be aware of how the OHCI controller deals with DMA
@@ -647,12 +684,12 @@
X 	/*
X 	 *  Put the TD onto our ED and make sure its ready to run
X 	 */
-	ohci_add_td_to_ed(td, interrupt_ed);
-	interrupt_ed->status &= ~OHCI_ED_SKIP;
+	td = ohci_add_td_to_ed(td, td, interrupt_ed);
+	interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
X 	ohci_unhalt_ed(interrupt_ed);
X 
-	/* Linus did this. see asm/system.h; scary concept... I don't
-	 * know if its needed here or not but it won't hurt. */
+	/* Make sure all the stores above get done before
+	 * the store which tells the OHCI about the new ed. */
X 	wmb();
X 
X 	/* Assimilate the new ED into the collective */
@@ -700,7 +737,8 @@
X  *
X  * This function can NOT be called from an interrupt.
X  */
-static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
+static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
+			    devrequest *cmd, void *data, int len)
X {
X 	struct ohci_device *dev = usb_to_ohci(usb);
X 	struct ohci_ed *control_ed = ohci_get_free_ed(dev);
@@ -708,8 +746,16 @@
X 	DECLARE_WAITQUEUE(wait, current);
X 	unsigned long flags;
X 	int completion_status = -1;
+	devrequest our_cmd;
X 
-#ifdef OHCI_DEBUG 
+	/* byte-swap fields of cmd if necessary */
+	our_cmd = *cmd;
+	cpu_to_le16s(&our_cmd.value);
+	cpu_to_le16s(&our_cmd.index);
+	cpu_to_le16s(&our_cmd.length);
+
+#ifdef OHCI_DEBUG
+	if (MegaDebug)
X 	printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
X #endif
X 	if (!control_ed) {
@@ -743,12 +789,11 @@
X 	 * uses a DATA0 packet.
X 	 *
X 	 * The setup packet contains a devrequest (usb.h) which
-	 * will always be 8 bytes long.  FIXME: the cmd parameter
-	 * should be a pointer to one of these instead of a void* !!!
+	 * will always be 8 bytes long.
X 	 */
X 	ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0,
X 			OHCI_TD_IOC_OFF,
-			cmd, 8,		/* cmd is always 8 bytes long */
+			&our_cmd, 8,	/* cmd is always 8 bytes long */
X 			NULL, NULL);
X 
X 	/* allocate the next TD */
@@ -761,7 +806,7 @@
X 	}
X 
X 	/* link to the next TD */
-	setup_td->next_td = virt_to_bus(data_td);
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 16'
echo 'File patch-2.3.6 is continued in part 17'
echo 17 > _shar_seq_.tmp
exit 0
#!/bin/sh
# this is part 18 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 18; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+
+    if (!(vendor = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer)))
+	vendor = "?";
+    if (!(product = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct)))
+	product = "?";
+
+    switch (us->protocol) {
+    case US_PR_CB:
+	style = "Control/Bulk";
+	break;
+
+    case US_PR_CBI:
+	style = "Control/Bulk/Interrupt";
+	break;
+
+    case US_PR_ZIP:
+	style = "Bulk only";
+	break;
+
+    }
+    SPRINTF ("Host scsi%d: usb-scsi\n", hostno);
+    SPRINTF ("Device: %s %s - GUID " GUID_FORMAT "\n", vendor, product, GUID_ARGS(us->guid) );
+    SPRINTF ("Style: %s\n", style);
+
+    /*
+     * Calculate start of next buffer, and return value.
+     */
+    *start = buffer + offset;
+
+    if ((pos - buffer) < offset)
+	return (0);
+    else if ((pos - buffer - offset) < length)
+	return (pos - buffer - offset);
+    else
+	return (length);
+}
+
+/*
+ * this defines our 'host'
+ */
+
+static Scsi_Host_Template my_host_template = {
+    NULL,			/* next */
+    NULL,			/* module */
+    NULL,			/* proc_dir */
+    usb_scsi_proc_info,
+    NULL,			/* name - points to unique */
+    us_detect,
+    us_release,
+    NULL,			/* info */
+    NULL,			/* ioctl */
+    us_command,
+    us_queuecommand,
+    NULL,			/* eh_strategy */
+    us_abort,
+    us_device_reset,
+    us_bus_reset,
+    us_host_reset,
+    NULL,			/* abort */
+    NULL,			/* reset */
+    NULL,			/* slave_attach */
+    NULL,			/* bios_param */
+    1,				/* can_queue */
+    -1,				/* this_id */
+    SG_ALL,			/* sg_tablesize */
+    1,				/* cmd_per_lun */
+    0,				/* present */
+    FALSE,			/* unchecked_isa_dma */
+    FALSE,			/* use_clustering */
+    TRUE,			/* use_new_eh_code */
+    TRUE			/* emulated */
+};
+
+static int usbscsi_control_thread(void * __us)
+{
+    struct us_data *us = (struct us_data *)__us;
+    int action;
+
+    lock_kernel();
+
+    /*
+     * This thread doesn't need any user-level access,
+     * so get rid of all our resources..
+     */
+    exit_mm(current);
+    exit_files(current);
+    //exit_fs(current);
+
+    sprintf(current->comm, "usbscsi%d", us->host_no);
+    
+    unlock_kernel();
+
+    up(us->notify);
+
+    for(;;) {
+	    siginfo_t info;
+	    int unsigned long signr;
+
+	    interruptible_sleep_on(&us->waitq);
+
+	    action = us->action;
+	    us->action = 0;
+
+	    switch (action) {
+	    case US_ACT_COMMAND       :
+		if (!us->pusb_dev || us->srb->target || us->srb->lun) {
+		    /* bad device */
+		    US_DEBUGP( "Bad device number (%d/%d) or dev %x\n", us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
+		    us->srb->result = DID_BAD_TARGET << 16;
+		} else {
+		    US_DEBUG(us_show_command(us->srb));
+		    if (us->filter && us->filter->command)
+		        us->srb->result = us->filter->command(us->fdata, us->srb);
+		    else
+		        us->srb->result = us->pop(us->srb);
+		}
+		us->srb->scsi_done(us->srb);
+		break;
+
+	    case US_ACT_ABORT         :
+		break;
+
+	    case US_ACT_DEVICE_RESET  :
+		break;
+
+	    case US_ACT_BUS_RESET     :
+		break;
+
+	    case US_ACT_HOST_RESET    :
+		break;
+
+	    }
+
+	    if(signal_pending(current)) {
+		    /* sending SIGUSR1 makes us print out some info */
+		    spin_lock_irq(¤t->sigmask_lock);
+		    signr = dequeue_signal(¤t->blocked, &info);
+		    spin_unlock_irq(¤t->sigmask_lock);
+
+		    if (signr == SIGUSR2) {
+			    printk("USBSCSI debug toggle\n");
+			    usbscsi_debug = !usbscsi_debug;
+		    } else {
+			    break;
+		    }
+	    }
+    }
+
+    MOD_DEC_USE_COUNT;
+
+    printk("usbscsi_control_thread exiting\n");
+
+    return 0;
+}	
+
+static int scsi_probe(struct usb_device *dev)
+{
+    struct usb_interface_descriptor *interface;
+    int i;
+    char *mf;		/* manufacturer */
+    char *prod;		/* product */
+    char *serial;		/* serial number */
+    struct us_data *ss = NULL;
+    struct usb_scsi_filter *filter = filters;
+    void *fdata = NULL;
+    unsigned int flags = 0;
+    GUID(guid);
+    struct us_data *prev;
+    Scsi_Host_Template *htmplt;
+    int protocol = 0;
+    int subclass = 0;
+
+    GUID_CLEAR(guid);
+    mf = usb_string(dev, dev->descriptor.iManufacturer);
+    prod = usb_string(dev, dev->descriptor.iProduct);
+    serial = usb_string(dev, dev->descriptor.iSerialNumber);
+
+    /* probe with filters first */
+
+    if (mf && prod)	{
+	    while (filter) {
+		    if ((fdata = filter->probe(dev, mf, prod, serial)) != NULL) {
+			    flags = filter->flags;
+			    printk(KERN_INFO "USB Scsi filter %s\n", filter->name);
+			    break;
+		    }
+		    filter = filter->next;
+	    }
+    }
+
+    /* generic devices next */
+
+    if (fdata == NULL) {
+
+	/* some exceptions */
+	if (dev->descriptor.idVendor == 0x04e6 &&
+	    dev->descriptor.idProduct == 0x0001) {
+	    /* shuttle E-USB */
+	    protocol = US_PR_ZIP;
+	    subclass = US_SC_8070;	/* an assumption */
+	} else if (dev->descriptor.bDeviceClass != 0 ||
+	    dev->config->altsetting->interface->bInterfaceClass != 8 ||
+	    dev->config->altsetting->interface->bInterfaceSubClass < US_SC_MIN ||
+	    dev->config->altsetting->interface->bInterfaceSubClass > US_SC_MAX) {
+	    return -1;
+	}
+
+	/* now check if we have seen it before */
+
+	if (dev->descriptor.iSerialNumber && 
+	    usb_string(dev, dev->descriptor.iSerialNumber) ) {
+	    make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
+		      usb_string(dev, dev->descriptor.iSerialNumber));
+	    for (ss = us_list; ss; ss = ss->next) {
+		if (GUID_EQUAL(guid, ss->guid))	{
+		    US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+		    break;
+		}
+	    }
+	}
+    }
+
+    if (!ss) {
+	if ((ss = (struct us_data *)kmalloc(sizeof(*ss), GFP_KERNEL)) == NULL) {
+	    printk(KERN_WARNING USB_SCSI "Out of memory\n");
+	    if (filter)
+		    filter->release(fdata);
+	    return -1;
+	}
+	memset(ss, 0, sizeof(struct us_data));
+    }
+
+    interface = dev->config->altsetting->interface;
+    ss->filter = filter;
+    ss->fdata = fdata;
+    ss->flags = flags;
+    if (subclass) {
+	ss->subclass = subclass;
+	ss->protocol = protocol;
+    } else {
+	ss->subclass = interface->bInterfaceSubClass;
+	ss->protocol = interface->bInterfaceProtocol;
+    }
+
+    /* set the protocol op */
+
+    US_DEBUGP("Protocol ");
+    switch (ss->protocol) {
+    case US_PR_CB:
+	US_DEBUGPX("Control/Bulk\n");
+	ss->pop = pop_CBI;
+	break;
+
+    case US_PR_CBI:
+	US_DEBUGPX("Control/Bulk/Interrupt\n");
+	ss->pop = pop_CBI;
+	break;
+
+    default:
+	US_DEBUGPX("Bulk\n");
+	ss->pop = pop_Bulk;
+	break;
+    }
+
+    /* 
+     * we are expecting a minimum of 2 endpoints - in and out (bulk)
+     * an optional interrupt is OK (necessary for CBI protocol)
+     * we will ignore any others
+     */
+
+    for (i = 0; i < interface->bNumEndpoints; i++) { 
+	    if (interface->endpoint[i].bmAttributes == 0x02) {
+		    if (interface->endpoint[i].bEndpointAddress & 0x80)
+			    ss->ep_in = interface->endpoint[i].bEndpointAddress & 0x0f;
+		    else
+			    ss->ep_out = interface->endpoint[i].bEndpointAddress & 0x0f;
+	    } else if (interface->endpoint[i].bmAttributes == 0x03) {
+		    ss->ep_int = interface->endpoint[i].bEndpointAddress & 0x0f;
+	    }
+    }
+    US_DEBUGP("Endpoints In %d Out %d Int %d\n", ss->ep_in, ss->ep_out, ss->ep_int);
+
+    /* exit if strange looking */
+
+    if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) ||
+	!ss->ep_in || !ss->ep_out || (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
+	US_DEBUGP("Problems with device\n");
+	if (ss->host) {
+	    scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt);
+	    kfree(ss->htmplt->name);
+	    kfree(ss->htmplt);
+	}
+	if (filter)
+		filter->release(fdata);
+	kfree(ss);
+	return -1;			/* no endpoints */
+    }
+
+    if (dev->config[0].iConfiguration && usb_string(dev, dev->config[0].iConfiguration))
+	US_DEBUGP("Configuration %s\n", usb_string(dev, dev->config[0].iConfiguration));
+    if (interface->iInterface && usb_string(dev, interface->iInterface))
+	US_DEBUGP("Interface %s\n", usb_string(dev, interface->iInterface));
+
+    ss->pusb_dev = dev;
+
+    /* Now generate a scsi host definition, and register with scsi above us */
+
+    if (!ss->host) {
+
+	/* make unique id if possible */
+
+	if (dev->descriptor.iSerialNumber && 
+	    usb_string(dev, dev->descriptor.iSerialNumber) ) {
+	    make_guid(ss->guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
+		      usb_string(dev, dev->descriptor.iSerialNumber));
+	}
+
+	US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+
+	/* set class specific stuff */
+
+	US_DEBUGP("SubClass ");
+	switch (ss->subclass) {
+	case US_SC_RBC:
+	    US_DEBUGPX("Reduced Block Commands\n");
+	    break;
+	case US_SC_8020:
+	    US_DEBUGPX("8020\n");
+	    break;
+	case US_SC_QIC:
+	    US_DEBUGPX("QIC157\n");
+	    break;
+	case US_SC_8070:
+	    US_DEBUGPX("8070\n");
+	    ss->flags |= US_FL_FIXED_COMMAND;
+	    ss->fixedlength = 12;
+	    break;
+	case US_SC_SCSI:
+	    US_DEBUGPX("Transparent SCSI\n");
+	    break;
+	case US_SC_UFI:
+	    US_DEBUGPX(" UFF\n");
+	    ss->flags |= US_FL_FIXED_COMMAND;
+	    ss->fixedlength = 12;
+	    break;
+
+	default:
+	    break;
+	}
+
+	/* create unique host template */
+
+	if ((htmplt = (Scsi_Host_Template *)kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) {
+	    printk(KERN_WARNING USB_SCSI "Out of memory\n");
+	    if (filter)
+		    filter->release(fdata);
+	    kfree(ss);
+	    return -1;
+	}
+	memcpy(htmplt, &my_host_template, sizeof(my_host_template));
+	ss->host_number = my_host_number++;
+
+
+	(struct us_data *)htmplt->proc_dir = ss;
+	if (ss->protocol == US_PR_CBI)
+	    init_waitqueue_head(&ss->ip_waitq);
+
+	/* start up our thread */
+
+	{
+	    DECLARE_MUTEX_LOCKED(sem);
+
+	    init_waitqueue_head(&ss->waitq);
+    
+	    ss->notify = &sem;
+	    ss->pid = kernel_thread(usbscsi_control_thread, ss,
+		    CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	    if (ss->pid < 0) {
+		printk(KERN_WARNING USB_SCSI "Unable to start control thread\n");
+		kfree(htmplt);
+		if (filter)
+			filter->release(fdata);
+		kfree(ss);
+		return -1;
+	    }
+
+	    /* wait for it to start */
+
+	    down(&sem);
+	}
+
+	/* now register - our detect function will be called */
+
+	scsi_register_module(MODULE_SCSI_HA, htmplt);
+
+	/* put us in the list */
+
+	prev = (struct us_data *)&us_list;
+	while (prev->next)
+	    prev = prev->next;
+	prev->next = ss;
+
+    }
+
+
+    printk(KERN_INFO "USB SCSI device found at address %d\n", dev->devnum);
+
+    dev->private = ss;
+    return 0;
+}
+
+static void scsi_disconnect(struct usb_device *dev)
+{
+	struct us_data *ss = dev->private;
+
+	if (!ss)
+	    return;
+	if (ss->filter)
+		ss->filter->release(ss->fdata);
+	ss->pusb_dev = NULL;
+	dev->private = NULL;		/* just in case */
+	MOD_DEC_USE_COUNT;
+}
+
+int usb_scsi_init(void)
+{
+
+	MOD_INC_USE_COUNT;
+#ifdef CONFIG_USB_HP4100
+	hp4100_init();
+#endif
+#ifdef CONFIG_USB_ZIP
+	usb_zip_init();
+#endif
+	usb_register(&scsi_driver);
+	printk(KERN_INFO "USB SCSI support registered.\n");
+	return 0;
+}
+
+
+int usb_scsi_register(struct usb_scsi_filter *filter)
+{
+	struct usb_scsi_filter *prev = (struct usb_scsi_filter *)&filters;
+
+	while (prev->next)
+		prev = prev->next;
+	prev->next = filter;
+	return 0;
+}
+
+void usb_scsi_deregister(struct usb_scsi_filter *filter)
+{
+	struct usb_scsi_filter *prev = (struct usb_scsi_filter *)&filters;
+
+	while (prev->next && prev->next != filter)
+		prev = prev->next;
+	if (prev->next)
+		prev->next = filter->next;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+
+	return usb_scsi_init();
+}
+
+void cleanup_module(void)
+{
+	unsigned int offset;
+
+	usb_deregister(&scsi_driver);
+}
+#endif
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/usb_scsi.h linux/drivers/usb/usb_scsi.h
--- v2.3.5/linux/drivers/usb/usb_scsi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb_scsi.h	Mon Jun  7 20:04:01 1999
@@ -0,0 +1,145 @@
+/* Driver for USB scsi - include file
+ * 
+ * (C) Michael Gee (mic...@linuxspecific.com) 1999
+ *
+ * This driver is scitzoid  - it make a USB scanner appear as both a SCSI device
+ * and a character device. The latter is only available if the device has an
+ * interrupt endpoint, and is used specifically to receive interrupt events.
+ *
+ * In order to support various 'strange' scanners, this module supports plug in
+ * device specific filter modules, which can do their own thing when required.
+ *
+ */
+
+#define USB_SCSI "usbscsi: "
+
+extern int usbscsi_debug;
+
+#ifdef CONFIG_USB_SCSI_DEBUG
+void us_show_command(Scsi_Cmnd *srb);
+#define US_DEBUGP(x...) { if(usbscsi_debug) printk( KERN_DEBUG USB_SCSI ## x ); }
+#define US_DEBUGPX(x...) { if(usbscsi_debug) printk( ## x ); }
+#define US_DEBUG(x)  { if(usbscsi_debug) x; }
+#else
+#define US_DEBUGP(x...)
+#define US_DEBUGPX(x...)
+#define US_DEBUG(x)
+#endif
+
+/* bit set if input */
+extern unsigned char us_direction[256/8];
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+/* Sub Classes */
+
+#define US_SC_RBC	1		/* Typically, flash devices */
+#define US_SC_8020	2		/* CD-ROM */
+#define US_SC_QIC	3		/* QIC-157 Tapes */
+#define US_SC_UFI	4		/* Floppy */
+#define US_SC_8070	5		/* Removable media */
+#define US_SC_SCSI	6		/* Transparent */
+#define US_SC_MIN	US_SC_RBC
+#define US_SC_MAX	US_SC_SCSI
+
+/* Protocols */
+
+#define US_PR_CB	1		/* Control/Bulk w/o interrupt */
+#define US_PR_CBI	0		/* Control/Bulk/Interrupt */
+#define US_PR_ZIP	0x50		/* bulk only */
+/* #define US_PR_BULK	?? */
+
+/*
+ * Bulk only data structures (Zip 100, for example)
+ */
+
+struct bulk_cb_wrap {
+    __u32	Signature;		/* contains 'USBC' */
+    __u32	Tag;			/* unique per command id */
+    __u32	DataTransferLength;	/* size of data */
+    __u8	Flags;	       		/* direction in bit 0 */
+    __u8	Lun;			/* LUN normally 0 */
+    __u8	Length;			/* of of the CDB */
+    __u8	CDB[16];		/* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN 	31
+#define US_BULK_CB_SIGN		0x43425355
+#define US_BULK_FLAG_IN		1
+#define US_BULK_FLAG_OUT	0
+
+struct bulk_cs_wrap {
+    __u32	Signature;		/* should = 'USBS' */
+    __u32	Tag;			/* same as original command */
+    __u32	Residue;		/* amount not transferred */
+    __u8	Status;			/* see below */
+    __u8	Filler[18];
+};
+
+#define US_BULK_CS_WRAP_LEN	31
+#define US_BULK_CS_SIGN		0x53425355
+#define US_BULK_STAT_OK		0
+#define US_BULK_STAT_FAIL	1
+#define US_BULK_STAT_PHASE	2
+
+#define US_BULK_RESET		0xff
+#define US_BULK_RESET_SOFT	1
+#define US_BULK_RESET_HARD	0
+
+/*
+ * CBI style
+ */
+
+#define US_CBI_ADSC		0
+
+/*
+ * Filter device definitions
+ */
+struct usb_scsi_filter {
+
+	struct usb_scsi_filter * next;	/* usb_scsi driver only */
+	char *name;			/* not really required */
+
+        unsigned int flags;                     			/* Filter flags */
+        void * (* probe) (struct usb_device *, char *, char *, char *);	/* probe device */
+	void (* release)(void *);					/* device gone */
+        int (* command)(void *, Scsi_Cmnd *);  /* all commands */
+};
+
+#define GUID(x) __u32 x[3]
+#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2])
+#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0;
+#define GUID_NONE(x) (!x[0] && !x[1] && !x[2])
+#define GUID_FORMAT "%08x%08x%08x"
+#define GUID_ARGS(x) x[0], x[1], x[2]
+
+static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial)
+{
+	pg[0] = (vendor << 16) | product;
+	pg[1] = pg[2] = 0;
+	while (*serial) {
+		pg[1] <<= 4;
+		pg[1] |= pg[2] >> 28;
+		pg[2] <<= 4;
+		if (*serial >= 'a')
+		    *serial -= 'a' - 'A';
+		pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0'
+						    	    : *serial - 'A' + 10;
+		serial++;
+	}
+}
+
+/* Flag definitions */
+#define US_FL_IP_STATUS		0x00000001		/* status uses interrupt */
+#define US_FL_FIXED_COMMAND	0x00000002		/* expand commands to fixed size */
+
+/*
+ * Called by filters to register/unregister the mini driver
+ *
+ * WARNING - the supplied probe function may be called before exiting this fn
+ */
+int usb_scsi_register(struct usb_scsi_filter *);
+void usb_scsi_deregister(struct usb_scsi_filter *);
+
+#ifdef CONFIG_USB_HP4100
+int hp4100_init(void);
+#endif
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/usb_scsi_debug.c linux/drivers/usb/usb_scsi_debug.c
--- v2.3.5/linux/drivers/usb/usb_scsi_debug.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb_scsi_debug.c	Mon Jun  7 20:04:01 1999
@@ -0,0 +1,104 @@
+
+/* Driver for USB scsi like devices
+ * 
+ * (C) Michael Gee (mic...@linuxspecific.com) 1999
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+
+#include <asm/spinlock.h>
+
+#include <linux/blk.h>
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+
+#include "usb.h"
+#include "usb_scsi.h"
+
+void us_show_command(Scsi_Cmnd *srb)
+{
+    char *what;
+
+    switch (srb->cmnd[0]) {
+    case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+    case REZERO_UNIT: what = "REZERO_UNIT"; break;
+    case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+    case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+    case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+    case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+    case READ_6: what = "READ_6"; break;
+    case WRITE_6: what = "WRITE_6"; break;
+    case SEEK_6: what = "SEEK_6"; break;
+    case READ_REVERSE: what = "READ_REVERSE"; break;
+    case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+    case SPACE: what = "SPACE"; break;
+    case INQUIRY: what = "INQUIRY"; break;
+    case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+    case MODE_SELECT: what = "MODE_SELECT"; break;
+    case RESERVE: what = "RESERVE"; break;
+    case RELEASE: what = "RELEASE"; break;
+    case COPY: what = "COPY"; break;
+    case ERASE: what = "ERASE"; break;
+    case MODE_SENSE: what = "MODE_SENSE"; break;
+    case START_STOP: what = "START_STOP"; break;
+    case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+    case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+    case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+    case SET_WINDOW: what = "SET_WINDOW"; break;
+    case READ_CAPACITY: what = "READ_CAPACITY"; break;
+    case READ_10: what = "READ_10"; break;
+    case WRITE_10: what = "WRITE_10"; break;
+    case SEEK_10: what = "SEEK_10"; break;
+    case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+    case VERIFY: what = "VERIFY"; break;
+    case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+    case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+    case SEARCH_LOW: what = "SEARCH_LOW"; break;
+    case SET_LIMITS: what = "SET_LIMITS"; break;
+    case READ_POSITION: what = "READ_POSITION"; break;
+    case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+    case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+    case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+    case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+    case COMPARE: what = "COMPARE"; break;
+    case COPY_VERIFY: what = "COPY_VERIFY"; break;
+    case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+    case READ_BUFFER: what = "READ_BUFFER"; break;
+    case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+    case READ_LONG: what = "READ_LONG"; break;
+    case WRITE_LONG: what = "WRITE_LONG"; break;
+    case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+    case WRITE_SAME: what = "WRITE_SAME"; break;
+    case READ_TOC: what = "READ_TOC"; break;
+    case LOG_SELECT: what = "LOG_SELECT"; break;
+    case LOG_SENSE: what = "LOG_SENSE"; break;
+    case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+    case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+    case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
+    case READ_12: what = "READ_12"; break;
+    case WRITE_12: what = "WRITE_12"; break;
+    case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+    case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+    case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+    case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+    case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+    case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+    case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+    default: what = "??"; break;
+    }
+    printk(KERN_DEBUG USB_SCSI "Command %s (%d bytes)\n", what, srb->cmd_len);
+    printk(KERN_DEBUG USB_SCSI "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	   srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], 
+           srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
+}
diff -u --recursive --new-file v2.3.5/linux/drivers/usb/usb_scsi_dt.c linux/drivers/usb/usb_scsi_dt.c
--- v2.3.5/linux/drivers/usb/usb_scsi_dt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb_scsi_dt.c	Mon Jun  7 20:04:01 1999
@@ -0,0 +1,4 @@
+0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
+0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
diff -u --recursive --new-file v2.3.5/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.5/linux/drivers/video/atyfb.c	Thu Apr 22 19:30:08 1999
+++ linux/drivers/video/atyfb.c	Wed Jun  9 14:44:25 1999
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.106 1999/04/16 11:20:49 geert Exp $
+/*  $Id: atyfb.c,v 1.107 1999/06/08 19:59:03 geert Exp $
X  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
X  *
X  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -200,6 +200,7 @@
X     struct atyfb_par default_par;
X     struct atyfb_par current_par;
X     u32 total_vram;
+    u32 ref_clk_per;
X     u32 pll_per;
X     u32 mclk_per;
X     u16 chip_type;
@@ -326,9 +327,7 @@
X static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info);
X static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
X static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
-#if defined(__sparc__) || defined(DEBUG)
X static u8 aty_ld_pll(int offset, const struct fb_info_aty *info);
-#endif
X static void aty_set_crtc(const struct fb_info_aty *info,
X 			 const struct crtc *crtc);
X static int aty_var_to_crtc(const struct fb_info_aty *info,
@@ -341,7 +340,8 @@
X 			   const struct pll_gx *pll);
X static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll);
X static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll);
-static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per);
+static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per,
+			     const struct fb_info_aty *info);
X static void aty_set_pll_ct(const struct fb_info_aty *info,
X 			   const struct pll_ct *pll);
X static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
@@ -349,7 +349,8 @@
X 		      u8 bpp, struct pll_ct *pll);
X static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
X 			     u8 bpp, struct pll_ct *pll);
-static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per);
+static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per,
+			     const struct fb_info_aty *info);
X static void atyfb_set_par(const struct atyfb_par *par,
X 			  struct fb_info_aty *info);
X static int atyfb_decode_var(const struct fb_var_screeninfo *var,
@@ -405,8 +406,6 @@
X static int default_pll __initdata = 0;
X static int default_mclk __initdata = 0;
X 
-static const u32 ref_clk_per = 1000000000000ULL/14318180;
-
X #if defined(CONFIG_PPC)
X static int default_vmode __initdata = VMODE_NVRAM;
X static int default_cmode __initdata = CMODE_NVRAM;
@@ -689,7 +688,6 @@
X     aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
X }
X 
-#if defined(__sparc__) || defined(DEBUG)
X static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
X {
X     u8 res;
@@ -702,7 +700,6 @@
X     eieio();
X     return res;
X }
-#endif
X 
X #if defined(CONFIG_PPC)
X 
@@ -1455,7 +1452,8 @@
X 
X     /* FIXME: ATI18818?? */
X 
-static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per)
+static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per,
+			     const struct fb_info_aty *info)
X {
X     u8 df, vco_div_count, ref_div_count;
X 
@@ -1463,7 +1461,7 @@
X     vco_div_count = pll->m & 0x3f;
X     ref_div_count = pll->n;
X 
-    *vclk_per = ((ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
+    *vclk_per = ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
X 
X     return 0;
X }
@@ -1579,10 +1577,10 @@
X 
X     pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
X 
-    pll_ref_div = info->pll_per*2*255/ref_clk_per;
+    pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
X 
X     /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
-    q = ref_clk_per*pll_ref_div*4/info->mclk_per;	/* actually 8*q */
+    q = info->ref_clk_per*pll_ref_div*4/info->mclk_per;	/* actually 8*q */
X     if (q < 16*8 || q > 255*8)
X 	FAIL("mclk out of range");
X     else if (q < 32*8)
@@ -1596,7 +1594,7 @@
X     mclk_fb_div = q*mclk_post_div/8;
X 
X     /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
-    q = ref_clk_per*pll_ref_div*4/vclk_per;	/* actually 8*q */
+    q = info->ref_clk_per*pll_ref_div*4/vclk_per;	/* actually 8*q */
X     if (q < 16*8 || q > 255*8)
X 	FAIL("vclk out of range");
X     else if (q < 32*8)
@@ -1677,7 +1675,8 @@
X     return 0;
X }
X 
-static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per)
+static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per,
+			     const struct fb_info_aty *info)
X {
X     u8 pll_ref_div = pll->pll_ref_div;
X     u8 vclk_fb_div = pll->vclk_fb_div;
@@ -1691,7 +1690,7 @@
X 				    (vclk_post_div & 3)];
X     if (vpostdiv == 0)
X 	return -EINVAL;
-    *vclk_per = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2;
+    *vclk_per = pll_ref_div*vpostdiv*info->ref_clk_per/vclk_fb_div/2;
X     return 0;
X }
X 
@@ -1845,9 +1844,9 @@
X     if ((err = aty_crtc_to_var(&par->crtc, var)))
X 	return err;
X     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
-	err = aty_pll_gx_to_var(&par->pll.gx, &var->pixclock);
+	err = aty_pll_gx_to_var(&par->pll.gx, &var->pixclock, info);
X     else
-	err = aty_pll_ct_to_var(&par->pll.ct, &var->pixclock);
+	err = aty_pll_ct_to_var(&par->pll.ct, &var->pixclock, info);
X     if (err)
X 	return err;
X 
@@ -2432,11 +2431,12 @@
X     int j, k;
X     struct fb_var_screeninfo var;
X     struct display *disp;
-    const char *chipname = NULL, *ramname = NULL;
+    const char *chipname = NULL, *ramname = NULL, *xtal;
X     int pll, mclk, gtb_memsize;
X #if defined(CONFIG_PPC)
X     int sense;
X #endif
+    u8 pll_ref_div;
X 
X     info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
X     chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
@@ -2524,6 +2524,25 @@
X 	}
X     }
X 
+    info->ref_clk_per = 1000000000000ULL/14318180;
+    xtal = "14.31818";
+    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
+	  Gx == ET_CHIP_ID ||
+	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))) &&
+	(pll_ref_div = aty_ld_pll(PLL_REF_DIV, info))) {
+	int diff1, diff2;
+	diff1 = 510*14/pll_ref_div-pll;
+	diff2 = 510*29/pll_ref_div-pll;
+	if (diff1 < 0)
+	    diff1 = -diff1;
+	if (diff2 < 0)
+	    diff2 = -diff2;
+	if (diff2 < diff1) {
+	    info->ref_clk_per = 1000000000000ULL/29498928;
+	    xtal = "29.498928";
+	}
+    }
+
X     i = aty_ld_le32(MEM_CNTL, info);
X     gtb_memsize = !(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
X 		    Gx == ET_CHIP_ID ||
@@ -2602,9 +2621,9 @@
X     if (default_mclk)
X 	mclk = default_mclk;
X 
-    printk("%d%c %s, %d MHz PLL, %d Mhz MCLK\n", 
+    printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n", 
X     	   info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), 
-    	   info->total_vram == 0x80000 ? 'K' : 'M', ramname, pll, mclk);
+    	   info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk);
X 
X     if (mclk < 44)
X 	info->mem_refresh_rate = 0;	/* 000 = 10 Mhz - 43 Mhz */
diff -u --recursive --new-file v2.3.5/linux/drivers/video/igafb.c linux/drivers/video/igafb.c
--- v2.3.5/linux/drivers/video/igafb.c	Sun Mar  7 10:39:03 1999
+++ linux/drivers/video/igafb.c	Wed Jun  9 14:44:26 1999
@@ -630,6 +630,7 @@
X         struct fb_info_iga *info;
X         unsigned long addr;
X         extern int con_is_present(void);
+	int iga2000 = 0;
X 
X         /* Do not attach when we have a serial console. */
X         if (!con_is_present())
@@ -637,8 +638,13 @@
X 
X         pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 
X                                PCI_DEVICE_ID_INTERG_1682, 0);
-        if(pdev == NULL)
-                return;
+	if (pdev == NULL) {
+        	pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 
+                               0x2000, 0);
+        	if(pdev == NULL)
+        	        return;
+		iga2000 = 1;
+	}
X 
X         info = kmalloc(sizeof(struct fb_info_iga), GFP_ATOMIC);
X         if (!info) {
@@ -648,8 +654,10 @@
X         memset(info, 0, sizeof(struct fb_info_iga));
X 
X 	info->frame_buffer = pdev->base_address[0];
-	if (!info->frame_buffer)
+	if (!info->frame_buffer) {
+		kfree(info);
X 		return;
+	}
X 
X         pcibios_read_config_dword(0, pdev->devfn,
X                                   PCI_BASE_ADDRESS_0, 
@@ -659,12 +667,23 @@
X 	info->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
X 
X #ifdef __sparc__
-	
+
X 	info->io_base_phys = info->frame_buffer_phys;
-	
-	/* Obtain virtual address and correct physical by PCIC shift */
-	info->io_base = pcic_alloc_io(&info->io_base_phys);
+
+	/*
+	 * The right test would be to look if there is a base I/O address.
+	 * But it appears that IGA 1682 reuses _memory_ address as a base
+	 * for I/O accesses.
+	 */
+	if (iga2000) {
+		info->io_base = (int) sparc_alloc_io(info->frame_buffer_phys |
+		    0x00800000, NULL, 0x1000, "iga", 0, 0);
+	} else {
+		/* Obtain virtual address and correct physical by PCIC shift */
+		info->io_base = pcic_alloc_io(&info->io_base_phys);
+	}
X 	if (!info->io_base) {
+                kfree(info);
X 		return;
X 	}
X 
@@ -679,6 +698,7 @@
X 	info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
X 	if (!info->mmap_map) {
X                 printk("igafb_init: can't alloc mmap_map\n");
+		/* XXX Here we left I/O allocated */
X                 kfree(info);
X 		return;
X 	}
@@ -730,11 +750,11 @@
X             }
X 
X #endif
-            if (!iga_init(info)) {
-		    if (info->mmap_map)
-			    kfree(info->mmap_map);
-		    kfree(info);
-            }
+        if (!iga_init(info)) {
+		if (info->mmap_map)
+			kfree(info->mmap_map);
+		kfree(info);
+        }
X 
X #ifdef __sparc__
X 	    /*
diff -u --recursive --new-file v2.3.5/linux/fs/Config.in linux/fs/Config.in
--- v2.3.5/linux/fs/Config.in	Mon May 31 22:28:06 1999
+++ linux/fs/Config.in	Wed Jun  9 18:42:08 1999
@@ -73,9 +73,9 @@
X   fi
X   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
X     tristate 'NFS server support' CONFIG_NFSD
-  fi
-  if [ "$CONFIG_NFSD" != "n" ]; then
-    bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
+    if [ "$CONFIG_NFSD" != "n" ]; then
+      bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
+    fi
X   fi
X   if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
X     define_bool CONFIG_SUNRPC y
diff -u --recursive --new-file v2.3.5/linux/fs/adfs/super.c linux/fs/adfs/super.c
--- v2.3.5/linux/fs/adfs/super.c	Fri Mar 26 13:57:41 1999
+++ linux/fs/adfs/super.c	Tue Jun  8 10:47:58 1999
@@ -300,7 +300,7 @@
X 	 */
X 	sb->s_op = &adfs_sops;
X 	sb->u.adfs_sb.s_root = adfs_inode_generate(dr->root, 0);
-	sb->s_root = d_alloc_root(iget(sb, sb->u.adfs_sb.s_root), NULL);
+	sb->s_root = d_alloc_root(iget(sb, sb->u.adfs_sb.s_root));
X 
X 	if (!sb->s_root) {
X 		for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
@@ -312,8 +312,7 @@
X 	return sb;
X 
X error_free_bh:
-	if (bh)
-		brelse(bh);
+	brelse(bh);
X error_unlock:
X 	unlock_super(sb);
X error_dec_use:
diff -u --recursive --new-file v2.3.5/linux/fs/affs/super.c linux/fs/affs/super.c
--- v2.3.5/linux/fs/affs/super.c	Sun Mar  7 15:25:23 1999
+++ linux/fs/affs/super.c	Tue Jun  8 10:47:58 1999
@@ -543,7 +543,7 @@
X 	root_inode = iget(s,root_block);
X 	if (!root_inode)
X 		goto out_no_root;
-	s->s_root  = d_alloc_root(root_inode, NULL);
+	s->s_root  = d_alloc_root(root_inode);
X 	if (!s->s_root)
X 		goto out_no_root;
X 	s->s_root->d_op = &affs_dentry_operations;
diff -u --recursive --new-file v2.3.5/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.3.5/linux/fs/autofs/inode.c	Mon Jan 11 15:03:30 1999
+++ linux/fs/autofs/inode.c	Tue Jun  8 10:47:58 1999
@@ -176,7 +176,7 @@
X 	 * Get the root inode and dentry, but defer checking for errors.
X 	 */
X 	root_inode = iget(s, AUTOFS_ROOT_INO);
-	root = d_alloc_root(root_inode, NULL);
+	root = d_alloc_root(root_inode);
X 	pipe = NULL;
X 
X 	/*
diff -u --recursive --new-file v2.3.5/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.5/linux/fs/binfmt_aout.c	Wed Jun  2 14:44:39 1999
+++ linux/fs/binfmt_aout.c	Tue Jun  8 23:01:35 1999
@@ -49,9 +49,7 @@
X 	end = PAGE_ALIGN(end);
X 	if (end <= start)
X 		return;
-	do_mmap(NULL, start, end - start,
-		PROT_READ | PROT_WRITE | PROT_EXEC,
-		MAP_FIXED | MAP_PRIVATE, 0);
+	do_brk(start, end - start);
X }
X 
X /*
@@ -372,14 +370,10 @@
X #ifdef __sparc__
X 	if (N_MAGIC(ex) == NMAGIC) {
X 		/* Fuck me plenty... */
-		error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
-				PROT_READ|PROT_WRITE|PROT_EXEC,
-				MAP_FIXED|MAP_PRIVATE, 0);
+		error = do_brk(N_TXTADDR(ex), ex.a_text);
X 		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
X 			  ex.a_text, 0);
-		error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
-				PROT_READ|PROT_WRITE|PROT_EXEC,
-				MAP_FIXED|MAP_PRIVATE, 0);
+		error = do_brk(N_DATADDR(ex), ex.a_data);
X 		read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
X 			  ex.a_data, 0);
X 		goto beyond_if;
@@ -388,16 +382,12 @@
X 
X 	if (N_MAGIC(ex) == OMAGIC) {
X #if defined(__alpha__) || defined(__sparc__)
-		do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
-			ex.a_text+ex.a_data + PAGE_SIZE - 1,
-			PROT_READ|PROT_WRITE|PROT_EXEC,
-			MAP_FIXED|MAP_PRIVATE, 0);
+		do_brk(N_TXTADDR(ex) & PAGE_MASK,
+			ex.a_text+ex.a_data + PAGE_SIZE - 1);
X 		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
X 			  ex.a_text+ex.a_data, 0);
X #else
-		do_mmap(NULL, 0, ex.a_text+ex.a_data,
-			PROT_READ|PROT_WRITE|PROT_EXEC,
-			MAP_FIXED|MAP_PRIVATE, 0);
+		do_brk(0, ex.a_text+ex.a_data);
X 		read_exec(bprm->dentry, 32, (char *) 0, ex.a_text+ex.a_data, 0);
X #endif
X 		flush_icache_range((unsigned long) 0,
@@ -421,9 +411,7 @@
X 
X 		if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
X 			sys_close(fd);
-			do_mmap(NULL, 0, ex.a_text+ex.a_data,
-				PROT_READ|PROT_WRITE|PROT_EXEC,
-				MAP_FIXED|MAP_PRIVATE, 0);
+			do_brk(0, ex.a_text+ex.a_data);
X 			read_exec(bprm->dentry, fd_offset,
X 				  (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
X 			flush_icache_range((unsigned long) N_TXTADDR(ex),
@@ -574,9 +562,7 @@
X 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
X 	bss = ex.a_text + ex.a_data + ex.a_bss;
X 	if (bss > len) {
-		error = do_mmap(NULL, start_addr + len, bss - len,
-				PROT_READ | PROT_WRITE | PROT_EXEC,
-				MAP_PRIVATE | MAP_FIXED, 0);
+		error = do_brk(start_addr + len, bss - len);
X 		retval = error;
X 		if (error != start_addr + len)
X 			goto out_putf;
diff -u --recursive --new-file v2.3.5/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.5/linux/fs/binfmt_elf.c	Wed Jun  2 14:44:39 1999
+++ linux/fs/binfmt_elf.c	Thu Jun  3 23:15:29 1999
@@ -77,9 +77,7 @@
X 	end = ELF_PAGEALIGN(end);
X 	if (end <= start)
X 		return;
-	do_mmap(NULL, start, end - start,
-		PROT_READ | PROT_WRITE | PROT_EXEC,
-		MAP_FIXED | MAP_PRIVATE, 0);
+	do_brk(start, end - start);
X }
X 
X 
@@ -328,9 +326,7 @@
X 
X 	/* Map the last of the bss segment */
X 	if (last_bss > elf_bss)
-		do_mmap(NULL, elf_bss, last_bss - elf_bss,
-			PROT_READ|PROT_WRITE|PROT_EXEC,
-			MAP_FIXED|MAP_PRIVATE, 0);
+		do_brk(elf_bss, last_bss - elf_bss);
X 
X 	*interp_load_addr = load_addr;
X 	error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
@@ -370,17 +366,15 @@
X 		goto out;
X 	}
X 
-	do_mmap(NULL, 0, text_data,
-		PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0);
+	do_brk(0, text_data);
X 	retval = read_exec(interpreter_dentry, offset, addr, text_data, 0);
X 	if (retval < 0)
X 		goto out;
X 	flush_icache_range((unsigned long)addr,
X 	                   (unsigned long)addr + text_data);
X 
-	do_mmap(NULL, ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1),
-		interp_ex->a_bss,
-		PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0);
+	do_brk(ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1),
+		interp_ex->a_bss);
X 	elf_entry = interp_ex->a_entry;
X 
X out:
@@ -885,9 +879,7 @@
X 				ELF_EXEC_PAGESIZE - 1);
X 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
X 	if (bss > len)
-		do_mmap(NULL, len, bss - len,
-			PROT_READ|PROT_WRITE|PROT_EXEC,
-			MAP_FIXED|MAP_PRIVATE, 0);
+		do_brk(len, bss - len);
X 	error = 0;
X 
X out_free_ph:
diff -u --recursive --new-file v2.3.5/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.5/linux/fs/buffer.c	Sat May 15 23:46:04 1999
+++ linux/fs/buffer.c	Tue Jun  8 10:47:58 1999
@@ -90,7 +90,7 @@
X /* The dummy values in this structure are left in there for compatibility
X  * with old programs that play with the /proc entries.
X  */
-union bdflush_param{
+union bdflush_param {
X 	struct {
X 		int nfract;  /* Percentage of buffer cache dirty to 
X 				activate bdflush */
diff -u --recursive --new-file v2.3.5/linux/fs/coda/inode.c linux/fs/coda/inode.c
--- v2.3.5/linux/fs/coda/inode.c	Wed Mar 10 17:03:52 1999
+++ linux/fs/coda/inode.c	Tue Jun  8 10:47:58 1999
@@ -115,7 +115,7 @@
X 	printk("coda_read_super: rootinode is %ld dev %d\n", 
X 	       root->i_ino, root->i_dev);
X 	sbi->sbi_root = root;
-	sb->s_root = d_alloc_root(root, NULL);
+	sb->s_root = d_alloc_root(root);
X 	unlock_super(sb);
X 	EXIT;  
X         return sb;
@@ -145,7 +145,7 @@
X         sb->s_dev = 0;
X 	coda_cache_clear_all(sb);
X 	sb_info = coda_sbp(sb);
-	sb_info->sbi_vcomm->vc_inuse = 0;
+/*	sb_info->sbi_vcomm->vc_inuse = 0; You can not do this: psdev_release would see usagecount == 0 and would refuse to decrease MOD_USE_COUNT --pavel */ 
X 	coda_super_info.sbi_sb = NULL;
X 	printk("Coda: Bye bye.\n");
X 	memset(sb_info, 0, sizeof(* sb_info));
diff -u --recursive --new-file v2.3.5/linux/fs/dcache.c linux/fs/dcache.c
--- v2.3.5/linux/fs/dcache.c	Sun Apr 25 23:17:56 1999
+++ linux/fs/dcache.c	Tue Jun  8 10:47:58 1999
@@ -546,7 +546,7 @@
X 	entry->d_inode = inode;
X }
X 
-struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
+struct dentry * d_alloc_root(struct inode * root_inode)
X {
X 	struct dentry *res = NULL;
X 
diff -u --recursive --new-file v2.3.5/linux/fs/devpts/inode.c linux/fs/devpts/inode.c
--- v2.3.5/linux/fs/devpts/inode.c	Wed Jun  2 14:44:39 1999
+++ linux/fs/devpts/inode.c	Tue Jun  8 10:47:58 1999
@@ -163,7 +163,7 @@
X 	 * Get the root inode and dentry, but defer checking for errors.
X 	 */
X 	root_inode = iget(s, 1); /* inode 1 == root directory */
-	root = d_alloc_root(root_inode, NULL);
+	root = d_alloc_root(root_inode);
X 
X 	/*
X 	 * Check whether somebody else completed the super block.
diff -u --recursive --new-file v2.3.5/linux/fs/efs/super.c linux/fs/efs/super.c
--- v2.3.5/linux/fs/efs/super.c	Mon May 31 22:28:06 1999
+++ linux/fs/efs/super.c	Tue Jun  8 10:47:58 1999
@@ -204,7 +204,7 @@
X 	}
X 	s->s_op   = &efs_superblock_operations;
X 	s->s_dev  = dev;
-	s->s_root = d_alloc_root(iget(s, EFS_ROOTINODE), NULL);
+	s->s_root = d_alloc_root(iget(s, EFS_ROOTINODE));
X 	unlock_super(s);
X  
X 	if (!(s->s_root)) {
diff -u --recursive --new-file v2.3.5/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.3.5/linux/fs/ext2/super.c	Mon Apr 12 10:03:45 1999
+++ linux/fs/ext2/super.c	Tue Jun  8 10:47:58 1999
@@ -629,7 +629,7 @@
X 	 */
X 	sb->s_dev = dev;
X 	sb->s_op = &ext2_sops;
-	sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO), NULL);
+	sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
X 	if (!sb->s_root) {
X 		sb->s_dev = 0;
X 		for (i = 0; i < db_count; i++)
diff -u --recursive --new-file v2.3.5/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.3.5/linux/fs/ext2/symlink.c	Sat Sep 19 13:38:18 1998
+++ linux/fs/ext2/symlink.c	Wed Jun  9 20:46:53 1999
@@ -102,7 +102,6 @@
X 		i++;
X 	if (copy_to_user(buffer, link, i))
X 		i = -EFAULT;
- 	UPDATE_ATIME(inode);
X 	if (bh)
X 		brelse (bh);
X 	return i;
diff -u --recursive --new-file v2.3.5/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.3.5/linux/fs/fat/inode.c	Sat May 15 23:46:04 1999
+++ linux/fs/fat/inode.c	Tue Jun  8 10:47:58 1999
@@ -650,7 +650,7 @@
X 	root_inode->i_ino = MSDOS_ROOT_INO;
X 	fat_read_root(root_inode);
X 	insert_inode_hash(root_inode);
-	sb->s_root = d_alloc_root(root_inode, NULL);
+	sb->s_root = d_alloc_root(root_inode);
X 	if (!sb->s_root)
X 		goto out_no_root;
X 	if(i>=0) {
diff -u --recursive --new-file v2.3.5/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.3.5/linux/fs/fcntl.c	Fri Nov 13 10:07:26 1998
+++ linux/fs/fcntl.c	Mon Jun  7 12:10:22 1999
@@ -183,26 +183,15 @@
X 	return err;
X }
X 
-static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
+static void send_sigio_to_task(struct task_struct *p,
+			       struct fown_struct *fown, struct fasync_struct *fa)
X {
-	struct task_struct * p;
-	int   pid	= fown->pid;
-	uid_t uid	= fown->uid;
-	uid_t euid	= fown->euid;
-	
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		int match = p->pid;
-		if (pid < 0)
-			match = -p->pgrp;
-		if (pid != match)
-			continue;
-		if ((euid != 0) &&
-		    (euid ^ p->suid) && (euid ^ p->uid) &&
-		    (uid ^ p->suid) && (uid ^ p->uid))
-			continue;
-		switch (fown->signum) {
-			siginfo_t si;
+	if ((fown->euid != 0) &&
+	    (fown->euid ^ p->suid) && (fown->euid ^ p->uid) &&
+	    (fown->uid ^ p->suid) && (fown->uid ^ p->uid))
+		return;
+	switch (fown->signum) {
+		siginfo_t si;
X 		default:
X 			/* Queue a rt signal with the appropriate fd as its
X 			   value.  We use SI_SIGIO as the source, not 
@@ -213,16 +202,36 @@
X 			si.si_signo = fown->signum;
X 			si.si_errno = 0;
X 		        si.si_code  = SI_SIGIO;
-			si.si_pid   = pid;
-			si.si_uid   = uid;
+			si.si_pid   = fown->pid;
+			si.si_uid   = fown->uid;
X 			si.si_fd    = fa->fa_fd;
X 			if (!send_sig_info(fown->signum, &si, p))
X 				break;
X 		/* fall-through: fall back on the old plain SIGIO signal */
X 		case 0:
X 			send_sig(SIGIO, p, 1);
-		}
X 	}
+}
+
+static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
+{
+	struct task_struct * p;
+	int   pid	= fown->pid;
+	
+	read_lock(&tasklist_lock);
+	if ( (pid > 0) && (p = find_task_by_pid(pid)) ) {
+		send_sigio_to_task(p, fown, fa);
+		goto out;
+	}
+	for_each_task(p) {
+		int match = p->pid;
+		if (pid < 0)
+			match = -p->pgrp;
+		if (pid != match)
+			continue;
+		send_sigio_to_task(p, fown, fa);
+	}
+out:
X 	read_unlock(&tasklist_lock);
X }
X 
diff -u --recursive --new-file v2.3.5/linux/fs/hfs/bnode.c linux/fs/hfs/bnode.c
--- v2.3.5/linux/fs/hfs/bnode.c	Mon May 17 09:55:22 1999
+++ linux/fs/hfs/bnode.c	Fri Jun  4 13:30:25 1999
@@ -123,6 +123,8 @@
X 	bnode->tree = tree;
X 	bnode->node = node;
X 	bnode->sticky = sticky;
+	hfs_init_waitqueue(&bnode->rqueue);
+	hfs_init_waitqueue(&bnode->wqueue);
X 
X 	if (sticky == HFS_NOT_STICKY) {
X 		/* Insert it in the cache if appropriate */
diff -u --recursive --new-file v2.3.5/linux/fs/hfs/btree.c linux/fs/hfs/btree.c
--- v2.3.5/linux/fs/hfs/btree.c	Fri May 14 18:55:24 1999
+++ linux/fs/hfs/btree.c	Fri Jun  4 13:30:25 1999
@@ -173,7 +173,7 @@
X 	bt->sys_mdb = mdb->sys_mdb;
X 	bt->reserved = 0;
X 	bt->lock = 0;
-	init_waitqueue_head(&bt->wait);
+	hfs_init_waitqueue(&bt->wait);
X 	bt->dirt = 0;
X 	memset(bt->cache, 0, sizeof(bt->cache));
X 
diff -u --recursive --new-file v2.3.5/linux/fs/hfs/catalog.c linux/fs/hfs/catalog.c
--- v2.3.5/linux/fs/hfs/catalog.c	Mon May 17 09:55:22 1999
+++ linux/fs/hfs/catalog.c	Fri Jun  4 13:30:25 1999
@@ -302,6 +302,8 @@
X 		entry->modify_date = hfs_get_nl(cat->u.dir.MdDat);
X 		entry->backup_date = hfs_get_nl(cat->u.dir.BkDat);
X 		dir->dirs = dir->files = 0;
+		hfs_init_waitqueue(&dir->read_wait);
+		hfs_init_waitqueue(&dir->write_wait);
X 	} else if (cat->cdrType == HFS_CDR_FIL) {
X 		struct hfs_file *fil = &entry->u.file;
X 
diff -u --recursive --new-file v2.3.5/linux/fs/hfs/mdb.c linux/fs/hfs/mdb.c
--- v2.3.5/linux/fs/hfs/mdb.c	Wed Dec 23 14:10:36 1998
+++ linux/fs/hfs/mdb.c	Fri Jun  4 13:30:25 1999
@@ -99,7 +99,9 @@
X 	memset(mdb, 0, sizeof(*mdb));
X 	mdb->magic = HFS_MDB_MAGIC;
X 	mdb->sys_mdb = sys_mdb;
-	INIT_LIST_HEAD(&mdb->entry_dirty);  
+	INIT_LIST_HEAD(&mdb->entry_dirty);
+	hfs_init_waitqueue(&mdb->rename_wait);
+	hfs_init_waitqueue(&mdb->bitmap_wait);
X 
X 	/* See if this is an HFS filesystem */
X 	buf = hfs_buffer_get(sys_mdb, part_start + HFS_MDB_BLK, 1);
diff -u --recursive --new-file v2.3.5/linux/fs/hfs/super.c linux/fs/hfs/super.c
--- v2.3.5/linux/fs/hfs/super.c	Fri May 14 18:55:24 1999
+++ linux/fs/hfs/super.c	Tue Jun  8 10:47:58 1999
@@ -466,7 +466,7 @@
X 	if (!root_inode) 
X 		goto bail_no_root;
X 	  
-	s->s_root = d_alloc_root(root_inode, NULL);
+	s->s_root = d_alloc_root(root_inode);
X 	if (!s->s_root) 
X 		goto bail_no_root;
X 
diff -u --recursive --new-file v2.3.5/linux/fs/hpfs/alloc.c linux/fs/hpfs/alloc.c
--- v2.3.5/linux/fs/hpfs/alloc.c	Mon May 17 09:55:22 1999
+++ linux/fs/hpfs/alloc.c	Fri Jun  4 01:06:29 1999
@@ -164,8 +164,11 @@
X 	if (near && near < s->s_hpfs_fs_size)
X 		if ((sec = alloc_in_bmp(s, near, n, f_p ? forward : forward/4))) goto ret;
X 	if (b != -1) {
-		if (b < 0x10000000) if ((sec = alloc_in_bmp(s, b<<14, n, f_p ? forward : forward/2))) goto ret;
-		else if ((sec = alloc_in_bmp(s, (b&0xfffffff)<<14, n, f_p ? forward : 0))) goto ret;
+		if ((sec = alloc_in_bmp(s, b<<14, n, f_p ? forward : forward/2))) {
+			b &= 0x0fffffff;
+			goto ret;
+		}
+		if (b > 0x10000000) if ((sec = alloc_in_bmp(s, (b&0xfffffff)<<14, n, f_p ? forward : 0))) goto ret;
X 	}	
X 	n_bmps = (s->s_hpfs_fs_size + 0x4000 - 1) >> 14;
X 	for (i = 0; i < n_bmps / 2; i++) {
diff -u --recursive --new-file v2.3.5/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.3.5/linux/fs/hpfs/hpfs_fn.h	Mon May 17 09:55:22 1999
+++ linux/fs/hpfs/hpfs_fn.h	Fri Jun  4 01:06:29 1999
@@ -36,7 +36,7 @@
X #define ANODE_ALLOC_FWD	512
X #define FNODE_ALLOC_FWD	0
X #define ALLOC_FWD_MIN	16
-#define ALLOC_FWD_MAX	512
+#define ALLOC_FWD_MAX	128
X #define ALLOC_M		1
X #define FNODE_RD_AHEAD	16
X #define ANODE_RD_AHEAD	16
diff -u --recursive --new-file v2.3.5/linux/fs/hpfs/namei.c linux/fs/hpfs/namei.c
--- v2.3.5/linux/fs/hpfs/namei.c	Wed Jun  2 14:44:39 1999
+++ linux/fs/hpfs/namei.c	Fri Jun  4 01:06:29 1999
@@ -482,14 +482,9 @@
X 	de.hidden = new_name[0] == '.';
X 
X 	if (new_inode) {
-		hpfs_brelse4(&qbh);
-		if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) {
-			int r;
-			if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
-				if (!(nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) {
-					hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent #2");
-					goto end1;
-				}
+		int r;
+		if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
+			if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) {
X 				new_inode->i_nlink = 0;
X 				copy_de(nde, &de);
X 				memcpy(nde->name, new_name, new_len);
@@ -497,11 +492,11 @@
X 				hpfs_brelse4(&qbh1);
X 				goto end;
X 			}
-			err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
+			hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent");
+			err = -EFSERROR;
X 			goto end1;
X 		}
-		hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent");
-		err = -EFSERROR;
+		err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
X 		goto end1;
X 	}
X 
diff -u --recursive --new-file v2.3.5/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.3.5/linux/fs/hpfs/super.c	Wed Jun  2 14:44:39 1999
+++ linux/fs/hpfs/super.c	Tue Jun  8 10:47:58 1999
@@ -528,7 +528,7 @@
X 	brelse(bh0);
X 
X 	hpfs_lock_iget(s, 1);
-	s->s_root = d_alloc_root(iget(s, s->s_hpfs_root), NULL);
+	s->s_root = d_alloc_root(iget(s, s->s_hpfs_root));
X 	hpfs_unlock_iget(s);
X 	unlock_super(s);
X 	if (!s->s_root || !s->s_root->d_inode) {
diff -u --recursive --new-file v2.3.5/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.5/linux/fs/isofs/inode.c	Mon May 31 22:28:06 1999
+++ linux/fs/isofs/inode.c	Tue Jun  8 10:47:58 1999
@@ -835,7 +835,7 @@
X 	if (!inode->i_op)
X 		goto out_bad_root;
X 	/* get the root dentry */
-	s->s_root = d_alloc_root(inode, NULL);
+	s->s_root = d_alloc_root(inode);
X 	if (!(s->s_root))
X 		goto out_no_root;
X 
diff -u --recursive --new-file v2.3.5/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v2.3.5/linux/fs/minix/bitmap.c	Tue Oct 20 14:08:14 1998
+++ linux/fs/minix/bitmap.c	Tue Jun  8 10:47:58 1999
@@ -140,7 +140,7 @@
X 	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
X 		printk("Bad inode number on dev %s: %d is out of range\n",
X 		       kdevname(inode->i_dev), ino);
-		return 0;
+		return NULL;
X 	}
X 	block = (2 + inode->i_sb->u.minix_sb.s_imap_blocks +
X 		 inode->i_sb->u.minix_sb.s_zmap_blocks +
@@ -148,7 +148,7 @@
X 	bh = bread(inode->i_dev, block, BLOCK_SIZE);
X 	if (!bh) {
X 		printk("unable to read i-node block\n");
-		return 0;
+		return NULL;
X 	}
X 	raw_inode = ((struct minix_inode *)bh->b_data +
X 		     (ino - 1) % MINIX_INODES_PER_BLOCK);
@@ -168,7 +168,7 @@
X 	if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
X 		printk("Bad inode number on dev %s: %d is out of range\n",
X 		       kdevname(inode->i_dev), ino);
-		return 0;
+		return NULL;
X 	}
X 	block = (2 + inode->i_sb->u.minix_sb.s_imap_blocks +
X 		 inode->i_sb->u.minix_sb.s_zmap_blocks +
@@ -176,7 +176,7 @@
X 	bh = bread(inode->i_dev, block, BLOCK_SIZE);
X 	if (!bh) {
X 		printk("unable to read i-node block\n");
-		return 0;
+		return NULL;
X 	}
X 	raw_inode = ((struct minix2_inode *) bh->b_data +
X 		     (ino - 1) % MINIX2_INODES_PER_BLOCK);
diff -u --recursive --new-file v2.3.5/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.3.5/linux/fs/minix/inode.c	Fri May 14 18:55:25 1999
+++ linux/fs/minix/inode.c	Tue Jun  8 10:47:58 1999
@@ -266,7 +266,7 @@
X 	if (errmsg)
X 		goto out_bad_root;
X 
-	s->s_root = d_alloc_root(root_inode, NULL);
+	s->s_root = d_alloc_root(root_inode);
X 	if (!s->s_root)
X 		goto out_iput;
X 
diff -u --recursive --new-file v2.3.5/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.3.5/linux/fs/minix/namei.c	Mon May 17 09:55:23 1999
+++ linux/fs/minix/namei.c	Tue Jun  8 10:47:58 1999
@@ -184,12 +184,7 @@
X 			dir->i_size = block*bh->b_size + offset;
X 			mark_inode_dirty(dir);
X 		}
-		if (de->inode) {
-			if (namecompare(namelen, info->s_namelen, name, de->name)) {
-				brelse(bh);
-				return -EEXIST;
-			}
-		} else {
+		if (!de->inode) {
X 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
X 			mark_inode_dirty(dir);
X 			for (i = 0; i < info->s_namelen ; i++)
diff -u --recursive --new-file v2.3.5/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.3.5/linux/fs/ncpfs/inode.c	Sat May 15 23:46:04 1999
+++ linux/fs/ncpfs/inode.c	Tue Jun  8 10:47:58 1999
@@ -431,7 +431,7 @@
X         if (!root_inode)
X 		goto out_no_root;
X 	DPRINTK(KERN_DEBUG "ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
-        server->root_dentry = sb->s_root = d_alloc_root(root_inode, NULL);
+        server->root_dentry = sb->s_root = d_alloc_root(root_inode);
X         if (!sb->s_root)
X 		goto out_no_root;
X 	server->root_dentry->d_op = &ncp_dentry_operations;
diff -u --recursive --new-file v2.3.5/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.3.5/linux/fs/nfs/dir.c	Fri May 14 18:55:26 1999
+++ linux/fs/nfs/dir.c	Tue Jun  8 17:58:03 1999
@@ -14,8 +14,10 @@
X  *              Following Linus comments on my original hack, this version
X  *              depends only on the dcache stuff and doesn't touch the inode
X  *              layer (iput() and friends).
+ *  6 Jun 1999	Cache readdir lookups in the page cache. -DaveM
X  */
X 
+#define NFS_NEED_XDR_TYPES
X #include <linux/sched.h>
X #include <linux/errno.h>
X #include <linux/stat.h>
@@ -24,31 +26,16 @@
X #include <linux/kernel.h>
X #include <linux/malloc.h>
X #include <linux/mm.h>
-#include <linux/sunrpc/types.h>
+#include <linux/sunrpc/clnt.h>
X #include <linux/nfs_fs.h>
+#include <linux/nfs.h>
+#include <linux/pagemap.h>
X 
X #include <asm/segment.h>	/* for fs functions */
X 
X #define NFS_PARANOIA 1
X /* #define NFS_DEBUG_VERBOSE 1 */
X 
-/*
- * Head for a dircache entry. Currently still very simple; when
- * the cache grows larger, we will need a LRU list.
- */
-struct nfs_dirent {
-	dev_t			dev;		/* device number */
-	ino_t			ino;		/* inode number */
-	u32			cookie;		/* cookie of first entry */
-	unsigned short		valid  : 1,	/* data is valid */
-				locked : 1;	/* entry locked */
-	unsigned int		size;		/* # of entries */
-	unsigned long		age;		/* last used */
-	unsigned long		mtime;		/* last attr stamp */
-	wait_queue_head_t	wait;
-	__u32 *			entry;		/* three __u32's per entry */
-};
-
X static int nfs_safe_remove(struct dentry *);
X 
X static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
@@ -107,253 +94,326 @@
X 	return -EISDIR;
X }
X 
-static struct nfs_dirent	dircache[NFS_MAX_DIRCACHE];
+/* Each readdir response is composed of entries which look
+ * like the following, as per the NFSv2 RFC:
+ *
+ *	__u32	not_end			zero if end of response
+ *	__u32	file ID			opaque ino_t
+ *	__u32	namelen			size of name string
+ *	VAR	name string		the string, padded to modulo 4 bytes
+ *	__u32	cookie			opaque ID of next entry
+ *
+ * When you hit not_end being zero, the next __u32 is non-zero if
+ * this is the end of the complete set of readdir entires for this
+ * directory.  This can be used, for example, to initiate pre-fetch.
+ *
+ * In order to know what to ask the server for, we only need to know
+ * the final cookie of the previous page, and offset zero has cookie
+ * zero, so we cache cookie to page offset translations in chunks.
+ */
+#define COOKIES_PER_CHUNK (8 - ((sizeof(void *) / sizeof(__u32))))
+struct nfs_cookie_table {
+	struct nfs_cookie_table *next;
+	__u32	cookies[COOKIES_PER_CHUNK];
+};
+static kmem_cache_t *nfs_cookie_cachep;
X 
-/*
- * We need to do caching of directory entries to prevent an
- * incredible amount of RPC traffic.  Only the most recent open
- * directory is cached.  This seems sufficient for most purposes.
- * Technically, we ought to flush the cache on close but this is
- * not a problem in practice.
+/* Since a cookie of zero is declared special by the NFS
+ * protocol, we easily can tell if a cookie in an existing
+ * table chunk is valid or not.
X  *
- * XXX: Do proper directory caching by stuffing data into the
- * page cache (may require some fiddling for rsize < PAGE_SIZE).
+ * NOTE: The cookies are indexed off-by-one because zero
+ *       need not an entry.
X  */
+static __inline__ __u32 *find_cookie(struct inode *inode, unsigned long off)
+{
+	static __u32 cookie_zero = 0;
+	struct nfs_cookie_table *p;
+	__u32 *ret;
+
+	if (!off)
+		return &cookie_zero;
+	off -= 1;
+	p = NFS_COOKIES(inode);
+	while(off >= COOKIES_PER_CHUNK && p) {
+		off -= COOKIES_PER_CHUNK;
+		p = p->next;
+	}
+	ret = NULL;
+	if (p) {
+		ret = &p->cookies[off];
+		if (!*ret)
+			ret = NULL;
+	}
+	return ret;
+}
X 
-static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+/* Now we cache directories properly, by stuffing the dirent
+ * data directly in the page cache.
+ *
+ * Inode invalidation due to refresh etc. takes care of
+ * _everything_, no sloppy entry flushing logic, no extraneous
+ * copying, network direct to page cache, the way it was meant
+ * to be.
+ *
+ * NOTE: Dirent information verification is done always by the
+ *	 page-in of the RPC reply, nowhere else, this simplies
+ *	 things substantially.
+ */
+#define NFS_NAMELEN_ALIGN(__len) ((((__len)+3)>>2)<<2)
+static u32 find_midpoint(__u32 *p, u32 doff)
X {
-	struct dentry 		*dentry = filp->f_dentry;
-	struct inode 		*inode = dentry->d_inode;
-	static DECLARE_WAIT_QUEUE_HEAD(readdir_wait);
-	wait_queue_head_t	*waitp = NULL;
-	struct nfs_dirent	*cache, *free;
-	unsigned long		age, dead;
-	u32			cookie;
-	int			ismydir, result;
-	int			i, j, index = 0;
-	__u32			*entry;
-	char			*name, *start;
+	u32 walk = doff & PAGE_MASK;
X 
-	dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
+	while(*p++ != 0) {
+		__u32 skip;
X 
-	result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-	if (result < 0)
-		goto out;
+		p++; /* skip fileid */
X 
-	/*
-	 * Try to find the entry in the cache
-	 */
-again:
-	if (waitp) {
-		interruptible_sleep_on(waitp);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		waitp = NULL;
+		/* Skip len, name, and cookie. */
+		skip = NFS_NAMELEN_ALIGN(*p++);
+		p += (skip >> 2) + 1;
+		walk += skip + (4 * sizeof(__u32));
+		if (walk >= doff)
+			break;
X 	}
+	return walk;
+}
X 
-	cookie = filp->f_pos;
-	entry  = NULL;
-	free   = NULL;
-	age    = ~(unsigned long) 0;
-	dead   = jiffies - NFS_ATTRTIMEO(inode);
+static int create_cookie(__u32 cookie, unsigned long off, struct inode *inode)
+{
+	struct nfs_cookie_table **cpp;
X 
-	for (i = 0, cache = dircache; i < NFS_MAX_DIRCACHE; i++, cache++) {
-		/*
-		dprintk("NFS: dircache[%d] valid %d locked %d\n",
-					i, cache->valid, cache->locked);
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 18'
echo 'File patch-2.3.6 is continued in part 19'
echo 19 > _shar_seq_.tmp
exit 0
#!/bin/sh
# this is part 20 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 20; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
-			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
+			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
X 			
X 	if (IS_ERR (base)) return NULL;
X 	
diff -u --recursive --new-file v2.3.5/linux/include/asm-sparc/pcic.h linux/include/asm-sparc/pcic.h
--- v2.3.5/linux/include/asm-sparc/pcic.h	Sun Oct  4 10:22:44 1998
+++ linux/include/asm-sparc/pcic.h	Wed Jun  9 14:44:26 1999
@@ -1,4 +1,4 @@
-/* $Id: pcic.h,v 1.1 1998/09/22 05:54:39 jj Exp $
+/* $Id: pcic.h,v 1.2 1999/06/03 15:02:51 davem Exp $
X  * pcic.h: JavaEngine 1 specific PCI definitions.
X  *
X  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -7,6 +7,8 @@
X #ifndef __SPARC_PCIC_H
X #define __SPARC_PCIC_H
X 
+#ifndef __ASSEMBLY__
+
X #include <linux/types.h>
X #include <linux/smp.h>
X #include <linux/smp_lock.h>
@@ -21,13 +23,17 @@
X         unsigned long           pcic_config_space_addr;
X         unsigned long           pcic_config_space_data;
X         struct linux_pbm_info   pbm;
+	struct pcic_ca2irq	*pcic_imap;
+	int			pcic_imdim;
X };
X 
X extern unsigned long pcic_alloc_io(unsigned long* addr);
X extern void pcic_probe(void);
X extern void sun4m_pci_init_IRQ(void);
X 
-/* Size of PCI Space */
+#endif
+
+/* Size of PCI I/O space which we relocate. */
X #define PCI_SPACE_SIZE                  0x1000000       /* 16 MB */
X 
X /* PCIC Register Set. */
@@ -50,10 +56,18 @@
X #define PCI_SOFTWARE_INT_CLEAR          0x6a    /* 16 bits */
X #define PCI_SOFTWARE_INT_SET            0x6e    /* 16 bits */
X #define PCI_SYS_INT_PENDING             0x70    /* 32 bits */
+#define  PCI_SYS_INT_PENDING_PIO		0x40000000
+#define  PCI_SYS_INT_PENDING_DMA		0x20000000
+#define  PCI_SYS_INT_PENDING_PCI		0x10000000
+#define  PCI_SYS_INT_PENDING_APSR		0x08000000
X #define PCI_SYS_INT_TARGET_MASK         0x74    /* 32 bits */
X #define PCI_SYS_INT_TARGET_MASK_CLEAR   0x78    /* 32 bits */
X #define PCI_SYS_INT_TARGET_MASK_SET     0x7c    /* 32 bits */
X #define PCI_SYS_INT_PENDING_CLEAR       0x83    /* 8  bits */
+#define  PCI_SYS_INT_PENDING_CLEAR_ALL		0x80
+#define  PCI_SYS_INT_PENDING_CLEAR_PIO		0x40
+#define  PCI_SYS_INT_PENDING_CLEAR_DMA		0x20
+#define  PCI_SYS_INT_PENDING_CLEAR_PCI		0x10
X #define PCI_IOTLB_CONTROL               0x84    /* 8  bits */
X #define PCI_INT_SELECT_LO               0x88    /* 16 bits */
X #define PCI_ARBITRATION_SELECT          0x8a    /* 16 bits */
diff -u --recursive --new-file v2.3.5/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.3.5/linux/include/asm-sparc64/namei.h	Thu Apr 22 19:24:52 1999
+++ linux/include/asm-sparc64/namei.h	Wed Jun  9 16:24:15 1999
@@ -28,7 +28,7 @@
X 
X 	base = lookup_dentry (emul, 
X 			      dget (current->fs->root), 
-			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
+			      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
X 			
X 	if (IS_ERR (base)) return NULL;
X 	
diff -u --recursive --new-file v2.3.5/linux/include/linux/cyclomx.h linux/include/linux/cyclomx.h
--- v2.3.5/linux/include/linux/cyclomx.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/cyclomx.h	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,91 @@
+/*
+* cyclomx.h	CYCLOM X Multiprotocol WAN Link Driver.
+*		User-level API definitions.
+*
+* Author:	Arnaldo Carvalho de Melo <ac...@conectiva.com.br>
+*
+* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Based on wanpipe.h by Gene Kozin <ge...@compuserve.com>
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* 1999/05/19	acme		wait_queue_head_t wait_stats(support for 2.3.*)
+* 1999/01/03	acme		judicious use of data types
+* Dec 27, 1998	Arnaldo		cleanup: PACKED not needed
+* Aug 08, 1998	Arnaldo		Version 0.0.1
+*/
+#ifndef	_CYCLOMX_H
+#define	_CYCLOMX_H
+
+#include <linux/wanrouter.h>
+#include <asm/spinlock.h>
+
+#ifdef	__KERNEL__
+/* Kernel Interface */
+
+#include <linux/cycx_drv.h>	/* CYCLOM X support module API definitions */
+#include <linux/cycx_cfm.h>	/* CYCLOM X firmware module definitions */
+#ifdef CONFIG_CYCLOMX_X25
+#include <linux/cycx_x25.h>
+#endif
+
+#ifndef	min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef	max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define	is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0)
+
+/* Adapter Data Space.
+ * This structure is needed because we handle multiple cards, otherwise
+ * static data would do it.
+ */
+typedef struct cycx {
+	char devname[WAN_DRVNAME_SZ+1];	/* card name */
+	cycxhw_t hw;			/* hardware configuration */
+	wan_device_t wandev;		/* WAN device data space */
+	u32 open_cnt;			/* number of open interfaces */
+	u32 state_tick;			/* link state timestamp */
+	spinlock_t lock;
+	char in_isr;			/* interrupt-in-service flag */
+	char buff_int_mode_unbusy;      /* flag for carrying out dev_tint */
+	u16 irq_dis_if_send_count;	/* Disabling irqs in if_send*/
+#if LINUX_VERSION_CODE >= 0x020300
+	wait_queue_head_t wait_stats;  /* to wait for the STATS indication */
+#else
+	struct wait_queue* wait_stats;  /* to wait for the STATS indication */
+#endif
+	u32 mbox;			/* -> mailbox */
+	void (*isr)(struct cycx* card);	/* interrupt service routine */
+	int (*exec)(struct cycx* card, void* u_cmd, void* u_data);
+	union {
+#ifdef CONFIG_CYCLOMX_X25
+		struct { /* X.25 specific data */
+			u32 lo_pvc;
+			u32 hi_pvc;
+			u32 lo_svc;
+			u32 hi_svc;
+			TX25Stats stats;
+			unsigned critical;	/* critical section flag */
+			u32 connection_keys;
+		} x;
+#endif
+	} u;
+} cycx_t;
+
+/* Public Functions */
+void cyclomx_open      (cycx_t* card);			/* cycx_main.c */
+void cyclomx_close     (cycx_t* card);			/* cycx_main.c */
+void cyclomx_set_state (cycx_t* card, int state);	/* cycx_main.c */
+
+#ifdef CONFIG_CYCLOMX_X25
+int cyx_init (cycx_t* card, wandev_conf_t* conf);	/* cycx_x25.c */
+#endif
+#endif	/* __KERNEL__ */
+#endif	/* _CYCLOMX_H */
diff -u --recursive --new-file v2.3.5/linux/include/linux/cycx_cfm.h linux/include/linux/cycx_cfm.h
--- v2.3.5/linux/include/linux/cycx_cfm.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/cycx_cfm.h	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,81 @@
+/*
+* cycx_cfm.h	CYCLOM X Multiprotocol WAN Link Driver.
+*		Definitions for the CYCLOM X Firmware Module (CFM).
+*
+* Author:	Arnaldo Carvalho de Melo <ac...@conectiva.com.br>
+* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Based on sdlasfm.h by Gene Kozin <7460...@compuserve.com>
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* Aug 08, 1998	Arnaldo		Initial version.
+*/
+#ifndef	_CYCX_CFM_H
+#define	_CYCX_CFM_H
+
+/* Defines */
+
+#define	CFM_VERSION	2
+#define	CFM_SIGNATURE	"CFM - Cyclades CYCX Firmware Module"
+
+/* min/max */
+#define	CFM_IMAGE_SIZE	0x20000	/* max size of CYCX code image file */
+#define	CFM_DESCR_LEN	256	/* max length of description string */
+#define	CFM_MAX_CYCX	1	/* max number of compatible adapters */
+#define	CFM_LOAD_BUFSZ	0x400	/* buffer size for reset code (buffer_load) */
+
+/* Firmware Commands */
+#define GEN_POWER_ON	0x1280
+
+#define GEN_SET_SEG	0x1401	/* boot segment setting.        */
+#define GEN_BOOT_DAT	0x1402	/* boot data.                   */
+#define GEN_START	0x1403	/* board start.                 */
+#define GEN_DEFPAR	0x1404	/* buffer length for boot.      */
+
+/* Adapter types */
+#define CYCX_2X		2
+#define CYCX_8X		8
+#define CYCX_16X	16
+
+#define	CFID_X25_2X	5200
+
+
+/* Data Types */
+
+typedef struct	cfm_info		/* firmware module information */
+{
+	unsigned short	codeid;		/* firmware ID */
+	unsigned short	version;	/* firmaware version number */
+	unsigned short	adapter[CFM_MAX_CYCX]; /* compatible adapter types */
+	unsigned long	memsize;	/* minimum memory size */
+	unsigned short	reserved[2];	/* reserved */
+	unsigned short	startoffs;	/* entry point offset */
+	unsigned short	winoffs;	/* dual-port memory window offset */
+	unsigned short	codeoffs;	/* code load offset */
+	unsigned long	codesize;	/* code size */
+	unsigned short	dataoffs;	/* configuration data load offset */
+	unsigned long	datasize;	/* configuration data size */
+} cfm_info_t;
+
+typedef struct cfm			/* CYCX firmware file structire */
+{
+	char		signature[80];	/* CFM file signature */
+	unsigned short	version;	/* file format version */
+	unsigned short	checksum;	/* info + image */
+	unsigned short	reserved[6];	/* reserved */
+	char		descr[CFM_DESCR_LEN]; /* description string */
+	cfm_info_t	info;		/* firmware module info */
+	unsigned char	image[1];	/* code image (variable size) */
+} cfm_t;
+
+typedef struct cycx_header_s {
+	unsigned long  reset_size;
+	unsigned long  data_size;
+	unsigned long  code_size;
+} cycx_header_t;
+
+#endif	/* _CYCX_CFM_H */
diff -u --recursive --new-file v2.3.5/linux/include/linux/cycx_drv.h linux/include/linux/cycx_drv.h
--- v2.3.5/linux/include/linux/cycx_drv.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/cycx_drv.h	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,66 @@
+/*
+* cycx_drv.h	CYCX Support Module.  Kernel API Definitions.
+*
+* Author:	Arnaldo Carvalho de Melo <ac...@conectiva.com.br>
+* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Based on sdladrv.h by Gene Kozin <ge...@compuserve.com>
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* 1999/01/03	acme		more judicious use of data types...
+*				uclong, ucchar, etc deleted, the u8, u16, u32
+*				types are the portable way to go.
+* 1999/01/03	acme		judicious use of data types... u16, u32, etc
+* Dec 26, 1998	Arnaldo 	FIXED_BUFFERS, CONF_OFFSET,
+*                               removal of cy_read{bwl}
+* Aug 08, 1998	Arnaldo 	Initial version.
+*/
+#ifndef	_CYCX_DRV_H
+#define	_CYCX_DRV_H
+
+#define	CYCX_WINDOWSIZE	0x4000	/* default dual-port memory window size */
+#define	GEN_CYCX_INTR	0x02
+#define	RST_ENABLE	0x04
+#define	START_CPU	0x06
+#define	RST_DISABLE	0x08
+#define	FIXED_BUFFERS	0x08
+#define	TEST_PATTERN	0xaa55
+#define	CMD_OFFSET	0x20
+#define CONF_OFFSET     0x0380
+#define	RESET_OFFSET	0x3c00	/* For reset file load */
+#define	DATA_OFFSET	0x0100	/* For code and data files load */
+#define	START_OFFSET	0x3ff0	/* 80186 starts here */
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/* Data Structures */
+/* Adapter hardware configuration. Pointer to this structure is passed to all
+ * APIs.  */
+typedef struct cycxhw {
+	u32 type;		/* adapter type */
+	u32 fwid;		/* firmware ID */
+	int irq;		/* interrupt request level */
+	u32 dpmbase;		/* dual-port memory base */
+	u32 dpmsize;		/* dual-port memory size */
+	u32 pclk;		/* CPU clock rate, kHz */
+	u32 memory;		/* memory size */
+	u32 reserved[5];
+} cycxhw_t;
+
+/* Function Prototypes */
+extern int cycx_setup  (cycxhw_t* hw, void* sfm, u32 len);
+extern int cycx_down   (cycxhw_t* hw);
+extern int cycx_inten  (cycxhw_t* hw);
+extern int cycx_intde  (cycxhw_t* hw);
+extern int cycx_intack (cycxhw_t* hw);
+extern int cycx_intr   (cycxhw_t* hw);
+extern int cycx_peek   (cycxhw_t* hw, u32 addr, void* buf, u32 len);
+extern int cycx_poke   (cycxhw_t* hw, u32 addr, void* buf, u32 len);
+extern int cycx_exec   (u32 addr);
+#endif	/* _CYCX_DRV_H */
diff -u --recursive --new-file v2.3.5/linux/include/linux/cycx_x25.h linux/include/linux/cycx_x25.h
--- v2.3.5/linux/include/linux/cycx_x25.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/cycx_x25.h	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,103 @@
+/*
+* cycx_x25.h	Cyclom X.25 firmware API definitions.
+*
+* Author:	Arnaldo Carvalho de Melo <ac...@conectiva.com.br>
+*
+* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Based on sdla_x25.h by Gene Kozin <7460...@compuserve.com>
+*
+*		This program is free software; you can redistribute it and/or
+*		modify it under the terms of the GNU General Public License
+*		as published by the Free Software Foundation; either version
+*		2 of the License, or (at your option) any later version.
+* ============================================================================
+* 1999/01/03	acme		judicious use of data types
+*
+* 1999/01/02	acme		#define X25_ACK_N3	0x4411
+* Dec 28, 1998	Arnaldo		cleanup: lot'o'things removed
+*					 commands listed,
+*					 TX25Cmd & TX25Config structs
+*					 typedef'ed
+*/
+#ifndef	_CYCX_X25_H
+#define	_CYCX_X25_H
+
+#ifndef PACKED
+#define PACKED __attribute__((packed))
+#endif 
+
+/* X.25 shared memory layout. */
+#define	X25_MBOX_OFFS	0x300	/* general mailbox block */
+#define	X25_RXMBOX_OFFS	0x340	/* receive mailbox */
+
+/* DATA STRUCTURES */
+/* X.25 Command Block. */
+typedef struct X25Cmd
+{
+	u16 command PACKED;
+	u16 link    PACKED; /* values: 0 or 1 */
+	u16 len     PACKED; /* values: 0 thru 0x205 (517) */
+	u32 buf     PACKED;
+} TX25Cmd;
+
+/* Defines for the 'command' field. */
+#define X25_CONNECT_REQUEST             0x4401
+#define X25_CONNECT_RESPONSE            0x4402
+#define X25_DISCONNECT_REQUEST          0x4403
+#define X25_DISCONNECT_RESPONSE         0x4404
+#define X25_DATA_REQUEST                0x4405
+#define X25_ACK_TO_VC			0x4406
+#define X25_INTERRUPT_RESPONSE          0x4407
+#define X25_CONFIG                      0x4408
+#define X25_CONNECT_INDICATION          0x4409
+#define X25_CONNECT_CONFIRM             0x440A
+#define X25_DISCONNECT_INDICATION       0x440B
+#define X25_DISCONNECT_CONFIRM          0x440C
+#define X25_DATA_INDICATION             0x440E
+#define X25_INTERRUPT_INDICATION        0x440F
+#define X25_ACK_FROM_VC			0x4410
+#define X25_ACK_N3			0x4411
+#define X25_CONNECT_COLLISION           0x4413
+#define X25_N3WIN                       0x4414
+#define X25_LINE_ON                     0x4415
+#define X25_LINE_OFF                    0x4416
+#define X25_RESET_REQUEST               0x4417
+#define X25_LOG                         0x4500
+#define X25_STATISTIC                   0x4600
+#define X25_TRACE                       0x4700
+#define X25_N2TRACEXC                   0x4702
+#define X25_N3TRACEXC                   0x4703
+
+typedef struct X25Config {
+	u8  link	PACKED; /* link number */
+	u8  speed	PACKED; /* line speed */
+	u8  clock	PACKED; /* internal/external */
+	u8  n2		PACKED; /* # of level 2 retransm.(values: 1 thru FF) */
+	u8  n2win	PACKED; /* level 2 window (values: 1 thru 7) */
+	u8  n3win	PACKED; /* level 3 window (values: 1 thru 7) */
+	u8  nvc		PACKED; /* # of logical channels (values: 1 thru 64) */
+	u8  pktlen	PACKED; /* level 3 packet lenght - log base 2 of size */
+	u8  locaddr	PACKED; /* my address */
+	u8  remaddr	PACKED; /* remote address */
+	u16 t1		PACKED;	/* time, in seconds */
+	u16 t2		PACKED;	/* time, in seconds */
+	u8  t21		PACKED;	/* time, in seconds */
+	u8  npvc	PACKED;	/* # of permanent virt. circuits (1 thru nvc) */
+	u8  t23		PACKED;	/* time, in seconds */
+	u8  flags	PACKED;	/* see dosx25.doc, in portuguese, for details */
+} TX25Config;
+
+typedef struct X25Stats {
+	u16 rx_crc_errors	PACKED;
+	u16 rx_over_errors	PACKED;
+	u16 n2_tx_frames 	PACKED;
+	u16 n2_rx_frames 	PACKED;
+	u16 tx_timeouts 	PACKED;
+	u16 rx_timeouts 	PACKED;
+	u16 n3_tx_packets 	PACKED;
+	u16 n3_rx_packets 	PACKED;
+	u16 tx_aborts	 	PACKED;
+	u16 rx_aborts	 	PACKED;
+} TX25Stats;
+#endif	/* _CYCX_X25_H */
diff -u --recursive --new-file v2.3.5/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.3.5/linux/include/linux/dcache.h	Sat May  8 17:56:37 1999
+++ linux/include/linux/dcache.h	Tue Jun  8 10:47:58 1999
@@ -12,8 +12,6 @@
X  * with heavy changes by Linus Torvalds
X  */
X 
-#define D_MAXLEN 1024
-
X #define IS_ROOT(x) ((x) == (x)->d_parent)
X 
X /*
@@ -132,7 +130,7 @@
X extern void d_delete(struct dentry *);
X 
X /* allocate/de-allocate */
-extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
+extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
X extern void prune_dcache(int);
X extern void shrink_dcache_sb(struct super_block *);
X extern void shrink_dcache_parent(struct dentry *);
@@ -147,7 +145,7 @@
X extern void free_inode_memory(int);	/* defined in fs/inode.c */
X 
X /* only used at mount-time */
-extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root);
+extern struct dentry * d_alloc_root(struct inode *);
X 
X /* test whether root is busy without destroying dcache */
X extern int is_root_busy(struct dentry *);
@@ -155,7 +153,7 @@
X /*
X  * This adds the entry to the hash queues.
X  */
-extern void d_rehash(struct dentry * entry);
+extern void d_rehash(struct dentry *);
X /*
X  * This adds the entry to the hash queues and initializes "d_inode".
X  * The entry was actually filled in earlier during "d_alloc()"
@@ -167,17 +165,16 @@
X }
X 
X /* used for rename() and baskets */
-extern void d_move(struct dentry * entry, struct dentry * newdentry);
+extern void d_move(struct dentry *, struct dentry *);
X 
X /* appendix may either be NULL or be used for transname suffixes */
-extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name);
+extern struct dentry * d_lookup(struct dentry *, struct qstr *);
X 
X /* validate "insecure" dentry pointer */
-extern int d_validate(struct dentry *dentry, struct dentry *dparent,
-		      unsigned int hash, unsigned int len);
+extern int d_validate(struct dentry *, struct dentry *, unsigned int, unsigned int);
X 
X /* write full pathname into buffer and return start of pathname */
-extern char * d_path(struct dentry * entry, char * buf, int buflen);
+extern char * d_path(struct dentry *, char *, int);
X 
X /* Allocation counts.. */
X static __inline__ struct dentry * dget(struct dentry *dentry)
diff -u --recursive --new-file v2.3.5/linux/include/linux/file.h linux/include/linux/file.h
--- v2.3.5/linux/include/linux/file.h	Sat Jan  9 19:16:44 1999
+++ linux/include/linux/file.h	Tue Jun  8 10:47:58 1999
@@ -44,7 +44,7 @@
X /*
X  * Install a file pointer in the fd array.
X  */
-extern inline void fd_install(unsigned int fd, struct file *file)
+extern inline void fd_install(unsigned int fd, struct file * file)
X {
X 	current->files->fd[fd] = file;
X }
@@ -65,7 +65,7 @@
X  * I suspect there are many other similar "optimizations" across the
X  * kernel...
X  */
-extern void fput(struct file *file); 
-extern void put_filp(struct file *file);
+extern void fput(struct file *); 
+extern void put_filp(struct file *);
X 
-#endif
+#endif /* __LINUX_FILE_H */
diff -u --recursive --new-file v2.3.5/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.5/linux/include/linux/fs.h	Wed Jun  2 14:44:39 1999
+++ linux/include/linux/fs.h	Tue Jun  8 23:03:41 1999
@@ -103,7 +103,8 @@
X /*
X  * Flags that can be altered by MS_REMOUNT
X  */
-#define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
+#define MS_RMT_MASK	(MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|\
+			MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
X 
X /*
X  * Magic mount flag number. Has to be or-ed to the flag values.
@@ -112,7 +113,7 @@
X #define MS_MGC_MSK 0xffff0000	/* magic flag number mask */
X 
X /*
- * Note that read-only etc flags are inode-specific: setting some file-system
+ * Note that nosuid etc flags are inode-specific: setting some file-system
X  * flags just means all the inodes inherit those flags by default. It might be
X  * possible to override it selectively if you really wanted to with some
X  * ioctl() that is not currently implemented.
@@ -171,9 +172,8 @@
X 
X #include <asm/semaphore.h>
X #include <asm/byteorder.h>
-#include <asm/bitops.h>
X 
-extern void update_atime (struct inode *inode);
+extern void update_atime (struct inode *);
X #define UPDATE_ATIME(inode) update_atime (inode)
X 
X extern void buffer_init(unsigned long);
@@ -233,8 +233,7 @@
X };
X 
X typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
-void init_buffer(struct buffer_head *bh, kdev_t dev, int block,
-		 bh_end_io_t *handler, void *dev_id);
+void init_buffer(struct buffer_head *, kdev_t, int, bh_end_io_t *, void *);
X 
X static inline int buffer_uptodate(struct buffer_head * bh)
X {
@@ -480,19 +479,17 @@
X 
X #include <linux/fcntl.h>
X 
-extern int fcntl_getlk(unsigned int fd, struct flock *l);
-extern int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l);
+extern int fcntl_getlk(unsigned int, struct flock *);
+extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
X 
X /* fs/locks.c */
-extern void locks_remove_posix(struct file *, fl_owner_t id);
+extern void locks_remove_posix(struct file *, fl_owner_t);
X extern void locks_remove_flock(struct file *);
X extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
X extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
X extern void posix_block_lock(struct file_lock *, struct file_lock *);
X extern void posix_unblock_lock(struct file_lock *);
X 
-#include <linux/stat.h>
-
X struct fasync_struct {
X 	int    magic;
X 	int    fa_fd;
@@ -667,10 +664,8 @@
X #define FLOCK_VERIFY_READ  1
X #define FLOCK_VERIFY_WRITE 2
X 
-extern int locks_mandatory_locked(struct inode *inode);
-extern int locks_mandatory_area(int read_write, struct inode *inode,
-				struct file *filp, loff_t offset,
-				size_t count);
+extern int locks_mandatory_locked(struct inode *);
+extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
X 
X extern inline int locks_verify_locked(struct inode *inode)
X {
@@ -709,35 +704,35 @@
X extern struct file *filp_open(const char *, int, int);
X extern int filp_close(struct file *, fl_owner_t id);
X 
-extern char * getname(const char * filename);
+extern char * getname(const char *);
X #define __getname()	((char *) __get_free_page(GFP_KERNEL))
X #define putname(name)	free_page((unsigned long)(name))
X 
-extern void kill_fasync(struct fasync_struct *fa, int sig);
+extern void kill_fasync(struct fasync_struct *, int);
X extern int register_blkdev(unsigned int, const char *, struct file_operations *);
-extern int unregister_blkdev(unsigned int major, const char * name);
-extern int blkdev_open(struct inode * inode, struct file * filp);
-extern int blkdev_release (struct inode * inode);
+extern int unregister_blkdev(unsigned int, const char *);
+extern int blkdev_open(struct inode *, struct file *);
+extern int blkdev_release (struct inode *);
X extern struct file_operations def_blk_fops;
X extern struct inode_operations blkdev_inode_operations;
X 
X /* fs/devices.c */
X extern int register_chrdev(unsigned int, const char *, struct file_operations *);
-extern int unregister_chrdev(unsigned int major, const char * name);
-extern int chrdev_open(struct inode * inode, struct file * filp);
+extern int unregister_chrdev(unsigned int, const char *);
+extern int chrdev_open(struct inode *, struct file *);
X extern struct file_operations def_chr_fops;
X extern struct inode_operations chrdev_inode_operations;
-extern char * bdevname(kdev_t dev);
-extern char * cdevname(kdev_t dev);
-extern char * kdevname(kdev_t dev);
+extern char * bdevname(kdev_t);
+extern char * cdevname(kdev_t);
+extern char * kdevname(kdev_t);
X extern void init_special_inode(struct inode *, umode_t, int);
X 
-extern void init_fifo(struct inode * inode);
+extern void init_fifo(struct inode *);
X extern struct inode_operations fifo_inode_operations;
X 
X /* Invalid inode operations -- fs/bad_inode.c */
-extern void make_bad_inode(struct inode * inode);
-extern int is_bad_inode(struct inode * inode);
+extern void make_bad_inode(struct inode *);
+extern int is_bad_inode(struct inode *);
X 
X extern struct file_operations connecting_fifo_fops;
X extern struct file_operations read_fifo_fops;
@@ -747,15 +742,15 @@
X extern struct file_operations write_pipe_fops;
X extern struct file_operations rdwr_pipe_fops;
X 
-extern struct file_system_type *get_fs_type(const char *name);
+extern struct file_system_type *get_fs_type(const char *);
X 
X extern int fs_may_remount_ro(struct super_block *);
-extern int fs_may_mount(kdev_t dev);
+extern int fs_may_mount(kdev_t);
X 
X extern struct file *inuse_filps;
X 
-extern void refile_buffer(struct buffer_head * buf);
-extern void set_writetime(struct buffer_head * buf, int flag);
+extern void refile_buffer(struct buffer_head *);
+extern void set_writetime(struct buffer_head *, int);
X extern int try_to_free_buffers(struct page *);
X 
X extern int nr_buffers;
@@ -767,7 +762,7 @@
X #define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write */
X #define NR_LIST		3
X 
-void mark_buffer_uptodate(struct buffer_head * bh, int on);
+void mark_buffer_uptodate(struct buffer_head *, int);
X 
X extern inline void mark_buffer_clean(struct buffer_head * bh)
X {
@@ -786,23 +781,23 @@
X 	}
X }
X 
-extern int check_disk_change(kdev_t dev);
-extern int invalidate_inodes(struct super_block * sb);
+extern int check_disk_change(kdev_t);
+extern int invalidate_inodes(struct super_block *);
X extern void invalidate_inode_pages(struct inode *);
-extern void invalidate_buffers(kdev_t dev);
-extern int floppy_is_wp(int minor);
-extern void sync_inodes(kdev_t dev);
-extern void write_inode_now(struct inode *inode);
-extern void sync_dev(kdev_t dev);
-extern int fsync_dev(kdev_t dev);
-extern void sync_supers(kdev_t dev);
-extern int bmap(struct inode * inode,int block);
+extern void invalidate_buffers(kdev_t);
+extern int floppy_is_wp(int);
+extern void sync_inodes(kdev_t);
+extern void write_inode_now(struct inode *);
+extern void sync_dev(kdev_t);
+extern int fsync_dev(kdev_t);
+extern void sync_supers(kdev_t);
+extern int bmap(struct inode *, int);
X extern int notify_change(struct dentry *, struct iattr *);
-extern int permission(struct inode * inode,int mask);
-extern int get_write_access(struct inode *inode);
-extern void put_write_access(struct inode *inode);
-extern struct dentry * open_namei(const char * pathname, int flag, int mode);
-extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
+extern int permission(struct inode *, int);
+extern int get_write_access(struct inode *);
+extern void put_write_access(struct inode *);
+extern struct dentry * open_namei(const char *, int, int);
+extern struct dentry * do_mknod(const char *, int, dev_t);
X extern int do_pipe(int *);
X 
X /* fs/dcache.c -- generic fs support functions */
@@ -840,7 +835,7 @@
X #define lnamei(pathname)	__namei(pathname, 0)
X 
X extern void iput(struct inode *);
-extern struct inode * igrab(struct inode *inode);
+extern struct inode * igrab(struct inode *);
X extern ino_t iunique(struct super_block *, ino_t);
X extern struct inode * iget(struct super_block *, unsigned long);
X extern void clear_inode(struct inode *);
@@ -851,7 +846,7 @@
X extern struct file * get_empty_filp(void);
X extern struct buffer_head * get_hash_table(kdev_t, int, int);
X extern struct buffer_head * getblk(kdev_t, int, int);
-extern struct buffer_head * find_buffer(kdev_t dev, int block, int size);
+extern struct buffer_head * find_buffer(kdev_t, int, int);
X extern void ll_rw_block(int, int, struct buffer_head * bh[]);
X extern int is_read_only(kdev_t);
X extern void __brelse(struct buffer_head *);
@@ -860,17 +855,16 @@
X 	if (buf)
X 		__brelse(buf);
X }
-extern void __bforget(struct buffer_head *buf);
+extern void __bforget(struct buffer_head *);
X extern inline void bforget(struct buffer_head *buf)
X {
X 	if (buf)
X 		__bforget(buf);
X }
-extern void set_blocksize(kdev_t dev, int size);
-extern unsigned int get_hardblocksize(kdev_t dev);
-extern struct buffer_head * bread(kdev_t dev, int block, int size);
-extern struct buffer_head * breada(kdev_t dev,int block, int size, 
-				   unsigned int pos, unsigned int filesize);
+extern void set_blocksize(kdev_t, int);
+extern unsigned int get_hardblocksize(kdev_t);
+extern struct buffer_head * bread(kdev_t, int, int);
+extern struct buffer_head * breada(kdev_t, int, int, unsigned int, unsigned int);
X 
X extern int brw_page(int, struct page *, kdev_t, int [], int, int);
X 
@@ -879,12 +873,12 @@
X extern int generic_readpage(struct file *, struct page *);
X extern int generic_file_mmap(struct file *, struct vm_area_struct *);
X extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
-extern ssize_t generic_file_write(struct file *, const char*, size_t, loff_t *, writepage_t);
+extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *, writepage_t);
X 
-extern struct super_block *get_super(kdev_t dev);
-extern void put_super(kdev_t dev);
-unsigned long generate_cluster(kdev_t dev, int b[], int size);
-unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size);
+extern struct super_block *get_super(kdev_t);
+extern void put_super(kdev_t);
+unsigned long generate_cluster(kdev_t, int b[], int);
+unsigned long generate_cluster_swab32(kdev_t, int b[], int);
X extern kdev_t ROOT_DEV;
X 
X extern void show_buffers(void);
@@ -892,7 +886,7 @@
X 
X #ifdef CONFIG_BLK_DEV_INITRD
X extern kdev_t real_root_dev;
-extern int change_root(kdev_t new_root_dev,const char *put_old);
+extern int change_root(kdev_t, const char *);
X #endif
X 
X extern ssize_t char_read(struct file *, char *, size_t, loff_t *);
@@ -902,8 +896,8 @@
X extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
X extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
X 
-extern int block_fsync(struct file *, struct dentry *dir);
-extern int file_fsync(struct file *, struct dentry *dir);
+extern int block_fsync(struct file *, struct dentry *);
+extern int file_fsync(struct file *, struct dentry *);
X 
X extern int inode_change_ok(struct inode *, struct iattr *);
X extern void inode_setattr(struct inode *, struct iattr *);
@@ -914,4 +908,4 @@
X 
X #endif /* __KERNEL__ */
X 
-#endif
+#endif /* _LINUX_FS_H */
diff -u --recursive --new-file v2.3.5/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.3.5/linux/include/linux/i2o.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/i2o.h	Wed Jun  2 14:40:22 1999
@@ -0,0 +1,588 @@
+#ifndef _I2O_H
+#define _I2O_H
+
+/*
+ *	Tunable parameters first
+ */
+
+/* How many different OSM's are we allowing */ 
+#define MAX_I2O_MODULES		64
+/* How many controllers are we allowing */
+#define MAX_I2O_CONTROLLERS	32
+
+
+#ifdef __KERNEL__   /* ioctl stuff only thing exported to users */
+
+/*
+ *	I2O Interface Objects
+ */
+
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+
+/*
+ * message structures
+ */
+
+#define    TID_SZ                                  12
+#define    FUNCTION_SZ                             8
+
+struct i2o_message
+{
+	u32	version_size;
+	u32	function_addr;
+	u32	initiator_context;
+	/* List follows */
+};
+
+
+/*
+ *	Each I2O device entity has one or more of these. There is one
+ *	per device. *FIXME* how to handle multiple types on one unit.
+ */
+ 
+struct i2o_device
+{
+	int class;		/* Block, Net, SCSI etc (from spec) */
+	int subclass;		/* eth, fddi, tr etc (from spec)   */
+	int id;			/* I2O ID assigned by the controller */
+	int parent;		/* Parent device */
+	int flags;		/* Control flags */
+	int i2oversion;		/* I2O version supported. Actually there
+				 * should be high and low version */
+	struct proc_dir_entry* proc_entry;	/* /proc dir */
+	struct i2o_driver *owner;		/* Owning device */
+	struct i2o_controller *controller;	/* Controlling IOP */
+	struct i2o_device *next;	/* Chain */
+	char dev_name[8];		/* linux /dev name if available */
+};
+
+/*
+ *	Resource data for each PCI I2O controller
+ */	 	
+
+struct i2o_pci
+{
+	int irq;
+};
+
+/*
+ *	Each I2O controller has one of these objects
+ */
+ 
+struct i2o_controller
+{
+	char name[16];
+	int unit;
+	int status;				/* I2O status */
+	int i2oversion;
+	int type;
+#define I2O_TYPE_PCI		0x01		/* PCI I2O controller */	
+	struct notifier_block *event_notifer;	/* Events */
+	atomic_t users;
+	struct i2o_device *devices;		/* I2O device chain */
+	struct i2o_controller *next;		/* Controller chain */
+	volatile u32 *post_port;		/* Messaging ports */
+	volatile u32 *reply_port;
+	volatile u32 *irq_mask;			/* Interrupt port */
+	u32 mem_offset;				/* MFA offset */
+	u32 mem_phys;				/* MFA physical */
+	u32 priv_mem;
+	u32 priv_mem_size;
+	u32 priv_io;
+	u32 priv_io_size;
+
+	struct proc_dir_entry* proc_entry;	/* /proc dir */
+
+	union
+	{					/* Bus information */
+		struct i2o_pci pci;
+	} bus;
+	void (*destructor)(struct i2o_controller *);			/* Bus specific destructor */
+	int (*bind)(struct i2o_controller *, struct i2o_device *);	/* Bus specific attach/detach */
+	int (*unbind)(struct i2o_controller *, struct i2o_device *);
+	void *page_frame;		/* Message buffers */
+	int inbound_size;		/* Inbound queue size */
+};
+
+struct i2o_handler
+{
+	void (*reply)(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);
+	char *name;
+	int context;		/* Low 8 bits of the transaction info */
+	/* User data follows */
+};
+
+/*
+ *	Messenger inlines
+ */
+
+extern inline u32 I2O_POST_READ32(struct i2o_controller *c)
+{
+	return *c->post_port;
+}
+
+extern inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
+{
+	*c->post_port = Val;
+}
+
+
+extern inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
+{
+	return *c->reply_port;
+}
+
+extern inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
+{
+	*c->reply_port= Val;
+}
+ 
+
+extern inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
+{
+	return *c->irq_mask;
+}
+
+extern inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
+{
+	*c->irq_mask = Val;
+}
+
+
+extern inline void i2o_post_message(struct i2o_controller *c, u32 m)
+{
+	/* The second line isnt spurious - thats forcing PCI posting */
+	I2O_POST_WRITE32(c,m);
+	(void) I2O_IRQ_READ32(c);
+}
+
+extern inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
+{
+	I2O_REPLY_WRITE32(c,m);
+}
+
+
+struct i2o_controller *i2o_controller_chain;
+
+extern int i2o_quiesce_controller(struct i2o_controller *);
+extern int i2o_clear_controller(struct i2o_controller *);
+extern int i2o_install_controller(struct i2o_controller *);
+extern int i2o_delete_controller(struct i2o_controller *);
+extern int i2o_activate_controller(struct i2o_controller *);
+extern void i2o_unlock_controller(struct i2o_controller *);
+extern struct i2o_controller *i2o_find_controller(int);
+extern int i2o_num_controllers;
+
+extern int i2o_install_handler(struct i2o_handler *);
+extern int i2o_remove_handler(struct i2o_handler *);
+
+extern int i2o_install_device(struct i2o_controller *, struct i2o_device *);
+extern int i2o_delete_device(struct i2o_device *);
+extern int i2o_claim_device(struct i2o_device *, struct i2o_driver *);
+extern int i2o_release_device(struct i2o_device *);
+
+extern int i2o_post_this(struct i2o_controller *, int, u32 *, int);
+extern int i2o_post_wait(struct i2o_controller *, int, u32 *, int, int *, int);
+extern int i2o_issue_claim(struct i2o_controller *, int, int, int, int *);
+extern int i2o_query_scalar(struct i2o_controller *, int, int, int, int, void *,
+			    int, int *);
+extern int i2o_params_set(struct i2o_controller *c, int, int, int, int, void *,
+			  int, int *);
+
+extern void i2o_run_queue(struct i2o_controller *);
+
+extern void i2o_report_status(const char *, const char *, u8, u8, u16);
+extern void report_common_status(u8);
+extern void report_lan_dsc(u16);
+
+extern u32 i2o_wait_message(struct i2o_controller *, char *);
+
+extern const char *i2o_get_class_name(int);
+
+
+/*
+ *	I2O classes / subclasses
+ */
+
+/*  Class ID and Code Assignments
+ *  (LCT.ClassID.Version field)
+ */
+#define    I2O_CLASS_VERSION_10                        0x00
+#define    I2O_CLASS_VERSION_11                        0x01
+
+/*  Class code names
+ *  (from v1.5 Table 6-1 Class Code Assignments.)
+ */
+ 
+#define    I2O_CLASS_EXECUTIVE                         0x000
+#define    I2O_CLASS_DDM                               0x001
+#define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
+#define    I2O_CLASS_SEQUENTIAL_STORAGE                0x011
+#define    I2O_CLASS_LAN                               0x020
+#define    I2O_CLASS_WAN                               0x030
+#define    I2O_CLASS_FIBRE_CHANNEL_PORT                0x040
+#define    I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL          0x041
+#define    I2O_CLASS_SCSI_PERIPHERAL                   0x051
+#define    I2O_CLASS_ATE_PORT                          0x060
+#define    I2O_CLASS_ATE_PERIPHERAL                    0x061
+#define    I2O_CLASS_FLOPPY_CONTROLLER                 0x070
+#define    I2O_CLASS_FLOPPY_DEVICE                     0x071
+#define    I2O_CLASS_BUS_ADAPTER_PORT                  0x080
+#define    I2O_CLASS_PEER_TRANSPORT_AGENT              0x090
+#define    I2O_CLASS_PEER_TRANSPORT                    0x091
+
+/*  Rest of 0x092 - 0x09f reserved for peer-to-peer classes
+ */
+ 
+#define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
+
+/*  Subclasses
+ */
+
+#define    I2O_SUBCLASS_i960                           0x001
+#define    I2O_SUBCLASS_HDM                            0x020
+#define    I2O_SUBCLASS_ISM                            0x021
+ 
+/* Operation functions */
+
+#define I2O_PARAMS_FIELD_GET	0x0001
+#define I2O_PARAMS_LIST_GET	0x0002
+#define I2O_PARAMS_MORE_GET	0x0003
+#define I2O_PARAMS_SIZE_GET	0x0004
+#define I2O_PARAMS_TABLE_GET	0x0005
+#define I2O_PARAMS_FIELD_SET	0x0006
+#define I2O_PARAMS_LIST_SET	0x0007
+#define I2O_PARAMS_ROW_ADD	0x0008
+#define I2O_PARAMS_ROW_DELETE	0x0009
+#define I2O_PARAMS_TABLE_CLEAR	0x000A
+
+/*
+ *	I2O serial number conventions / formats
+ *	(circa v1.5)
+ */
+
+#define    I2O_SNFORMAT_UNKNOWN                        0
+#define    I2O_SNFORMAT_BINARY                         1
+#define    I2O_SNFORMAT_ASCII                          2
+#define    I2O_SNFORMAT_UNICODE                        3
+#define    I2O_SNFORMAT_LAN48_MAC                      4
+#define    I2O_SNFORMAT_WAN                            5
+
+/* Plus new in v2.0 (Yellowstone pdf doc)
+ */
+
+#define    I2O_SNFORMAT_LAN64_MAC                      6
+#define    I2O_SNFORMAT_DDM                            7
+#define    I2O_SNFORMAT_IEEE_REG64                     8
+#define    I2O_SNFORMAT_IEEE_REG128                    9
+#define    I2O_SNFORMAT_UNKNOWN2                       0xff
+
+
+/*
+ *	"Special" TID assignments
+ */
+#define    I2O_IOP_TID                                 0
+#define    I2O_HOST_TID                                1
+
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define TRL_SINGLE_FIXED_LENGTH		0x00
+#define TRL_SINGLE_VARIABLE_LENGTH	0x40
+#define TRL_MULTIPLE_FIXED_LENGTH	0x80
+
+/* LAN Class specific functions */
+
+#define    LAN_PACKET_SEND			0x3B
+#define    LAN_SDU_SEND				0x3D
+#define    LAN_RECEIVE_POST			0x3E
+#define    LAN_RESET				0x35
+#define    LAN_SUSPEND				0x37
+
+/*
+ *	Messaging API values
+ */
+ 
+#define	I2O_CMD_ADAPTER_ASSIGN		0xB3
+#define	I2O_CMD_ADAPTER_READ		0xB2
+#define	I2O_CMD_ADAPTER_RELEASE		0xB5
+#define	I2O_CMD_BIOS_INFO_SET		0xA5
+#define	I2O_CMD_BOOT_DEVICE_SET		0xA7
+#define	I2O_CMD_CONFIG_VALIDATE		0xBB
+#define	I2O_CMD_CONN_SETUP		0xCA
+#define	I2O_CMD_DDM_DESTROY		0xB1
+#define	I2O_CMD_DDM_ENABLE		0xD5
+#define	I2O_CMD_DDM_QUIESCE		0xC7
+#define	I2O_CMD_DDM_RESET		0xD9
+#define	I2O_CMD_DDM_SUSPEND		0xAF
+#define	I2O_CMD_DEVICE_ASSIGN		0xB7
+#define	I2O_CMD_DEVICE_RELEASE		0xB9
+#define	I2O_CMD_HRT_GET			0xA8
+#define	I2O_CMD_ADAPTER_CLEAR		0xBE
+#define	I2O_CMD_ADAPTER_CONNECT		0xC9
+#define	I2O_CMD_ADAPTER_RESET		0xBD
+#define	I2O_CMD_LCT_NOTIFY		0xA2
+#define	I2O_CMD_OUTBOUND_INIT		0xA1
+#define	I2O_CMD_PATH_ENABLE		0xD3
+#define	I2O_CMD_PATH_QUIESCE		0xC5
+#define	I2O_CMD_PATH_RESET		0xD7
+#define	I2O_CMD_STATIC_MF_CREATE	0xDD
+#define	I2O_CMD_STATIC_MF_RELEASE	0xDF
+#define	I2O_CMD_STATUS_GET		0xA0
+#define	I2O_CMD_SW_DOWNLOAD		0xA9
+#define	I2O_CMD_SW_UPLOAD		0xAB
+#define	I2O_CMD_SW_REMOVE		0xAD
+#define	I2O_CMD_SYS_ENABLE		0xD1
+#define	I2O_CMD_SYS_MODIFY		0xC1
+#define	I2O_CMD_SYS_QUIESCE		0xC3
+#define	I2O_CMD_SYS_TAB_SET		0xA3
+
+#define I2O_CMD_UTIL_NOP		0x00
+#define I2O_CMD_UTIL_ABORT		0x01
+#define I2O_CMD_UTIL_CLAIM		0x09
+#define I2O_CMD_UTIL_RELEASE		0x0B
+#define I2O_CMD_UTIL_PARAMS_GET		0x06
+#define I2O_CMD_UTIL_PARAMS_SET		0x05
+#define I2O_CMD_UTIL_EVT_REGISTER	0x13
+#define I2O_CMD_UTIL_ACK		0x14
+#define I2O_CMD_UTIL_CONFIG_DIALOG	0x10
+#define I2O_CMD_UTIL_DEVICE_RESERVE	0x0D
+#define I2O_CMD_UTIL_DEVICE_RELEASE	0x0F
+#define I2O_CMD_UTIL_LOCK		0x17
+#define I2O_CMD_UTIL_LOCK_RELEASE	0x19
+#define I2O_CMD_UTIL_REPLY_FAULT_NOTIFY	0x15
+
+#define I2O_CMD_SCSI_EXEC		0x81
+#define I2O_CMD_SCSI_ABORT		0x83
+#define I2O_CMD_SCSI_BUSRESET		0x27
+
+#define I2O_CMD_BLOCK_READ		0x30
+#define I2O_CMD_BLOCK_WRITE		0x31
+#define I2O_CMD_BLOCK_CFLUSH		0x37
+#define I2O_CMD_BLOCK_MLOCK		0x49
+#define I2O_CMD_BLOCK_MUNLOCK		0x4B
+#define I2O_CMD_BLOCK_MMOUNT		0x41
+#define I2O_CMD_BLOCK_MEJECT		0x43
+
+#define I2O_PRIVATE_MSG			0xFF
+
+/*
+ *	Init Outbound Q status 
+ */
+ 
+#define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS	0x01
+#define I2O_CMD_OUTBOUND_INIT_REJECTED		0x02
+#define I2O_CMD_OUTBOUND_INIT_FAILED		0x03
+#define I2O_CMD_OUTBOUND_INIT_COMPLETE		0x04
+
+/*
+ *	I2O Get Status State values 
+ */
+
+#define	ADAPTER_STATE_INITIALIZING		0x01
+#define	ADAPTER_STATE_RESET			0x02
+#define	ADAPTER_STATE_HOLD			0x04
+#define ADAPTER_STATE_READY			0x05
+#define	ADAPTER_STATE_OPERATIONAL		0x08
+#define	ADAPTER_STATE_FAILED			0x10
+#define	ADAPTER_STATE_FAULTED			0x11
+	
+/* I2O API function return values */
+
+#define I2O_RTN_NO_ERROR			0
+#define I2O_RTN_NOT_INIT			1
+#define I2O_RTN_FREE_Q_EMPTY			2
+#define I2O_RTN_TCB_ERROR			3
+#define I2O_RTN_TRANSACTION_ERROR		4
+#define I2O_RTN_ADAPTER_ALREADY_INIT		5
+#define I2O_RTN_MALLOC_ERROR			6
+#define I2O_RTN_ADPTR_NOT_REGISTERED		7
+#define I2O_RTN_MSG_REPLY_TIMEOUT		8
+#define I2O_RTN_NO_STATUS			9
+#define I2O_RTN_NO_FIRM_VER			10
+#define	I2O_RTN_NO_LINK_SPEED			11
+
+/* Reply message status defines for all messages */
+
+#define I2O_REPLY_STATUS_SUCCESS                    	0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY                	0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     	0x02
+#define	I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER		0x03
+#define	I2O_REPLY_STATUS_ERROR_DIRTY			0x04
+#define	I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER		0x05
+#define	I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER		0x06
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY		0x08
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER	0x09
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER	0x0A
+#define	I2O_REPLY_STATUS_TRANSACTION_ERROR		0x0B
+#define	I2O_REPLY_STATUS_PROGRESS_REPORT		0x80
+
+/* Status codes and Error Information for Parameter functions */
+
+#define I2O_PARAMS_STATUS_SUCCESS		0x00
+#define I2O_PARAMS_STATUS_BAD_KEY_ABORT		0x01
+#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE   	0x02
+#define I2O_PARAMS_STATUS_BUFFER_FULL		0x03
+#define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL	0x04
+#define I2O_PARAMS_STATUS_FIELD_UNREADABLE	0x05
+#define I2O_PARAMS_STATUS_FIELD_UNWRITEABLE	0x06
+#define I2O_PARAMS_STATUS_INSUFFICIENT_FIELDS	0x07
+#define I2O_PARAMS_STATUS_INVALID_GROUP_ID	0x08
+#define I2O_PARAMS_STATUS_INVALID_OPERATION	0x09
+#define I2O_PARAMS_STATUS_NO_KEY_FIELD		0x0A
+#define I2O_PARAMS_STATUS_NO_SUCH_FIELD		0x0B
+#define I2O_PARAMS_STATUS_NON_DYNAMIC_GROUP	0x0C
+#define I2O_PARAMS_STATUS_OPERATION_ERROR	0x0D
+#define I2O_PARAMS_STATUS_SCALAR_ERROR		0x0E
+#define I2O_PARAMS_STATUS_TABLE_ERROR		0x0F
+#define I2O_PARAMS_STATUS_WRONG_GROUP_TYPE	0x10
+
+/* DetailedStatusCode defines for Executive, DDM, Util and Transaction error
+ * messages: Table 3-2 Detailed Status Codes.*/
+
+#define I2O_DSC_SUCCESS                        0x0000
+#define I2O_DSC_BAD_KEY                        0x0002
+#define I2O_DSC_TCL_ERROR                      0x0003
+#define I2O_DSC_REPLY_BUFFER_FULL              0x0004
+#define I2O_DSC_NO_SUCH_PAGE                   0x0005
+#define I2O_DSC_INSUFFICIENT_RESOURCE_SOFT     0x0006
+#define I2O_DSC_INSUFFICIENT_RESOURCE_HARD     0x0007
+#define I2O_DSC_CHAIN_BUFFER_TOO_LARGE         0x0009
+#define I2O_DSC_UNSUPPORTED_FUNCTION           0x000A
+#define I2O_DSC_DEVICE_LOCKED                  0x000B
+#define I2O_DSC_DEVICE_RESET                   0x000C
+#define I2O_DSC_INAPPROPRIATE_FUNCTION         0x000D
+#define I2O_DSC_INVALID_INITIATOR_ADDRESS      0x000E
+#define I2O_DSC_INVALID_MESSAGE_FLAGS          0x000F
+#define I2O_DSC_INVALID_OFFSET                 0x0010
+#define I2O_DSC_INVALID_PARAMETER              0x0011
+#define I2O_DSC_INVALID_REQUEST                0x0012
+#define I2O_DSC_INVALID_TARGET_ADDRESS         0x0013
+#define I2O_DSC_MESSAGE_TOO_LARGE              0x0014
+#define I2O_DSC_MESSAGE_TOO_SMALL              0x0015
+#define I2O_DSC_MISSING_PARAMETER              0x0016
+#define I2O_DSC_TIMEOUT                        0x0017
+#define I2O_DSC_UNKNOWN_ERROR                  0x0018
+#define I2O_DSC_UNKNOWN_FUNCTION               0x0019
+#define I2O_DSC_UNSUPPORTED_VERSION            0x001A
+#define I2O_DSC_DEVICE_BUSY                    0x001B
+#define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
+
+/* Message header defines for VersionOffset */
+#define I2OVER15	0x0001
+#define I2OVER20	0x0002
+/* Default is 1.5, FIXME: Need support for both 1.5 and 2.0 */
+#define I2OVERSION	I2OVER15
+#define SGL_OFFSET_0    I2OVERSION
+#define SGL_OFFSET_4    (0x0040 | I2OVERSION)
+#define SGL_OFFSET_5    (0x0050 | I2OVERSION)
+#define SGL_OFFSET_6    (0x0060 | I2OVERSION)
+#define SGL_OFFSET_8    (0x0080 | I2OVERSION)
+#define SGL_OFFSET_10   (0x00A0 | I2OVERSION)
+
+#define TRL_OFFSET_5    (0x0050 | I2OVERSION)
+#define TRL_OFFSET_6    (0x0060 | I2OVERSION)
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC	0x0100
+#define MSG_64BIT_CNTXT	0x0200
+#define MSG_MULTI_TRANS	0x1000
+#define MSG_FAIL	0x2000
+#define MSG_LAST	0x4000
+#define MSG_REPLY	0x8000
+
+  /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
+#define LAN_MSG_REQST	(MSG_MULTI_TRANS | SGL_OFFSET_4)
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE	0x00030000
+#define FOUR_WORD_MSG_SIZE	0x00040000
+#define FIVE_WORD_MSG_SIZE	0x00050000
+#define SIX_WORD_MSG_SIZE	0x00060000
+#define SEVEN_WORD_MSG_SIZE	0x00070000
+#define EIGHT_WORD_MSG_SIZE	0x00080000
+#define NINE_WORD_MSG_SIZE	0x00090000
+#define TEN_WORD_MSG_SIZE	0x000A0000
+#define I2O_MESSAGE_SIZE(x)	((x)<<16)
+
+
+/* Special TID Assignments */
+
+#define ADAPTER_TID		0
+#define HOST_TID		1
+
+#define MSG_FRAME_SIZE		128
+#define NMBR_MSG_FRAMES		128
+
+#define MSG_POOL_SIZE		16384
+
+#define I2O_POST_WAIT_OK	1
+#define I2O_POST_WAIT_TIMEOUT	-1
+
+#endif /* __KERNEL__ */
+
+#include <asm/ioctl.h>
+
+/*
+ * I2O Control IOCTLs and structures
+ */
+#define I2O_MAGIC_NUMBER	'i'
+#define I2OGETIOPS		_IO(I2O_MAGIC_NUMBER,0)
+#define I2OHRTGET		_IO(I2O_MAGIC_NUMBER,1)
+#define I2OLCTGET		_IO(I2O_MAGIC_NUMBER,2)
+#define I2OPARMSET		_IO(I2O_MAGIC_NUMBER,3)
+#define I2OPARMGET		_IO(I2O_MAGIC_NUMBER,4)
+#define I2OSWDL			_IO(I2O_MAGIC_NUMBER,5)
+#define I2OSWUL			_IO(I2O_MAGIC_NUMBER,6)
+#define I2OSWDEL		_IO(I2O_MAGIC_NUMBER,7)
+#define I2OHTML			_IO(I2O_MAGIC_NUMBER,8)
+
+/* On hold until we figure this out
+#define I2OEVTREG		_IO(I2O_MAGIC_NUMBER,9)
+#define I2OEVTCLR		_IO(I2O_MAGIC_NUMBER,10)
+#define I2OEVTGET		_IO(I2O_MAGIC_NUMBER,11)
+ */
+
+struct i2o_cmd_hrtlct
+{
+	unsigned int iop;  /* IOP unit number */
+	void  *resbuf;  /* Buffer for result */
+	unsigned int *reslen;  /* Buffer length in bytes */
+};
+
+
+struct i2o_cmd_psetget
+{
+	unsigned int iop;      /* IOP unit number */
+	unsigned int tid;      /* Target device TID */
+	void  *opbuf;   /* Operation List buffer */
+ unsigned int oplen; /* Operation List buffer length in bytes */
+	void  *resbuf;  /* Result List buffer */
+	unsigned int  *reslen;  /* Result List buffer length in bytes */
+};
+
+struct i2o_sw_xfer
+{
+	unsigned int iop;	/* IOP unit number */
+	unsigned char dl_flags;	/* DownLoadFlags field */
+	unsigned char sw_type;	/* Software type */
+	unsigned int sw_id;     /* Software ID */
+	void  *buf;      	/* Pointer to software buffer */
+	unsigned int *swlen;    /* Length of software data */
+	unsigned int *maxfrag;  /* Maximum fragment count */
+        unsigned int *curfrag;  /* Current fragment count */
+};
+
+struct i2o_html
+{
+	unsigned int iop;      /* IOP unit number */
+	unsigned int tid;      /* Target device ID */
+	unsigned int page;     /* HTML page */
+	void  *resbuf;  /* Buffer for reply HTML page */
+ unsigned int *reslen; /* Length in bytes of reply buffer */
+	void  *qbuf;    /* Pointer to HTTP query string */
+	unsigned int qlen;     /* Length in bytes of query string buffer */
+};
+
+#endif
diff -u --recursive --new-file v2.3.5/linux/include/linux/igmp.h linux/include/linux/igmp.h
--- v2.3.5/linux/include/linux/igmp.h	Mon Jan 12 15:28:18 1998
+++ linux/include/linux/igmp.h	Wed Jun  9 14:45:36 1999
@@ -101,19 +101,7 @@
X 	char			loaded;
X };
X 
-extern __inline__ int ip_check_mc(struct device *dev, u32 mc_addr)
-{
-	struct in_device *in_dev = dev->ip_ptr;
-	struct ip_mc_list *im;
-
-	if (in_dev) {
-		for (im=in_dev->mc_list; im; im=im->next)
-			if (im->multiaddr == mc_addr)
-				return 1;
-	}
-	return 0;
-}
-
+extern int ip_check_mc(struct device *dev, u32 mc_addr);
X extern int igmp_rcv(struct sk_buff *, unsigned short);
X extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
X extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
diff -u --recursive --new-file v2.3.5/linux/include/linux/inet.h linux/include/linux/inet.h
--- v2.3.5/linux/include/linux/inet.h	Thu May 15 16:48:05 1997
+++ linux/include/linux/inet.h	Wed Jun  9 14:45:36 1999
@@ -46,6 +46,7 @@
X 
X extern void		inet_proto_init(struct net_proto *pro);
X extern char		*in_ntoa(__u32 in);
+extern char		*in_ntoa2(__u32 in, char *buf);
X extern __u32		in_aton(const char *str);
X 
X #endif
diff -u --recursive --new-file v2.3.5/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.3.5/linux/include/linux/inetdevice.h	Mon Jan  4 15:31:35 1999
+++ linux/include/linux/inetdevice.h	Wed Jun  9 14:45:36 1999
@@ -74,7 +74,7 @@
X extern void		devinet_init(void);
X extern struct in_device *inetdev_init(struct device *dev);
X extern struct in_device	*inetdev_by_index(int);
-extern u32		inet_select_addr(struct device *dev, u32 dst, int scope);
+extern u32		inet_select_addr(const struct device *dev, u32 dst, int scope);
X extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
X extern void		inet_forward_change(void);
X 
diff -u --recursive --new-file v2.3.5/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.5/linux/include/linux/mm.h	Fri May 14 18:55:29 1999
+++ linux/include/linux/mm.h	Tue Jun  8 23:03:47 1999
@@ -314,6 +314,7 @@
X extern unsigned long do_mmap(struct file *, unsigned long, unsigned long,
X 	unsigned long, unsigned long, unsigned long);
X extern int do_munmap(unsigned long, size_t);
+extern unsigned long do_brk(unsigned long, unsigned long);
X 
X /* filemap.c */
X extern void remove_inode_page(struct page *);
@@ -381,6 +382,8 @@
X 		vma = NULL;
X 	return vma;
X }
+
+extern struct vm_area_struct *find_extend_vma(struct task_struct *tsk, unsigned long addr);
X 
X #define buffer_under_min()	((buffermem >> PAGE_SHIFT) * 100 < \
X 				buffer_mem.min_percent * num_physpages)
diff -u --recursive --new-file v2.3.5/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.3.5/linux/include/linux/netdevice.h	Mon May 31 22:28:06 1999
+++ linux/include/linux/netdevice.h	Wed Jun  9 14:45:36 1999
@@ -152,6 +152,7 @@
X 	struct hh_cache *hh_next;	/* Next entry			     */
X 	atomic_t	hh_refcnt;	/* number of users                   */
X 	unsigned short  hh_type;	/* protocol identifier, f.e ETH_P_IP */
+	int		hh_len;		/* length of header */
X 	int		(*hh_output)(struct sk_buff *skb);
X 	rwlock_t	hh_lock;
X 	/* cached hardware header; allow for machine alignment needs.        */
@@ -260,6 +261,7 @@
X 	void 			*atalk_ptr;	/* AppleTalk link 	*/
X 	void			*ip_ptr;	/* IPv4 specific data	*/  
X 	void                    *dn_ptr;        /* DECnet specific data */
+	void                    *ip6_ptr;       /* IPv6 specific data */
X 
X 	struct Qdisc		*qdisc;
X 	struct Qdisc		*qdisc_sleeping;
@@ -268,6 +270,13 @@
X 
X 	/* hard_start_xmit synchronizer */
X 	spinlock_t		xmit_lock;
+	/* cpu id of processor entered to hard_start_xmit or -1,
+	   if nobody entered there.
+	 */
+	int			xmit_lock_owner;
+	/* device queue lock */
+	spinlock_t		queue_lock;
+	atomic_t		refcnt;
X 
X 	/* Pointers to interface service routines.	*/
X 	int			(*open)(struct device *dev);
diff -u --recursive --new-file v2.3.5/linux/include/linux/nfs.h linux/include/linux/nfs.h
--- v2.3.5/linux/include/linux/nfs.h	Sat Mar  6 14:21:13 1999
+++ linux/include/linux/nfs.h	Tue Jun  8 22:11:58 1999
@@ -158,6 +158,11 @@
X 	const char *		name;
X };
X 
+struct nfs_readlinkargs {
+	struct nfs_fh *		fh;
+	const void *		buffer;
+};
+
X struct nfs_readargs {
X 	struct nfs_fh *		fh;
X 	__u32			offset;
@@ -195,7 +200,7 @@
X 	struct nfs_fh *		fh;
X 	__u32			cookie;
X 	void *			buffer;
-	unsigned int		bufsiz;
+	int			bufsiz;
X };
X 
X struct nfs_diropok {
@@ -208,16 +213,10 @@
X 	unsigned int		count;
X };
X 
-struct nfs_readlinkres {
-	char **			string;
-	unsigned int *		lenp;
-	unsigned int		maxlen;
-	void *			buffer;
-};
-
X struct nfs_readdirres {
X 	void *			buffer;
-	unsigned int		bufsiz;
+	int			bufsiz;
+	u32			cookie;
X };
X 
X #endif /* NFS_NEED_XDR_TYPES */
diff -u --recursive --new-file v2.3.5/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.3.5/linux/include/linux/nfs_fs.h	Wed Jun  2 14:44:39 1999
+++ linux/include/linux/nfs_fs.h	Tue Jun  8 23:03:44 1999
@@ -79,6 +79,8 @@
X #define NFS_FLAGS(inode)		((inode)->u.nfs_i.flags)
X #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATE)
X #define NFS_WRITEBACK(inode)		((inode)->u.nfs_i.writeback)
+#define NFS_COOKIES(inode)		((inode)->u.nfs_i.cookies)
+#define NFS_DIREOF(inode)		((inode)->u.nfs_i.direof)
X 
X /*
X  * These are the default flags for swap requests
@@ -139,9 +141,6 @@
X extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
X 			const char *name, struct nfs_fh *fhandle,
X 			struct nfs_fattr *fattr);
-extern int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
-			void **p0, char **string, unsigned int *len,
-			unsigned int maxlen);
X extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
X 			int swap, unsigned long offset, unsigned int count,
X 			void *buffer, struct nfs_fattr *fattr);
@@ -166,8 +165,6 @@
X 			struct nfs_fh *fhandle, struct nfs_fattr *fattr);
X extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
X 			const char *name);
-extern int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
-			u32 cookie, unsigned int size, __u32 *entry);
X extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
X 			struct nfs_fsinfo *res);
X 
@@ -195,9 +192,7 @@
X  */
X extern struct inode_operations nfs_dir_inode_operations;
X extern struct dentry_operations nfs_dentry_operations;
-extern void nfs_free_dircache(void);
X extern void nfs_invalidate_dircache(struct inode *);
-extern void nfs_invalidate_dircache_sb(struct super_block *);
X 
X /*
X  * linux/fs/nfs/symlink.c
diff -u --recursive --new-file v2.3.5/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v2.3.5/linux/include/linux/nfs_fs_i.h	Sat Mar  6 15:04:35 1999
+++ linux/include/linux/nfs_fs_i.h	Tue Jun  8 22:42:23 1999
@@ -47,6 +47,10 @@
X 	 * pages.
X 	 */
X 	struct nfs_wreq *	writeback;
+
+	/* Readdir caching information. */
+	void *cookies;
+	u32 direof;
X };
X 
X /*
diff -u --recursive --new-file v2.3.5/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.3.5/linux/include/linux/pagemap.h	Mon May 31 22:28:06 1999
+++ linux/include/linux/pagemap.h	Tue Jun  8 23:03:47 1999
@@ -28,6 +28,7 @@
X #define PAGE_CACHE_SHIFT	PAGE_SHIFT
X #define PAGE_CACHE_SIZE		PAGE_SIZE
X #define PAGE_CACHE_MASK		PAGE_MASK
+#define PAGE_CACHE_ALIGN(addr)	(((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK)
X 
X #define page_cache_alloc()	__get_free_page(GFP_USER)
X #define page_cache_free(x)	free_page(x)
diff -u --recursive --new-file v2.3.5/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.5/linux/include/linux/parport.h	Mon May 31 22:28:06 1999
+++ linux/include/linux/parport.h	Tue Jun  8 23:04:38 1999
@@ -103,9 +103,6 @@
X 
X 	void (*change_mode)(struct parport *, int);
X 
-	void (*release_resources)(struct parport *);
-	int (*claim_resources)(struct parport *);
-
X 	void (*epp_write_data)(struct parport *, unsigned char);
X 	unsigned char (*epp_read_data)(struct parport *);
X 	void (*epp_write_addr)(struct parport *, unsigned char);
@@ -169,6 +166,7 @@
X 	unsigned int waiting;
X 	struct pardevice *waitprev;
X 	struct pardevice *waitnext;
+        void * sysctl_table;
X };
X 
X /* Directory information for the /proc interface */
@@ -210,6 +208,7 @@
X 	spinlock_t pardevice_lock;
X 	spinlock_t waitlist_lock;
X 	rwlock_t cad_lock;
+        void * sysctl_table;
X };
X 
X struct parport_driver {
@@ -240,10 +239,6 @@
X /* parport_in_use returns nonzero if there are devices attached to a port. */
X #define parport_in_use(x)  ((x)->devices != NULL)
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 20'
echo 'File patch-2.3.6 is continued in part 21'
echo 21 > _shar_seq_.tmp
exit 0
#!/bin/sh
# this is part 21 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 21; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
X 
-/* Put a parallel port to sleep; release its hardware resources.  Only possible
- * if no devices are registered.  */
-extern void parport_quiesce(struct parport *);
-
X /* parport_enumerate returns a pointer to the linked list of all the ports
X  * in this machine.
X  */
@@ -339,7 +334,7 @@
X #define PARPORT_DEV_LURK		(1<<0)	/* WARNING !! DEPRECATED !! */
X #define PARPORT_DEV_EXCL		(1<<1)	/* Need exclusive access. */
X 
-#define PARPORT_FLAG_COMA		(1<<0)
+#define PARPORT_FLAG_COMA_		(1<<0)  /* No longer used. */
X #define PARPORT_FLAG_EXCL		(1<<1)	/* EXCL driver registered. */
X 
X extern int parport_parse_irqs(int, const char *[], int irqval[]);
@@ -349,10 +344,12 @@
X 				   char);
X 
X /* Prototypes from parport_procfs */
-extern int parport_proc_init(void);
-extern void parport_proc_cleanup(void);
X extern int parport_proc_register(struct parport *pp);
X extern int parport_proc_unregister(struct parport *pp);
+extern int parport_device_proc_register(struct pardevice *device);
+extern int parport_device_proc_unregister(struct pardevice *device);
+extern int parport_default_proc_register(void);
+extern int parport_default_proc_unregister(void);
X 
X extern void dec_parport_count(void);
X extern void inc_parport_count(void);
diff -u --recursive --new-file v2.3.5/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.5/linux/include/linux/pci.h	Fri May 14 18:55:29 1999
+++ linux/include/linux/pci.h	Wed Jun  9 16:59:16 1999
@@ -273,6 +273,8 @@
X #define PCI_CLASS_SERIAL_USB		0x0c03
X #define PCI_CLASS_SERIAL_FIBER		0x0c04
X 
+#define PCI_CLASS_HOT_SWAP_CONTROLLER	0xff00
+
X #define PCI_CLASS_OTHERS		0xff
X 
X /*
@@ -365,6 +367,7 @@
X #define PCI_DEVICE_ID_DEC_21150		0x0022
X #define PCI_DEVICE_ID_DEC_21152		0x0024
X #define PCI_DEVICE_ID_DEC_21153		0x0025
+#define PCI_DEVICE_ID_DEC_21154		0x0026
X 
X #define PCI_VENDOR_ID_CIRRUS		0x1013
X #define PCI_DEVICE_ID_CIRRUS_7548	0x0038
@@ -510,9 +513,12 @@
X #define PCI_DEVICE_ID_WINBOND2_89C940	0x0940
X 
X #define PCI_VENDOR_ID_MOTOROLA		0x1057
+#define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
X #define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
X #define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
X #define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
+#define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
+#define PCI_DEVICE_ID_MOTOROLA_CPX8216	0x4806
X 
X #define PCI_VENDOR_ID_PROMISE		0x105a
X #define PCI_DEVICE_ID_PROMISE_20246	0x4d33
@@ -1062,9 +1068,11 @@
X 
X #define PCI_VENDOR_ID_ADAPTEC		0x9004
X #define PCI_DEVICE_ID_ADAPTEC_7810	0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821	0x2178
X #define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
X #define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
X #define PCI_DEVICE_ID_ADAPTEC_5800	0x5800
+#define PCI_DEVICE_ID_ADAPTEC_3860	0x6038
X #define PCI_DEVICE_ID_ADAPTEC_1480A	0x6075
X #define PCI_DEVICE_ID_ADAPTEC_7860	0x6078
X #define PCI_DEVICE_ID_ADAPTEC_7861	0x6178
@@ -1079,15 +1087,28 @@
X #define PCI_DEVICE_ID_ADAPTEC_7882	0x8278
X #define PCI_DEVICE_ID_ADAPTEC_7883	0x8378
X #define PCI_DEVICE_ID_ADAPTEC_7884	0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885	0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886	0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887	0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888	0x8878
X #define PCI_DEVICE_ID_ADAPTEC_1030	0x8b78
X 
X #define PCI_VENDOR_ID_ADAPTEC2		0x9005
X #define PCI_DEVICE_ID_ADAPTEC2_2940U2	0x0010
-#define PCI_DEVICE_ID_ADAPTEC2_78902	0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2	0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B	0x0013
X #define PCI_DEVICE_ID_ADAPTEC2_7890	0x001f
X #define PCI_DEVICE_ID_ADAPTEC2_3940U2	0x0050
X #define PCI_DEVICE_ID_ADAPTEC2_3950U2D	0x0051
X #define PCI_DEVICE_ID_ADAPTEC2_7896	0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A	0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B	0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D	0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P	0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A	0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B	0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D	0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P	0x00cf
X 
X #define PCI_VENDOR_ID_ATRONICS		0x907f
X #define PCI_DEVICE_ID_ATRONICS_2015	0x2015
diff -u --recursive --new-file v2.3.5/linux/include/linux/pkt_sched.h linux/include/linux/pkt_sched.h
--- v2.3.5/linux/include/linux/pkt_sched.h	Tue Apr 28 11:10:10 1998
+++ linux/include/linux/pkt_sched.h	Wed Jun  9 14:45:36 1999
@@ -38,6 +38,9 @@
X 	__u32	pps;			/* Current flow packet rate */
X 	__u32	qlen;
X 	__u32	backlog;
+#ifdef __KERNEL__
+	spinlock_t *lock;
+#endif
X };
X 
X struct tc_estimator
diff -u --recursive --new-file v2.3.5/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.5/linux/include/linux/proc_fs.h	Mon May 31 22:28:06 1999
+++ linux/include/linux/proc_fs.h	Tue Jun  8 23:04:14 1999
@@ -52,7 +52,8 @@
X 	PROC_STRAM,
X 	PROC_SOUND,
X 	PROC_MTRR, /* whether enabled or not */
-	PROC_FS
+	PROC_FS,
+	PROC_SYSVIPC
X };
X 
X enum pid_directory_inos {
@@ -207,6 +208,7 @@
X 	PROC_SCSI_INIA100,
X 	PROC_SCSI_FCAL,
X 	PROC_SCSI_I2O,
+	PROC_SCSI_USB_SCSI,
X 	PROC_SCSI_SCSI_DEBUG,	
X 	PROC_SCSI_NOT_PRESENT,
X 	PROC_SCSI_FILE,                        /* I'm assuming here that we */
@@ -243,6 +245,12 @@
X 	PROC_CODA_FS_LAST
X };
X 
+enum sysvipc_directory_inos {
+	PROC_SYSVIPC_SHM = PROC_CODA_FS_LAST,
+	PROC_SYSVIPC_SEM,
+	PROC_SYSVIPC_MSG
+};
+
X /* Finally, the dynamically allocatable proc entries are reserved: */
X 
X #define PROC_DYNAMIC_FIRST 4096
@@ -313,6 +321,7 @@
X extern struct proc_dir_entry proc_pid_fd;
X extern struct proc_dir_entry proc_mca;
X extern struct proc_dir_entry *proc_bus;
+extern struct proc_dir_entry *proc_sysvipc;
X 
X extern struct inode_operations proc_scsi_inode_operations;
X 
@@ -422,6 +431,7 @@
X #endif
X extern struct inode_operations proc_omirr_inode_operations;
X extern struct inode_operations proc_ppc_htab_inode_operations;
+extern struct inode_operations proc_sysvipc_inode_operations;
X 
X /*
X  * generic.c
diff -u --recursive --new-file v2.3.5/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- v2.3.5/linux/include/linux/rtnetlink.h	Mon May 31 22:28:06 1999
+++ linux/include/linux/rtnetlink.h	Wed Jun  9 14:45:36 1999
@@ -515,9 +515,6 @@
X 
X #ifdef __KERNEL__
X 
-extern atomic_t rtnl_rlockct;
-extern wait_queue_head_t rtnl_wait;
-
X extern __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
X {
X 	int len = strlen(str) + 1;
@@ -544,127 +541,31 @@
X #define RTA_PUT(skb, attrtype, attrlen, data) \
X ({ if (skb_tailroom(skb) < (int)RTA_SPACE(attrlen)) goto rtattr_failure; \
X    __rta_fill(skb, attrtype, attrlen, data); })
-
-extern unsigned long rtnl_wlockct;
-
-/* NOTE: these locks are not interrupt safe, are not SMP safe,
- * they are even not atomic. 8)8)8) ... and it is not a bug.
- * Really, if these locks will be programmed correctly,
- * all the addressing/routing machine would become SMP safe,
- * but is absolutely useless at the moment, because all the kernel
- * is not reenterable in any case. --ANK
- *
- * Well, atomic_* and set_bit provide the only thing here:
- * gcc is confused not to overoptimize them, that's all.
- * I remember as gcc splitted ++ operation, but cannot reproduce
- * it with gcc-2.7.*. --ANK
- *
- * One more note: rwlock facility should be written and put
- * to a kernel wide location: f.e. current implementation of semaphores
- * (especially, for x86) looks like a wonder. It would be good
- * to have something similar for rwlock. Recursive lock could be also
- * useful thing. --ANK
- */
-
-extern __inline__ int rtnl_shlock_nowait(void)
-{
-	atomic_inc(&rtnl_rlockct);
-	if (test_bit(0, &rtnl_wlockct)) {
-		atomic_dec(&rtnl_rlockct);
-		return -EAGAIN;
-	}
-	return 0;
-}
-
-extern __inline__ void rtnl_shlock(void)
-{
-	while (rtnl_shlock_nowait())
-		sleep_on(&rtnl_wait);
-}
-
-/* Check for possibility to PROMOTE shared lock to exclusive.
-   Shared lock must be already grabbed with rtnl_shlock*().
- */
-
-extern __inline__ int rtnl_exlock_nowait(void)
-{
-	if (atomic_read(&rtnl_rlockct) > 1)
-		return -EAGAIN;
-	if (test_and_set_bit(0, &rtnl_wlockct))
-		return -EAGAIN;
-	return 0;
-}
-
-extern __inline__ void rtnl_exlock(void)
-{
-	while (rtnl_exlock_nowait())
-		sleep_on(&rtnl_wait);
-}
-
-#if 0
-extern __inline__ void rtnl_shunlock(void)
-{
-	atomic_dec(&rtnl_rlockct);
-	if (atomic_read(&rtnl_rlockct) <= 1) {
-		wake_up(&rtnl_wait);
-		if (rtnl && rtnl->receive_queue.qlen)
-			rtnl->data_ready(rtnl, 0);
-	}
-}
-#else
-
-/* The problem: inline requires to include <net/sock.h> and, hence,
-   almost all of net includes :-(
- */
-
-#define rtnl_shunlock() ({ \
-	atomic_dec(&rtnl_rlockct); \
-	if (atomic_read(&rtnl_rlockct) <= 1) { \
-		wake_up(&rtnl_wait); \
-		if (rtnl && rtnl->receive_queue.qlen) \
-			rtnl->data_ready(rtnl, 0); \
-	} \
-})
X #endif
X 
-/* Release exclusive lock. Note, that we do not wake up rtnetlink socket,
- * it will be done later after releasing shared lock.
- */
-
-extern __inline__ void rtnl_exunlock(void)
-{
-	clear_bit(0, &rtnl_wlockct);
-	wake_up(&rtnl_wait);
-}
-
-#else
+extern struct semaphore rtnl_sem;
X 
-extern __inline__ void rtnl_shlock(void)
-{
-	while (atomic_read(&rtnl_rlockct))
-		sleep_on(&rtnl_wait);
-	atomic_inc(&rtnl_rlockct);
-}
+#define rtnl_exlock()		do { } while(0)
+#define rtnl_exunlock()		do { } while(0)
+#define rtnl_exlock_nowait()	(0)
X 
-extern __inline__ void rtnl_shunlock(void)
-{
-	if (atomic_dec_and_test(&rtnl_rlockct))
-		wake_up(&rtnl_wait);
-}
-
-extern __inline__ void rtnl_exlock(void)
-{
-}
-
-extern __inline__ void rtnl_exunlock(void)
-{
-}
+#define rtnl_shlock()		down(&rtnl_sem)
+#define rtnl_shlock_nowait()	down_trylock(&rtnl_sem)
X 
+#ifndef CONFIG_RTNETLINK
+#define rtnl_shunlock()	up(&rtnl_sem)
+#else
+#define rtnl_shunlock()	do { up(&rtnl_sem); \
+		             if (rtnl && rtnl->receive_queue.qlen) \
+				     rtnl->data_ready(rtnl, 0); \
+		        } while(0)
X #endif
X 
X extern void rtnl_lock(void);
X extern void rtnl_unlock(void);
X extern void rtnetlink_init(void);
+
+
X 
X #endif /* __KERNEL__ */
X 
diff -u --recursive --new-file v2.3.5/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.5/linux/include/linux/sched.h	Mon May 31 22:28:06 1999
+++ linux/include/linux/sched.h	Tue Jun  8 23:03:44 1999
@@ -163,9 +163,9 @@
X #define AVL_MIN_MAP_COUNT	32
X 
X struct mm_struct {
-	struct vm_area_struct *mmap;		/* list of VMAs */
-	struct vm_area_struct *mmap_avl;	/* tree of VMAs */
-	struct vm_area_struct *mmap_cache;	/* last find_vma result */
+	struct vm_area_struct * mmap;		/* list of VMAs */
+	struct vm_area_struct * mmap_avl;	/* tree of VMAs */
+	struct vm_area_struct * mmap_cache;	/* last find_vma result */
X 	pgd_t * pgd;
X 	atomic_t count;
X 	int map_count;				/* number of VMAs */
@@ -453,8 +453,8 @@
X }
X 
X /* per-UID process charging. */
-extern int alloc_uid(struct task_struct *p);
-void free_uid(struct task_struct *p);
+extern int alloc_uid(struct task_struct *);
+void free_uid(struct task_struct *);
X 
X #include <asm/current.h>
X 
@@ -482,26 +482,25 @@
X #define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
X #define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE)
X 
-extern int in_group_p(gid_t grp);
+extern int in_group_p(gid_t);
X 
X extern void flush_signals(struct task_struct *);
X extern void flush_signal_handlers(struct task_struct *);
-extern int dequeue_signal(sigset_t *block, siginfo_t *);
-extern int send_sig_info(int, struct siginfo *info, struct task_struct *);
-extern int force_sig_info(int, struct siginfo *info, struct task_struct *);
-extern int kill_pg_info(int, struct siginfo *info, pid_t);
-extern int kill_sl_info(int, struct siginfo *info, pid_t);
-extern int kill_proc_info(int, struct siginfo *info, pid_t);
-extern int kill_something_info(int, struct siginfo *info, int);
-extern void notify_parent(struct task_struct * tsk, int);
-extern void force_sig(int sig, struct task_struct * p);
-extern int send_sig(int sig, struct task_struct * p, int priv);
+extern int dequeue_signal(sigset_t *, siginfo_t *);
+extern int send_sig_info(int, struct siginfo *, struct task_struct *);
+extern int force_sig_info(int, struct siginfo *, struct task_struct *);
+extern int kill_pg_info(int, struct siginfo *, pid_t);
+extern int kill_sl_info(int, struct siginfo *, pid_t);
+extern int kill_proc_info(int, struct siginfo *, pid_t);
+extern int kill_something_info(int, struct siginfo *, int);
+extern void notify_parent(struct task_struct *, int);
+extern void force_sig(int, struct task_struct *);
+extern int send_sig(int, struct task_struct *, int);
X extern int kill_pg(pid_t, int, int);
X extern int kill_sl(pid_t, int, int);
X extern int kill_proc(pid_t, int, int);
-extern int do_sigaction(int sig, const struct k_sigaction *act,
-			struct k_sigaction *oact);
-extern int do_sigaltstack(const stack_t *ss, stack_t *oss, unsigned long sp);
+extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
+extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
X 
X extern inline int signal_pending(struct task_struct *p)
X {
@@ -552,12 +551,10 @@
X 		: on_sig_stack(sp) ? SS_ONSTACK : 0);
X }
X 
-extern int request_irq(unsigned int irq,
+extern int request_irq(unsigned int,
X 		       void (*handler)(int, void *, struct pt_regs *),
-		       unsigned long flags, 
-		       const char *device,
-		       void *dev_id);
-extern void free_irq(unsigned int irq, void *dev_id);
+		       unsigned long, const char *, void *);
+extern void free_irq(unsigned int, void *);
X 
X /*
X  * This has now become a routine instead of a macro, it sets a flag if
diff -u --recursive --new-file v2.3.5/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.5/linux/include/linux/sysctl.h	Mon May 31 22:28:06 1999
+++ linux/include/linux/sysctl.h	Thu Jun  3 16:21:47 1999
@@ -452,12 +452,42 @@
X /* CTL_DEV names: */
X enum {
X 	DEV_CDROM=1,
-	DEV_HWMON=2
+	DEV_HWMON=2,
+	DEV_PARPORT=3
X };
X 
X /* /proc/sys/dev/cdrom */
X enum {
X 	DEV_CDROM_INFO=1
+};
+
+/* /proc/sys/dev/parport */
+enum {
+	DEV_PARPORT_DEFAULT=-3
+};
+
+/* /proc/sys/dev/parport/default */
+enum {
+	DEV_PARPORT_DEFAULT_TIMESLICE=1,
+	DEV_PARPORT_DEFAULT_SPINTIME=2
+};
+
+/* /proc/sys/dev/parport/parport n */
+enum {
+	DEV_PARPORT_SPINTIME=1,
+	DEV_PARPORT_HARDWARE=2,
+	DEV_PARPORT_DEVICES=3,
+	DEV_PARPORT_AUTOPROBE=16
+};
+
+/* /proc/sys/dev/parport/parport n/devices/ */
+enum {
+	DEV_PARPORT_DEVICES_ACTIVE=-3,
+};
+
+/* /proc/sys/dev/parport/parport n/devices/device n */
+enum {
+	DEV_PARPORT_DEVICE_TIMESLICE=1,
X };
X 
X #ifdef __KERNEL__
diff -u --recursive --new-file v2.3.5/linux/include/linux/wanrouter.h linux/include/linux/wanrouter.h
--- v2.3.5/linux/include/linux/wanrouter.h	Tue May 11 13:06:00 1999
+++ linux/include/linux/wanrouter.h	Tue Jun  8 23:05:38 1999
@@ -5,6 +5,7 @@
X *
X * Author:	Gene Kozin	<ge...@compuserve.com>
X *		Jaspreet Singh	<jasp...@sangoma.com>
+* Additions:	Arnaldo Carvalho de Melo <ac...@conectiva.com.br>
X *
X * Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
X *
@@ -13,11 +14,14 @@
X *		as published by the Free Software Foundation; either version
X *		2 of the License, or (at your option) any later version.
X * ============================================================================
+* May 23, 1999	Arnaldo Melo	Added local_addr to wanif_conf_t
+*				WAN_DISCONNECTING state added
X * Nov 06, 1997	Jaspreet Singh	Changed Router Driver version to 1.1 from 1.0
X * Oct 20, 1997	Jaspreet Singh	Added 'cir','bc','be' and 'mc' to 'wanif_conf_t'
X *				Added 'enable_IPX' and 'network_number' to 
X *				'wan_device_t'.  Also added defines for
-*				UDP PACKET TYPE, Interrupt test, critical values*				for RACE conditions.
+*				UDP PACKET TYPE, Interrupt test, critical values
+*				for RACE conditions.
X * Oct 05, 1997	Jaspreet Singh	Added 'dlci_num' and 'dlci[100]' to 
X *				'wan_fr_conf_t' to configure a list of dlci(s)
X *				for a NODE 
@@ -125,7 +129,7 @@
X 	unsigned n392;		/* error threshold counter */
X 	unsigned n393;		/* monitored events counter */
X 	unsigned dlci_num;	/* number of DLCs (access node) */
-	unsigned  dlci[100];    /* List of all DLCIs */
+	unsigned dlci[100];	/* List of all DLCIs */
X } wan_fr_conf_t;
X 
X /*----------------------------------------------------------------------------
@@ -274,6 +278,7 @@
X 	WAN_DISCONNECTED,	/* link/channel is disconnected */
X 	WAN_CONNECTING,		/* connection is in progress */
X 	WAN_CONNECTED,		/* link/channel is operational */
+	WAN_DISCONNECTING,	/* disconnection is in progress */
X 	WAN_LIMIT		/* for verification only */
X };
X 
@@ -298,6 +303,8 @@
X 	unsigned bc;			/* Committed Burst Size fwd, bwd */
X 	unsigned be;			/* Excess Burst Size fwd, bwd */ 
X 	char mc;			/* Multicast on or off */
+	char local_addr[WAN_ADDRESS_SZ+1];/* local media address, ASCIIZ */
+	unsigned char port;		/* board port */
X 	int reserved[8];		/* reserved for future extensions */
X } wanif_conf_t;
X 
diff -u --recursive --new-file v2.3.5/linux/include/net/addrconf.h linux/include/net/addrconf.h
--- v2.3.5/linux/include/net/addrconf.h	Sun Mar 21 07:22:00 1999
+++ linux/include/net/addrconf.h	Wed Jun  9 14:45:36 1999
@@ -56,7 +56,7 @@
X extern int			ipv6_get_saddr(struct dst_entry *dst, 
X 					       struct in6_addr *daddr,
X 					       struct in6_addr *saddr);
-extern struct inet6_ifaddr *	ipv6_get_lladdr(struct device *dev);
+extern int			ipv6_get_lladdr(struct device *dev, struct in6_addr *);
X 
X /*
X  *	multicast prototypes (mcast.c)
@@ -68,6 +68,7 @@
X 						  int ifindex, 
X 						  struct in6_addr *addr);
X extern void			ipv6_sock_mc_close(struct sock *sk);
+extern int			inet6_mc_check(struct sock *sk, struct in6_addr *addr);
X 
X extern int			ipv6_dev_mc_inc(struct device *dev,
X 						struct in6_addr *addr);
diff -u --recursive --new-file v2.3.5/linux/include/net/dst.h linux/include/net/dst.h
--- v2.3.5/linux/include/net/dst.h	Mon May 31 22:28:06 1999
+++ linux/include/net/dst.h	Wed Jun  9 14:45:36 1999
@@ -170,6 +170,9 @@
X 	if (dst->expires == 0 || (long)(dst->expires - expires) > 0)
X 		dst->expires = expires;
X }
+
+extern void		dst_init(void);
+
X #endif
X 
X #endif /* _NET_DST_H */
diff -u --recursive --new-file v2.3.5/linux/include/net/if_inet6.h linux/include/net/if_inet6.h
--- v2.3.5/linux/include/net/if_inet6.h	Sun Mar  1 14:40:40 1998
+++ linux/include/net/if_inet6.h	Wed Jun  9 14:45:36 1999
@@ -44,6 +44,7 @@
X 	__u32			valid_lft;
X 	__u32			prefered_lft;
X 	unsigned long		tstamp;
+	atomic_t		refcnt;
X 
X 	__u8			probes;
X 	__u8			flags;
@@ -108,6 +109,7 @@
X 
X 	struct inet6_ifaddr	*addr_list;
X 	struct ifmcaddr6	*mc_list;
+	rwlock_t		lock;
X 	__u32			if_flags;
X 
X 	struct neigh_parms	*nd_parms;
diff -u --recursive --new-file v2.3.5/linux/include/net/ip.h linux/include/net/ip.h
--- v2.3.5/linux/include/net/ip.h	Mon May 31 22:28:06 1999
+++ linux/include/net/ip.h	Wed Jun  9 14:45:36 1999
@@ -146,10 +146,10 @@
X 	skb->protocol = __constant_htons(ETH_P_IP);
X 
X 	if (hh) {
-		read_lock_irq(&hh->hh_lock);
+		read_lock_bh(&hh->hh_lock);
X 		memcpy(skb->data - 16, hh->hh_data, 16);
-		read_unlock_irq(&hh->hh_lock);
-	        skb_push(skb, dev->hard_header_len);
+		read_unlock_bh(&hh->hh_lock);
+	        skb_push(skb, hh->hh_len);
X 		return hh->hh_output(skb);
X 	} else if (dst->neighbour)
X 		return dst->neighbour->output(skb);
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/dongle.h linux/include/net/irda/dongle.h
--- v2.3.5/linux/include/net/irda/dongle.h	Mon May 31 22:28:07 1999
+++ linux/include/net/irda/dongle.h	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Wed Oct 21 22:47:12 1998
- * Modified at:   Mon May 10 14:51:06 1999
+ * Modified at:   Sun May 16 13:40:03 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -35,15 +35,15 @@
X 	ACTISYS_PLUS_DONGLE,
X 	GIRBIL_DONGLE,
X 	LITELINK_DONGLE,
-} DONGLE_T;
+} IRDA_DONGLE;
X 
X struct irda_device;
X 
X struct dongle {
-	DONGLE_T type;
+	IRDA_DONGLE type;
X 	void (*open)(struct irda_device *, int type);
X 	void (*close)(struct irda_device *);
-	void (*reset)( struct irda_device *, int unused);
+	void (*reset)( struct irda_device *);
X 	void (*change_speed)( struct irda_device *, int baudrate);
X 	void (*qos_init)( struct irda_device *, struct qos_info *);
X };
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/ircomm_common.h linux/include/net/irda/ircomm_common.h
--- v2.3.5/linux/include/net/irda/ircomm_common.h	Mon May 31 22:28:07 1999
+++ linux/include/net/irda/ircomm_common.h	Mon Jun  7 16:18:58 1999
@@ -77,9 +77,9 @@
X 
X #define IRCOMM_MAGIC            0x434f4d4d
X #define COMM_INIT_CTRL_PARAM    3          /* length of initial control parameters */
-#define COMM_HEADER             1          /* length of clen field */
-#define COMM_HEADER_SIZE        (TTP_MAX_HEADER+COMM_HEADER)
-#define COMM_DEFAULT_DATA_SIZE  64
+#define COMM_HEADER_SIZE        1          /* length of clen field */
+#define COMM_MAX_HEADER_SIZE    (TTP_MAX_HEADER+COMM_HEADER_SIZE)
+#define COMM_DEFAULT_SDU_SIZE   (64 - COMM_HEADER_SIZE)
X #define IRCOMM_MAX_CONNECTION   1          /* Don't change for now */
X 
X 
@@ -177,8 +177,8 @@
X 	int null_modem_mode;     /* switch for null modem emulation */
X 	int ttp_stop;
X 
-	int max_txbuff_size;          
-	__u32 max_sdu_size;
+	__u32 tx_max_sdu_size;          
+	__u32 rx_max_sdu_size;
X 	__u8 max_header_size;
X 
X  	__u32 daddr;        /* Device address of the peer device */ 
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/irda_device.h linux/include/net/irda/irda_device.h
--- v2.3.5/linux/include/net/irda/irda_device.h	Mon May 31 22:28:07 1999
+++ linux/include/net/irda/irda_device.h	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Mon May 10 15:46:02 1999
+ * Modified at:   Wed May 19 08:44:48 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -124,14 +124,14 @@
X 
X 	struct dongle *dongle; /* Dongle driver */
X 
-	/* spinlock_t lock; */ /* For serializing operations */
+	spinlock_t lock;       /* For serializing operations */
X 	
X 	/* Media busy stuff */
X 	int media_busy;
X 	struct timer_list media_busy_timer;
X 
X 	/* Callbacks for driver specific implementation */
-        void (*change_speed)(struct irda_device *driver, int baud);
+        void (*change_speed)(struct irda_device *idev, int baud);
X  	int  (*is_receiving)(struct irda_device *);    /* receiving? */
X 	void (*set_dtr_rts)(struct irda_device *idev, int dtr, int rts);
X 	int  (*raw_write)(struct irda_device *idev, __u8 *buf, int len);
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/irlan_common.h linux/include/net/irda/irlan_common.h
--- v2.3.5/linux/include/net/irda/irlan_common.h	Mon May 31 22:28:07 1999
+++ linux/include/net/irda/irlan_common.h	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Sun May  9 11:45:33 1999
+ * Modified at:   Mon May 31 13:54:20 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>, 
@@ -124,6 +124,9 @@
X 	int unicast_open;
X 	int broadcast_open;
X 
+	int tx_busy;
+	struct sk_buff_head txq; /* Transmit control queue */
+
X 	struct timer_list kick_timer;
X };
X 
@@ -163,7 +166,7 @@
X 	struct device dev;        /* Ethernet device structure*/
X 	struct enet_statistics stats;
X 
-	__u32 saddr;              /* Source devcie address */
+	__u32 saddr;              /* Source device address */
X 	__u32 daddr;              /* Destination device address */
X 	int   netdev_registered;
X 	int   notify_irmanager;
@@ -200,6 +203,8 @@
X void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout);
X 
X void irlan_open_data_tsap(struct irlan_cb *self);
+
+int irlan_run_ctrl_tx_queue(struct irlan_cb *self);
X 
X void irlan_get_provider_info(struct irlan_cb *self);
X void irlan_get_unicast_addr(struct irlan_cb *self);
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/irlan_eth.h linux/include/net/irda/irlan_eth.h
--- v2.3.5/linux/include/net/irda/irlan_eth.h	Sat Apr 24 17:50:05 1999
+++ linux/include/net/irda/irlan_eth.h	Mon Jun  7 16:18:58 1999
@@ -6,10 +6,10 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Thu Oct 15 08:36:58 1998
- * Modified at:   Thu Apr 22 14:09:37 1999
+ * Modified at:   Fri May 14 23:29:00 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
X  *      
X  *     This program is free software; you can redistribute it and/or 
X  *     modify it under the terms of the GNU General Public License as 
@@ -32,6 +32,7 @@
X int  irlan_eth_xmit(struct sk_buff *skb, struct device *dev);
X 
X void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow);
+void irlan_eth_send_gratuitous_arp(struct device *dev);
X 
X void irlan_eth_set_multicast_list( struct device *dev);
X struct enet_statistics *irlan_eth_get_stats(struct device *dev);
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/irport.h linux/include/net/irda/irport.h
--- v2.3.5/linux/include/net/irda/irport.h	Mon May 31 22:28:07 1999
+++ linux/include/net/irda/irport.h	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun Aug  3 13:49:59 1997
- * Modified at:   Mon May 10 22:12:56 1999
+ * Modified at:   Wed May 19 15:31:16 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1997, 1998-1999 Dag Brattli <da...@cs.uit.no>
@@ -49,13 +49,14 @@
X 
X #define FRAME_MAX_SIZE 2048
X 
-void irport_start(int iobase);
-void irport_stop(int iobase);
+void irport_start(struct irda_device *idev, int iobase);
+void irport_stop(struct irda_device *idev, int iobase);
X int  irport_probe(int iobase);
X 
X void irport_change_speed(struct irda_device *idev, int speed);
X void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
X 
X int  irport_hard_xmit(struct sk_buff *skb, struct device *dev);
+void irport_wait_until_sent(struct irda_device *idev);
X 
X #endif
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/irqueue.h linux/include/net/irda/irqueue.h
--- v2.3.5/linux/include/net/irda/irqueue.h	Tue May 11 13:04:00 1999
+++ linux/include/net/irda/irqueue.h	Tue Jun  8 23:03:42 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Tue Jun  9 13:26:50 1998
- * Modified at:   Thu Feb 25 20:34:21 1999
+ * Modified at:   Tue May 25 07:54:41 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (C) 1998, Aage Kvalnes <aa...@cs.uit.no>
@@ -29,8 +29,6 @@
X 
X #include <linux/types.h>
X #include <asm/spinlock.h>
-
-/* #include <net/irda/irda.h> */
X 
X #ifndef QUEUE_H
X #define QUEUE_H
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/irvtd.h linux/include/net/irda/irvtd.h
--- v2.3.5/linux/include/net/irda/irvtd.h	Fri May 14 18:55:30 1999
+++ linux/include/net/irda/irvtd.h	Mon Jun  7 16:18:58 1999
@@ -53,6 +53,8 @@
X 	struct sk_buff_head rxbuff; 
X 	struct ircomm_cb *comm;     /* ircomm instance */
X 
+	__u32 tx_max_sdu_size;
+	__u32 max_header_size;
X 	/* 
X 	 * These members are used for compatibility with usual serial device.
X 	 * See linux/serial.h
@@ -69,7 +71,8 @@
X 	wait_queue_head_t       delta_msr_wait;
X 	wait_queue_head_t       tx_wait;
X 
-	struct timer_list       timer;
+	struct timer_list       tx_timer;
+	struct timer_list       rx_timer;
X 
X 	long pgrp;
X 	long session;  
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/smc-ircc.h linux/include/net/irda/smc-ircc.h
--- v2.3.5/linux/include/net/irda/smc-ircc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/smc-ircc.h	Mon Jun  7 16:18:58 1999
@@ -0,0 +1,160 @@
+/*********************************************************************
+ *                
+ * Filename:      smc.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Thomas Davis (tad...@jps.net)
+ *
+ *     Copyright (c) 1998, 1999 Thomas Davis (tad...@jps.net>
+ *     All Rights Reserved
+ *      
+ *     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.
+ *  
+ *     I, Thomas Davis, admit no liability nor provide warranty for any
+ *     of this software. This material is provided "AS-IS" and at no charge.
+ *     
+ * Definitions for the SMC IrCC controller.
+ *
+ ********************************************************************/
+
+#ifndef SMC_IRCC_H
+#define SMC_IRCC_H
+
+#define UART_MASTER			0x07
+#define UART_MASTER_POWERDOWN	1<<7
+#define UART_MASTER_RESET		1<<6
+#define UART_MASTER_INT_EN		1<<5
+#define UART_MASTER_ERROR_RESET	1<<4
+
+/* Register block 0 */
+
+#define UART_IIR	0x01
+#define UART_IER	0x02
+#define UART_LSR	0x03
+#define UART_LCR_A	0x04
+#define UART_LCR_B	0x05
+#define UART_BSR	0x06
+
+#define UART_IIR_ACTIVE_FRAME	1<<7
+#define UART_IIR_EOM 		1<<6
+#define UART_IIR_RAW_MODE		1<<5
+#define UART_IIR_FIFO		1<<4
+
+#define UART_IER_ACTIVE_FRAME	1<<7
+#define UART_IER_EOM 		1<<6
+#define UART_IER_RAW_MODE		1<<5
+#define UART_IER_FIFO		1<<4
+
+#define UART_LSR_UNDERRUN		1<<7
+#define UART_LSR_OVERRUN		1<<6
+#define UART_LSR_FRAME_ERROR 	1<<5
+#define UART_LSR_SIZE_ERROR		1<<4
+#define UART_LSR_CRC_ERROR		1<<3
+#define UART_LSR_FRAME_ABORT 	1<<2
+
+#define UART_LCR_A_FIFO_RESET        1<<7
+#define UART_LCR_A_FAST              1<<6
+#define UART_LCR_A_GP_DATA           1<<5
+#define UART_LCR_A_RAW_TX            1<<4
+#define UART_LCR_A_RAW_RX            1<<3
+#define UART_LCR_A_ABORT             1<<2
+#define UART_LCR_A_DATA_DONE         1<<1
+
+#define UART_LCR_B_SCE_DISABLED 	0x00<<6
+#define UART_LCR_B_SCE_TRANSMIT 	0x01<<6
+#define UART_LCR_B_SCE_RECEIVE		0x02<<6
+#define UART_LCR_B_SCE_UNDEFINED	0x03<<6
+#define UART_LCR_B_SIP_ENABLE		1<<5
+#define UART_LCR_B_BRICK_WALL		1<<4
+
+#define UART_BSR_NOT_EMPTY	1<<7
+#define UART_BSR_FIFO_FULL	1<<6
+#define UART_BSR_TIMEOUT	1<<5
+
+/* Register block 1 */
+
+#define UART_SCE_CFGA	0x00
+#define UART_SCE_CFGB	0x01
+#define UART_FIFO_THRESHOLD	0x02
+
+#define UART_CFGA_AUX_IR		0x01<<7
+#define UART_CFGA_HALF_DUPLEX	0x01<<2
+#define UART_CFGA_TX_POLARITY	0x01<<1
+#define UART_CFGA_RX_POLARITY	0x01
+
+#define UART_CFGA_COM		0x00<<3
+#define UART_CFGA_IRDA_SIR_A	0x01<<3
+#define UART_CFGA_ASK_SIR		0x02<<3
+#define UART_CFGA_IRDA_SIR_B	0x03<<3
+#define UART_CFGA_IRDA_HDLC 	0x04<<3
+#define UART_CFGA_IRDA_4PPM 	0x05<<3
+#define UART_CFGA_CONSUMER		0x06<<3
+#define UART_CFGA_RAW_IR		0x07<<3
+#define UART_CFGA_OTHER		0x08<<3
+
+#define UART_IR_HDLC			0x04
+#define UART_IR_4PPM			0x01
+#define UART_IR_CONSUMER		0x02
+
+#define UART_CFGB_LOOPBACK		0x01<<5
+#define UART_CFGB_LPBCK_TX_CRC	0x01<<4
+#define UART_CFGB_NOWAIT		0x01<<3
+#define UART_CFGB_STRING_MOVE	0x01<<2
+#define UART_CFGB_DMA_BURST 	0x01<<1
+#define UART_CFGB_DMA_ENABLE	0x01
+
+#define UART_CFGB_COM		0x00<<6
+#define UART_CFGB_IR		0x01<<6
+#define UART_CFGB_AUX		0x02<<6
+#define UART_CFGB_INACTIVE		0x03<<6
+
+/* Register block 2 - Consumer IR - not used */
+
+/* Register block 3 - Identification Registers! */
+
+#define UART_ID_HIGH	0x00   /* 0x10 */
+#define UART_ID_LOW	0x01   /* 0xB8 */
+#define UART_CHIP_ID 	0x02   /* 0xF1 */
+#define UART_VERSION	0x03   /* 0x01 */
+#define UART_INTERFACE	0x04   /* low 4 = DMA, high 4 = IRQ */
+
+/* Register block 4 - IrDA */
+#define UART_CONTROL        0x00
+#define UART_BOF_COUNT_LO      0x01
+#define UART_BRICKWALL_CNT_LO 0x02
+#define UART_BRICKWALL_TX_CNT_HI   0x03
+#define UART_TX_SIZE_LO   0x04
+#define UART_RX_SIZE_HI   0x05
+#define UART_RX_SIZE_LO   0x06
+
+#define UART_1152     0x01<<7
+#define UART_CRC      0x01<<6
+
+/* For storing entries in the status FIFO */
+struct st_fifo_entry {
+	int status;
+	int len;
+};
+
+struct st_fifo {
+	struct st_fifo_entry entries[10];
+	int head;
+	int tail;
+	int len;
+};
+
+/* Private data for each instance */
+struct ircc_cb {
+	struct st_fifo st_fifo;
+
+	int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
+	int tx_len;          /* Number of frames in tx_buff */
+
+	struct irda_device idev;
+};
+
+#endif
diff -u --recursive --new-file v2.3.5/linux/include/net/irda/smc_ircc.h linux/include/net/irda/smc_ircc.h
--- v2.3.5/linux/include/net/irda/smc_ircc.h	Thu Dec 17 09:01:03 1998
+++ linux/include/net/irda/smc_ircc.h	Wed Dec 31 16:00:00 1969
@@ -1,123 +0,0 @@
-#if 0
-static char *rcsid = "$Id: smc_ircc.h,v 1.5 1998/07/27 01:25:29 ratbert Exp $";
-#endif
-
-#ifndef SMC_IRCC_H
-#define SMC_IRCC_H
-
-#define FIR_XMIT	1
-#define FIR_RECEIVE	2
-#define SIR_XMIT	3
-#define SIR_RECEIVE	4
-
-#define MASTER			0x07
-#define MASTER_POWERDOWN	1<<7
-#define MASTER_RESET		1<<6
-#define MASTER_INT_EN		1<<5
-#define MASTER_ERROR_RESET	1<<4
-
-/* Register block 0 */
-
-#define IIR	0x01
-#define IER	0x02
-#define LSR	0x03
-#define LCR_A	0x04
-#define LCR_B	0x05
-#define BSR	0x06
-
-#define IIR_ACTIVE_FRAME	1<<7
-#define IIR_EOM 		1<<6
-#define IIR_RAW_MODE		1<<5
-#define IIR_FIFO		1<<4
-
-#define IER_ACTIVE_FRAME	1<<7
-#define IER_EOM 		1<<6
-#define IER_RAW_MODE		1<<5
-#define IER_FIFO		1<<4
-
-#define LSR_UNDER_RUN		1<<7
-#define LSR_OVER_RUN		1<<6
-#define LSR_FRAME_ERROR 	1<<5
-#define LSR_SIZE_ERROR		1<<4
-#define LSR_CRC_ERROR		1<<3
-#define LSR_FRAME_ABORT 	1<<2
-
-#define LCR_A_FIFO_RESET        1<<7
-#define LCR_A_FAST              1<<6
-#define LCR_A_GP_DATA           1<<5
-#define LCR_A_RAW_TX            1<<4
-#define LCR_A_RAW_RX            1<<3
-#define LCR_A_ABORT             1<<2
-#define LCR_A_DATA_DONE         1<<1
-
-#define LCR_B_SCE_MODE_DISABLED 	0x00<<6
-#define LCR_B_SCE_MODE_TRANSMIT 	0x01<<6
-#define LCR_B_SCE_MODE_RECEIVE		0x02<<6
-#define LCR_B_SCE_MODE_UNDEFINED	0x03<<6
-#define LCR_B_SIP_ENABLE		1<<5
-#define LCR_B_BRICK_WALL		1<<4
-
-#define BSR_NOT_EMPTY	1<<7
-#define BSR_FIFO_FULL	1<<6
-#define BSR_TIMEOUT	1<<5
-
-/* Register block 1 */
-
-#define SCE_CFG_A	0x00
-#define SCE_CFG_B	0x01
-#define FIFO_THRESHOLD	0x02
-
-#define CFG_A_AUX_IR		0x01<<7
-#define CFG_A_HALF_DUPLEX	0x01<<2
-#define CFG_A_TX_POLARITY	0x01<<1
-#define CFG_A_RX_POLARITY	0x01
-
-#define CFG_A_COM		0x00<<3
-#define CFG_A_IRDA_SIR_A	0x01<<3
-#define CFG_A_ASK_SIR		0x02<<3
-#define CFG_A_IRDA_SIR_B	0x03<<3
-#define CFG_A_IRDA_HDLC 	0x04<<3
-#define CFG_A_IRDA_4PPM 	0x05<<3
-#define CFG_A_CONSUMER		0x06<<3
-#define CFG_A_RAW_IR		0x07<<3
-#define CFG_A_OTHER		0x08<<3
-
-#define IR_HDLC			0x04
-#define IR_4PPM			0x01
-#define IR_CONSUMER		0x02
-
-#define CFG_B_LOOPBACK		0x01<<5
-#define CFG_B_LPBCK_TX_CRC	0x01<<4
-#define CFG_B_NOWAIT		0x01<<3
-#define CFB_B_STRING_MOVE	0x01<<2
-#define CFG_B_DMA_BURST 	0x01<<1
-#define CFG_B_DMA_ENABLE	0x01
-
-#define CFG_B_MUX_COM		0x00<<6
-#define CFG_B_MUX_IR		0x01<<6
-#define CFG_B_MUX_AUX		0x02<<6
-#define CFG_B_INACTIVE		0x03<<6
-
-/* Register block 2 - Consumer IR - not used */
-
-/* Register block 3 - Identification Registers! */
-
-#define SMSC_ID_HIGH	0x00   /* 0x10 */
-#define SMSC_ID_LOW	0x01   /* 0xB8 */
-#define CHIP_ID 	0x02   /* 0xF1 */
-#define VERSION_NUMBER	0x03   /* 0x01 */
-#define HOST_INTERFACE	0x04   /* low 4 = DMA, high 4 = IRQ */
-
-/* Register block 4 - IrDA */
-#define IR_CONTROL        0x00
-#define BOF_COUNT_LO      0x01
-#define BRICK_WALL_CNT_LO 0x02
-#define BRICK_TX_CNT_HI   0x03
-#define TX_DATA_SIZE_LO   0x04
-#define RX_DATA_SIZE_HI   0x05
-#define RX_DATA_SIZE_LO   0x06
-
-#define SELECT_1152     0x01<<7
-#define CRC_SELECT      0x01<<6
-
-#endif
diff -u --recursive --new-file v2.3.5/linux/include/net/neighbour.h linux/include/net/neighbour.h
--- v2.3.5/linux/include/net/neighbour.h	Tue May 11 13:05:00 1999
+++ linux/include/net/neighbour.h	Wed Jun  9 14:45:36 1999
@@ -96,7 +96,8 @@
X 	__u8			flags;
X 	__u8			nud_state;
X 	__u8			type;
-	__u8			probes;
+	atomic_t		probes;
+	rwlock_t		lock;
X 	unsigned char		ha[MAX_ADDR_LEN];
X 	struct hh_cache		*hh;
X 	atomic_t		refcnt;
@@ -155,7 +156,7 @@
X 	struct timer_list 	proxy_timer;
X 	struct sk_buff_head	proxy_queue;
X 	int			entries;
-	atomic_t		lock;
+	rwlock_t		lock;
X 	unsigned long		last_rand;
X 	struct neigh_parms	*parms_list;
X 	struct neigh_statistics	stats;
@@ -165,9 +166,12 @@
X 
X extern void			neigh_table_init(struct neigh_table *tbl);
X extern int			neigh_table_clear(struct neigh_table *tbl);
-extern struct neighbour		*__neigh_lookup(struct neigh_table *tbl,
-					       const void *pkey, struct device *dev,
-					       int creat);
+extern struct neighbour *	neigh_lookup(struct neigh_table *tbl,
+					     const void *pkey,
+					     struct device *dev);
+extern struct neighbour *	neigh_create(struct neigh_table *tbl,
+					     const void *pkey,
+					     struct device *dev);
X extern void			neigh_destroy(struct neighbour *neigh);
X extern int			__neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
X extern int			neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int arp);
@@ -226,16 +230,6 @@
X 		neigh->confirmed = jiffies;
X }
X 
-extern __inline__ struct neighbour *
-neigh_lookup(struct neigh_table *tbl, const void *pkey, struct device *dev)
-{
-	struct neighbour *neigh;
-	start_bh_atomic();
-	neigh = __neigh_lookup(tbl, pkey, dev, 0);
-	end_bh_atomic();
-	return neigh;
-}
-
X extern __inline__ int neigh_is_connected(struct neighbour *neigh)
X {
X 	return neigh->nud_state&NUD_CONNECTED;
@@ -254,17 +248,16 @@
X 	return 0;
X }
X 
-extern __inline__ void neigh_table_lock(struct neigh_table *tbl)
+extern __inline__ struct neighbour *
+__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct device *dev, int creat)
X {
-	atomic_inc(&tbl->lock);
-	synchronize_bh();
-}
+	struct neighbour *n = neigh_lookup(tbl, pkey, dev);
X 
-extern __inline__ void neigh_table_unlock(struct neigh_table *tbl)
-{
-	atomic_dec(&tbl->lock);
-}
+	if (n || !creat)
+		return n;
X 
+	return neigh_create(tbl, pkey, dev);
+}
X 
X #endif
X #endif
diff -u --recursive --new-file v2.3.5/linux/include/net/pkt_cls.h linux/include/net/pkt_cls.h
--- v2.3.5/linux/include/net/pkt_cls.h	Thu Mar 25 09:23:34 1999
+++ linux/include/net/pkt_cls.h	Wed Jun  9 14:45:36 1999
@@ -77,14 +77,11 @@
X 	return -1;
X }
X 
-extern __inline__ unsigned long cls_set_class(unsigned long *clp, unsigned long cl)
-{
-	cl = xchg(clp, cl);
-	synchronize_bh();
-	return cl;
-}
+
X 
X extern int register_tcf_proto_ops(struct tcf_proto_ops *ops);
X extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
+
+
X 
X #endif
diff -u --recursive --new-file v2.3.5/linux/include/net/pkt_sched.h linux/include/net/pkt_sched.h
--- v2.3.5/linux/include/net/pkt_sched.h	Thu Apr 22 19:45:19 1999
+++ linux/include/net/pkt_sched.h	Wed Jun  9 14:45:36 1999
@@ -66,9 +66,12 @@
X struct Qdisc_head
X {
X 	struct Qdisc_head *forw;
+	struct Qdisc_head *back;
X };
X 
X extern struct Qdisc_head qdisc_head;
+extern spinlock_t qdisc_runqueue_lock;
+extern rwlock_t qdisc_tree_lock;
X 
X struct Qdisc
X {
@@ -106,6 +109,46 @@
X 	int		refcnt;
X };
X 
+extern __inline__ void sch_tree_lock(struct Qdisc *q)
+{
+	write_lock(&qdisc_tree_lock);
+	spin_lock_bh(&q->dev->queue_lock);
+}
+
+extern __inline__ void sch_tree_unlock(struct Qdisc *q)
+{
+	spin_unlock_bh(&q->dev->queue_lock);
+	write_unlock(&qdisc_tree_lock);
+}
+
+extern __inline__ void tcf_tree_lock(struct tcf_proto *tp)
+{
+	write_lock(&qdisc_tree_lock);
+	spin_lock_bh(&tp->q->dev->queue_lock);
+}
+
+extern __inline__ void tcf_tree_unlock(struct tcf_proto *tp)
+{
+	spin_unlock_bh(&tp->q->dev->queue_lock);
+	write_unlock(&qdisc_tree_lock);
+}
+
+
+extern __inline__ unsigned long
+cls_set_class(struct tcf_proto *tp, unsigned long *clp, unsigned long cl)
+{
+	tcf_tree_lock(tp);
+	cl = xchg(clp, cl);
+	tcf_tree_unlock(tp);
+	return cl;
+}
+
+extern __inline__ unsigned long
+__cls_set_class(unsigned long *clp, unsigned long cl)
+{
+	return xchg(clp, cl);
+}
+
X 
X /* 
X    Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth
@@ -343,12 +386,14 @@
X 	u32		toks;
X 	u32		ptoks;
X 	psched_time_t	t_c;
+	spinlock_t	lock;
X 	struct qdisc_rate_table *R_tab;
X 	struct qdisc_rate_table *P_tab;
X 
X 	struct tc_stats	stats;
X };
X 
+extern int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st);
X extern void tcf_police_destroy(struct tcf_police *p);
X extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est);
X extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p);
@@ -384,20 +429,56 @@
X int tc_filter_init(void);
X int pktsched_init(void);
X 
-void qdisc_run_queues(void);
-int qdisc_restart(struct device *dev);
+extern void qdisc_run_queues(void);
+extern int qdisc_restart(struct device *dev);
+
+extern spinlock_t qdisc_runqueue_lock;
+
+/* Is it on run list? Reliable only under qdisc_runqueue_lock. */
+
+extern __inline__ int qdisc_on_runqueue(struct Qdisc *q)
+{
+	return q->h.forw != NULL;
+}
+
+/* Is run list not empty? Reliable only under qdisc_runqueue_lock. */
+
+extern __inline__ int qdisc_pending(void)
+{
+	return qdisc_head.forw != &qdisc_head;
+}
+
+/* Add qdisc to tail of run list. Called with BH, disabled on this CPU */
+
+extern __inline__ void qdisc_run(struct Qdisc *q)
+{
+	spin_lock(&qdisc_runqueue_lock);
+	if (!qdisc_on_runqueue(q)) {
+		q->h.forw = &qdisc_head;
+		q->h.back = qdisc_head.back;
+		qdisc_head.back->forw = &q->h;
+		qdisc_head.back = &q->h;
+	}
+	spin_unlock(&qdisc_runqueue_lock);
+}
+
+/* If the device is not throttled, restart it and add to run list.
+ * BH must be disabled on this CPU.
+ */
X 
X extern __inline__ void qdisc_wakeup(struct device *dev)
X {
X 	if (!dev->tbusy) {
-		struct Qdisc *q = dev->qdisc;
-		if (qdisc_restart(dev) && q->h.forw == NULL) {
-			q->h.forw = qdisc_head.forw;
-			qdisc_head.forw = &q->h;
-		}
+		spin_lock(&dev->queue_lock);
+		if (qdisc_restart(dev))
+			qdisc_run(dev->qdisc);
+		spin_unlock(&dev->queue_lock);
X 	}
X }
X 
+/* Calculate maximal size of packet seen by hard_start_xmit
+   routine of this device.
+ */
X extern __inline__ unsigned psched_mtu(struct device *dev)
X {
X 	unsigned mtu = dev->mtu;
diff -u --recursive --new-file v2.3.5/linux/include/net/route.h linux/include/net/route.h
--- v2.3.5/linux/include/net/route.h	Mon May 31 22:28:07 1999
+++ linux/include/net/route.h	Wed Jun  9 14:45:36 1999
@@ -35,13 +35,6 @@
X 
X #define RT_HASH_DIVISOR	    	256
X 
-/*
- * Prevents LRU trashing, entries considered equivalent,
- * if the difference between last use times is less then this number.
- */
-#define RT_CACHE_BUBBLE_THRESHOLD	(5*HZ)
-
-
X #define RTO_ONLINK	0x01
X #define RTO_TPROXY	0x80000000
X 
@@ -103,6 +96,7 @@
X };
X 
X extern struct ip_rt_acct ip_rt_acct[256];
+extern rwlock_t ip_rt_acct_lock;
X 
X extern void		ip_rt_init(void);
X extern void		ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
diff -u --recursive --new-file v2.3.5/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.3.5/linux/include/net/tcp.h	Mon May 31 22:28:07 1999
+++ linux/include/net/tcp.h	Tue Jun  8 23:04:46 1999
@@ -289,7 +289,7 @@
X #define TCP_PROBEWAIT_LEN (1*HZ)/* time to wait between probes when
X 				 * I've got something to write and
X 				 * there is no window			*/
-#define TCP_KEEPALIVE_TIME (180*60*HZ)		/* two hours */
+#define TCP_KEEPALIVE_TIME (120*60*HZ)		/* two hours */
X #define TCP_KEEPALIVE_PROBES	9		/* Max of 9 keepalive probes	*/
X #define TCP_KEEPALIVE_PERIOD ((75*HZ)>>2)	/* period of keepalive check	*/
X 
diff -u --recursive --new-file v2.3.5/linux/include/net/udp.h linux/include/net/udp.h
--- v2.3.5/linux/include/net/udp.h	Sun Nov 30 14:00:39 1997
+++ linux/include/net/udp.h	Tue Jun  8 17:58:03 1999
@@ -34,8 +34,14 @@
X 
X extern unsigned short udp_good_socknum(void);
X 
-#define UDP_NO_CHECK	0
+/* Note: this must match 'valbool' in sock_setsockopt */
+#define UDP_CSUM_NOXMIT		1
X 
+/* Used by SunRPC/xprt layer. */
+#define UDP_CSUM_NORCV		2
+
+/* Default, as per the RFC, is to always do csums. */
+#define UDP_CSUM_DEFAULT	0
X 
X extern struct proto udp_prot;
X 
diff -u --recursive --new-file v2.3.5/linux/include/scsi/scsicam.h linux/include/scsi/scsicam.h
--- v2.3.5/linux/include/scsi/scsicam.h	Thu Jun 12 15:29:27 1997
+++ linux/include/scsi/scsicam.h	Wed Jun  9 16:59:16 1999
@@ -14,4 +14,6 @@
X #define SCSICAM_H
X #include <linux/kdev_t.h>
X extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip);
+extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
+           unsigned int  *cyls, unsigned int *hds, unsigned int *secs);
X #endif /* def SCSICAM_H */
diff -u --recursive --new-file v2.3.5/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.3.5/linux/include/scsi/sg.h	Fri May  7 11:05:30 1999
+++ linux/include/scsi/sg.h	Mon Jun  7 16:20:36 1999
@@ -12,10 +12,16 @@
X *       Copyright (C) 1998, 1999 Douglas Gilbert
X 
X 
-    Version: 2.1.32 (990501)
-    This version for later 2.1.x series and 2.2.x kernels
+    Version: 2.1.34 (990603)
+    This version for later 2.1.x and 2.2.x series kernels
X     D. P. Gilbert (dgil...@interlog.com, do...@triode.net.au)
X 
+    Changes since 2.1.33 (990521)
+        - implement SG_SET_RESERVED_SIZE and associated memory re-org.
+        - add SG_NEXT_CMD_LEN to override SCSI command lengths
+        - add SG_GET_VERSION_NUM to get version expressed as an integer
+    Changes since 2.1.32 (990501)
+        - fix race condition in sg_read() and sg_open()
X     Changes since 2.1.31 (990327)
X         - add ioctls SG_GET_UNDERRUN_FLAG and _SET_. Change the default
X           to _not_ flag underruns (affects aic7xxx driver)
@@ -25,24 +31,6 @@
X     Changes since 2.1.30 (990320)
X         - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
X         -                increase max allowable mid-level pool usage
-    Changes since 2.1.21 (990315)
-        - skipped to 2.1.30 indicating interface change (revert to 2.1.9)
-        - remove attempt to accomodate cdrecord 1.8, will fix app
-        - keep SG_?ET_RESERVED_SIZE naming for clarity
-    Changes since 2.1.20 (990313)
-        - ommission: left out logic for SG_?ET_ALT_INTERFACE, now added
-    Changes since 2.1.9 (990309)
-        - skipped to version 2.1.20 to indicate some interface changes
-        - incorporate sg changes to make cdrecord 1.8 work (had its
-          own patches that were different from the original)
-        - change SG_?ET_BUFF_SIZE to SG_?ET_RESERVED_SIZE for clarity
-    Changes since 2.1.8 (990303)
-        - debug ">9" option dumps debug for _all_ active sg devices
-        - increase allowable dma pool usage + increase minimum threshhold
-        - pad out sg_scsi_id structure
-    Changes since 2.1.7 (990227)
-        - command queuing now "non-default" [back. compat. with cdparanoia]
-        - Tighten access on some ioctls
X 
X 
X     New features and changes:
@@ -52,24 +40,32 @@
X         - the SCSI target, host and driver status are returned
X           in unused fields of sg_header (maintaining its original size).
X         - asynchronous notification support added (SIGPOLL, SIGIO) for
-          read()s ( write()s should never block).
-        - pack_id logic added so read() can be made to wait for a specific
-          pack_id. 
+          read()s (write()s should never block).
+        - pack_id logic added so read() can wait for a specific pack_id. 
X         - uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a
X           pci scsi adapter).
X         - this driver no longer uses a single SG_BIG_BUFF sized buffer
-          obtained at driver/module init time. Rather it obtains a 
-          SG_SCATTER_SZ buffer when a fd is open()ed and frees it at
-          the corresponding release() (ie pr fd). Hence open() can return
-          ENOMEM! If write() request > SG_SCATTER_SZ bytes for data then
-          it can fail with ENOMEM as well (if so, scale back).
+          obtained at driver/module init time. Rather it tries to obtain a 
+          SG_DEF_RESERVED_SIZE buffer when a fd is open()ed and frees it
+          at the corresponding release() (ie per fd). Actually the "buffer"
+          may be a collection of buffers if scatter-gather is being used.
+        - add SG_SET_RESERVED_SIZE ioctl allowing the user to request a
+          large buffer for duration of current file descriptor's lifetime.
+        - SG_GET_RESERVED_SIZE ioctl can be used to find out how much
+          actually has been reserved.
+        - add SG_NEXT_CMD_LEN ioctl to override SCSI command length on
+          the next write() to this file descriptor.
+        - SG_GET_RESERVED_SIZE's presence as a symbol can be used for
+          compile time identification of the version 2 sg driver.
+          However, it is recommended that run time identification based on
+          calling the ioctl of the same name is a more flexible and
+          safer approach.
X         - adds several ioctl calls, see ioctl section below.
-        - SG_SCATTER_SZ's presence indicates this version of "sg" driver.
X  
X  Good documentation on the original "sg" device interface and usage can be
- found in the Linux HOWTO document: "SCSI Programming HOWTO" by Heiko
- Eissfeldt; last updated 7 May 1996. I will add more info on using the
- extensions in this driver as required. A quick summary:
+ found in the Linux HOWTO document: "SCSI Programming HOWTO" (version 0.5)
+ by Heiko Eissfeldt; last updated 7 May 1996. Here is a quick summary of
+ sg basics:
X  An SG device is accessed by writing SCSI commands plus any associated 
X  outgoing data to it; the resulting status codes and any incoming data
X  are then obtained by a read call. The device can be opened O_NONBLOCK
@@ -88,38 +84,37 @@
X  The given SCSI command has its LUN field overwritten internally by the
X  value associated with the device that has been opened.
X 
- Memory (RAM) is used within this driver for direct memory access (DMA)
- in transferring data to and from the SCSI device. The dreaded ENOMEM
- seems to be more prevalent under early 2.2.x kernels than under the
- 2.0.x kernel series. For a given (large) transfer the memory obtained by
- this driver must be contiguous or scatter-gather must be used (if
- supported by the adapter). [Furthermore, ISA SCSI adapters can only use
- memory below the 16MB level on a i386.]
- This driver tries hard to find some suitable memory before admitting
- defeat and returning ENOMEM. All is not lost if application writers
- then back off the amount they are requesting. The value returned by
- the SG_GET_RESERVED_SIZE ioctl is guaranteed to be available (one
- per fd). This driver does the following:
-   -  attempts to reserve a SG_SCATTER_SZ sized buffer on open(). The
-      actual amount reserved is given by the SG_GET_RESERVED_SIZE ioctl().
-   -  each write() needs to reserve a DMA buffer of the size of the
-      data buffer indicated (excluding sg_header and command overhead).
-      This buffer, depending on its size, adapter type (ISA or not) and
-      the amount of memory available will be obtained from the kernel
-      directly (get_free_pages or kmalloc) or the from the scsi mid-level
-      dma pool (taking care not to exhaust it).
-      If the buffer requested is > SG_SCATTER_SZ or memory is tight then
-      scatter-gather will be used if supported by the adapter.
-  -   write() will also attempt to use the buffer reserved on open()
-      if it is large enough.
- The above strategy ensures that a write() can always depend on a buffer 
- of the size indicated by the SG_GET_RESERVED_SIZE ioctl() (which could be
- 0, but at least the app knows things are tight in advance).
- Hence application writers can adopt quite aggressive strategies (e.g. 
- requesting 512KB) and scale them back in the face of ENOMEM errors.
- N.B. Queuing up commands also ties up kernel memory.
+ This device currently uses "indirect IO" in the sense that data is
+ DMAed into kernel buffers from the hardware and afterwards is
+ transferred into the user space (or vice versa if you are writing).
+ Transfer speeds or up to 20 to 30MBytes/sec have been measured using
+ indirect IO. For faster throughputs "direct IO" which cuts out the
+ double handling of data is required. This will also need a new interface.
+
+ Grabbing memory for those kernel buffers used in this driver for DMA may
+ cause the dreaded ENOMEM error. This error seems to be more prevalent 
+ under early 2.2.x kernels than under the 2.0.x kernel series. For a given 
+ (large) transfer the memory obtained by this driver must be contiguous or
+ scatter-gather must be used (if supported by the adapter). [Furthermore, 
+ ISA SCSI adapters can only use memory below the 16MB level on a i386.]
+
+ When a "sg" device is open()ed O_RDWR then this driver will attempt to
+ reserve a buffer of SG_DEF_RESERVED_SIZE that will be used by subsequent
+ write()s on this file descriptor as long as:
+    -  it is not already in use (eg when command queuing is in use)
+    -  the write() does not call for a buffer size larger than the
+       reserved size.
+ In these cases the write() will attempt to find the memory it needs for
+ DMA buffers dynamically and in the worst case will fail with ENOMEM.
+ The amount of memory actually reserved depends on various dynamic factors
+ and can be checked with the SG_GET_RESERVED_SIZE ioctl(). [In a very
+ tight memory situation it may yield 0!] The size of the reserved buffer
+ can be changed with the SG_SET_RESERVED_SIZE ioctl(). It should be
+ followed with a call to the SG_GET_RESERVED_SIZE ioctl() to find out how
+ much was actually reserved.
X 
- More documentation can be found at www.torque.net/sg
+ More documentation plus test and utility programs can be found at 
+ http://www.torque.net/sg
X */
X 
X #define SG_MAX_SENSE 16   /* too little, unlikely to change in 2.2.x */
@@ -129,7 +124,7 @@
X     int pack_len;    /* [o] reply_len (ie useless), ignored as input */
X     int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
X     int pack_id;     /* [io] id number of packet (use ints >= 0) */
-    int result;      /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */
+    int result;      /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
X     unsigned int twelve_byte:1; 
X         /* [i] Force 12 byte command length for group 6 & 7 commands  */
X     unsigned int target_status:5;   /* [o] scsi status from target */
@@ -154,9 +149,9 @@
X     int unused3;  
X } Sg_scsi_id;
X 
-/* ioctls  ( _GET_s yield result via 'int *' 3rd argument unless 
-            otherwise indicated */
-#define SG_SET_TIMEOUT 0x2201  /* unit: jiffies, 10ms on i386 */
+/* IOCTLs: ( _GET_s yield result via 'int *' 3rd argument unless 
+             otherwise indicated) */
+#define SG_SET_TIMEOUT 0x2201  /* unit: jiffies (10ms on i386) */
X #define SG_GET_TIMEOUT 0x2202  /* yield timeout as _return_ value */
X 
X #define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
@@ -165,23 +160,21 @@
X #define SG_SET_TRANSFORM 0x2204
X #define SG_GET_TRANSFORM 0x2205
X 
-#define SG_SET_RESERVED_SIZE 0x2275  /* currently ignored, future addition */
-/* Following yields buffer reserved by open(): 0 <= x <= SG_SCATTER_SZ */
-#define SG_GET_RESERVED_SIZE 0x2272
+#define SG_SET_RESERVED_SIZE 0x2275  /* request a new reserved buffer size */
+#define SG_GET_RESERVED_SIZE 0x2272  /* actual size of reserved buffer */
X 
X /* The following ioctl takes a 'Sg_scsi_id *' object as its 3rd argument. */
-#define SG_GET_SCSI_ID 0x2276   /* Yields fd's bus,chan,dev,lun+type */
+#define SG_GET_SCSI_ID 0x2276   /* Yields fd's bus, chan, dev, lun + type */
X /* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */
X 
-/* Override adapter setting and always DMA using low memory ( <16MB on i386).
-   Default is 0 (off - use adapter setting) */
+/* Override host setting and always DMA using low memory ( <16MB on i386) */
X #define SG_SET_FORCE_LOW_DMA 0x2279  /* 0-> use adapter setting, 1-> force */
X #define SG_GET_LOW_DMA 0x227a   /* 0-> use all ram for dma; 1-> low dma ram */
X 
X /* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which
X    will attempt to read that pack_id or block (or return EAGAIN). If 
X    pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0
-   (default) then pack_id ignored by read() and oldest readable fetched. */ 
+   then pack_id ignored by read() and oldest readable fetched. */ 
X #define SG_SET_FORCE_PACK_ID 0x227b
X #define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
X 
@@ -194,43 +187,47 @@
X /* Yields max scatter gather tablesize allowed by current host adapter */
X #define SG_GET_SG_TABLESIZE 0x227F  /* 0 implies can't do scatter gather */
X 
-/* Control whether sequencing per file descriptor (default) or per device */
-#define SG_GET_MERGE_FD 0x2274   /* 0-> per fd (default), 1-> per device */
+/* Control whether sequencing per file descriptor or per device */
+#define SG_GET_MERGE_FD 0x2274   /* 0-> per fd, 1-> per device */
X #define SG_SET_MERGE_FD 0x2273   /* Attempt to change sequencing state,
-  if more than 1 fd open on device, will fail with EBUSY */
+  if more than current fd open on device, will fail with EBUSY */
X 
X /* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q) */
X #define SG_GET_COMMAND_Q 0x2270   /* Yields 0 (queuing off) or 1 (on) */
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 21'
echo 'File patch-2.3.6 is continued in part 22'
echo 22 > _shar_seq_.tmp
#!/bin/sh
# this is part 22 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 22; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
X #define SG_SET_COMMAND_Q 0x2271   /* Change queuing state with 0 or 1 */
X 
-/* Get/set whether DMA underrun will cause an error (DID_ERROR) [this only
-   currently applies to the [much-used] aic7xxx driver) */
+/* Get/set whether DMA underrun will cause an error (DID_ERROR). This only
+   currently applies to the [much-used] aic7xxx driver. */
X #define SG_GET_UNDERRUN_FLAG 0x2280 /* Yields 0 (don't flag) or 1 (flag) */
X #define SG_SET_UNDERRUN_FLAG 0x2281 /* Change flag underrun state */
X 
+#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
+#define SG_NEXT_CMD_LEN 0x2283  /* override SCSI command length with given
+                   number on the next write() on this file descriptor */
+
+
+#define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
+/* Largest size (in bytes) a single scatter-gather list element can have.
+   The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on 
+   i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
+   by adapter then this value is the largest data block that can be
+   read/written by a single scsi command. The user can find the value of
+   PAGE_SIZE by calling getpagesize() defined in unistd.h . */
X 
X #define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
X #define SG_DEFAULT_RETRIES 1
X 
-/* Default modes, commented if they differ from original sg driver */
+/* Defaults, commented if they differ from original sg driver */
X #define SG_DEF_COMMAND_Q 0
X #define SG_DEF_MERGE_FD 0       /* was 1 -> per device sequencing */
X #define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
X #define SG_DEF_FORCE_PACK_ID 0
X #define SG_DEF_UNDERRUN_FLAG 0
+#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ
X 
X /* maximum outstanding requests, write() yields EDOM if exceeded */
X #define SG_MAX_QUEUE 16
X 
-#define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
-/* Largest size (in bytes) a single scatter-gather list element can have.
-   The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on 
-   i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
-   by adapter then this value is the largest data block that can be
-   read/written by a single scsi command. Max number of scatter-gather
-   list elements seems to be limited to 255. */
-
-#define SG_BIG_BUFF SG_SCATTER_SZ       /* for backward compatibility */
-/* #define SG_BIG_BUFF (SG_SCATTER_SZ * 8) */ /* =256KB, if you want */
+#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE    /* for backward compatibility */
X 
X #endif
diff -u --recursive --new-file v2.3.5/linux/ipc/msg.c linux/ipc/msg.c
--- v2.3.5/linux/ipc/msg.c	Fri May 14 18:55:30 1999
+++ linux/ipc/msg.c	Mon Jun  7 12:20:50 1999
@@ -8,6 +8,7 @@
X  * Fixed up the unchecked user space derefs
X  * Copyright (C) 1998 Alan Cox & Andi Kleen
X  *
+ * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dra...@iname.com>
X  */
X 
X #include <linux/malloc.h>
@@ -15,6 +16,7 @@
X #include <linux/interrupt.h>
X #include <linux/smp_lock.h>
X #include <linux/init.h>
+#include <linux/proc_fs.h>
X 
X #include <asm/uaccess.h>
X 
@@ -23,6 +25,9 @@
X static void freeque (int id);
X static int newque (key_t key, int msgflg);
X static int findkey (key_t key);
+#ifdef CONFIG_PROC_FS
+static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+#endif
X 
X static struct msqid_ds *msgque[MSGMNI];
X static int msgbytes = 0;
@@ -35,11 +40,18 @@
X void __init msg_init (void)
X {
X 	int id;
-	
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent;
+#endif
+
X 	for (id = 0; id < MSGMNI; id++) 
X 		msgque[id] = (struct msqid_ds *) IPC_UNUSED;
X 	msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
X 	init_waitqueue_head(&msg_lock);
+#ifdef CONFIG_PROC_FS
+	ent = create_proc_entry("sysvipc/msg", 0, 0);
+	ent->read_proc = sysvipc_msg_read_proc;
+#endif
X 	return;
X }
X 
@@ -492,3 +504,49 @@
X 	return err;
X }
X 
+#ifdef CONFIG_PROC_FS
+static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	off_t pos = 0;
+	off_t begin = 0;
+	int i, len = 0;
+
+	len += sprintf(buffer, "       key      msqid perms cbytes  qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n");
+
+	for(i = 0; i < MSGMNI; i++)
+		if(msgque[i] != IPC_UNUSED) {
+			len += sprintf(buffer + len, "%10d %10d  %4o  %5u %5u %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
+				msgque[i]->msg_perm.key,
+				msgque[i]->msg_perm.seq * MSGMNI + i,
+				msgque[i]->msg_perm.mode,
+				msgque[i]->msg_cbytes,
+				msgque[i]->msg_qnum,
+				msgque[i]->msg_lspid,
+				msgque[i]->msg_lrpid,
+				msgque[i]->msg_perm.uid,
+				msgque[i]->msg_perm.gid,
+				msgque[i]->msg_perm.cuid,
+				msgque[i]->msg_perm.cgid,
+				msgque[i]->msg_stime,
+				msgque[i]->msg_rtime,
+				msgque[i]->msg_ctime);
+
+			pos += len;
+			if(pos < offset) {
+				len = 0;
+				begin = pos;
+			}
+			if(pos > offset + length)
+				goto done;
+		}
+	*eof = 1;
+done:
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+	if(len > length)
+		len = length;
+	if(len < 0)
+		len = 0;
+	return len;
+}
+#endif
diff -u --recursive --new-file v2.3.5/linux/ipc/sem.c linux/ipc/sem.c
--- v2.3.5/linux/ipc/sem.c	Fri May 14 18:55:30 1999
+++ linux/ipc/sem.c	Mon Jun  7 12:20:50 1999
@@ -48,11 +48,14 @@
X  *      better but only get the semops right which only wait for zero or
X  *      increase. If there are decrement operations in the operations
X  *      array we do the same as before.
+ *
+ * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dra...@iname.com>
X  */
X 
X #include <linux/malloc.h>
X #include <linux/smp_lock.h>
X #include <linux/init.h>
+#include <linux/proc_fs.h>
X 
X #include <asm/uaccess.h>
X 
@@ -60,6 +63,9 @@
X static int newary (key_t, int, int);
X static int findkey (key_t key);
X static void freeary (int id);
+#ifdef CONFIG_PROC_FS
+static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+#endif
X 
X static struct semid_ds *semary[SEMMNI];
X static int used_sems = 0, used_semids = 0;
@@ -71,11 +77,18 @@
X void __init sem_init (void)
X {
X 	int i;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent;
+#endif
X 
X 	init_waitqueue_head(&sem_lock);
X 	used_sems = used_semids = max_semid = sem_seq = 0;
X 	for (i = 0; i < SEMMNI; i++)
X 		semary[i] = (struct semid_ds *) IPC_UNUSED;
+#ifdef CONFIG_PROC_FS
+	ent = create_proc_entry("sysvipc/sem", 0, 0);
+	ent->read_proc = sysvipc_sem_read_proc;
+#endif
X 	return;
X }
X 
@@ -785,3 +798,46 @@
X 	}
X 	current->semundo = NULL;
X }
+
+#ifdef CONFIG_PROC_FS
+static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	off_t pos = 0;
+	off_t begin = 0;
+	int i, len = 0;
+
+	len += sprintf(buffer, "       key      semid perms nsems   uid   gid  cuid  cgid      otime      ctime\n");
+
+	for(i = 0; i < SEMMNI; i++)
+		if(semary[i] != IPC_UNUSED) {
+			len += sprintf(buffer + len, "%10d %10d  %4o %5u %5u %5u %5u %5u %10lu %10lu\n",
+				semary[i]->sem_perm.key,
+				semary[i]->sem_perm.seq * SEMMNI + i,
+				semary[i]->sem_perm.mode,
+				semary[i]->sem_nsems,
+				semary[i]->sem_perm.uid,
+				semary[i]->sem_perm.gid,
+				semary[i]->sem_perm.cuid,
+				semary[i]->sem_perm.cgid,
+				semary[i]->sem_otime,
+				semary[i]->sem_ctime);
+
+			pos += len;
+			if(pos < offset) {
+				len = 0;
+	    		begin = pos;
+			}
+			if(pos > offset + length)
+				goto done;
+		}
+	*eof = 1;
+done:
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+	if(len > length)
+		len = length;
+	if(len < 0)
+		len = 0;
+	return len;
+}
+#endif
diff -u --recursive --new-file v2.3.5/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.5/linux/ipc/shm.c	Fri May 14 18:55:30 1999
+++ linux/ipc/shm.c	Mon Jun  7 12:20:50 1999
@@ -4,6 +4,8 @@
X  *         Many improvements/fixes by Bruno Haible.
X  * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
X  * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
+ *
+ * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dra...@iname.com>
X  */
X 
X #include <linux/malloc.h>
@@ -12,6 +14,7 @@
X #include <linux/smp_lock.h>
X #include <linux/init.h>
X #include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
X 
X #include <asm/uaccess.h>
X #include <asm/pgtable.h>
@@ -26,6 +29,9 @@
X static void shm_close (struct vm_area_struct *shmd);
X static unsigned long shm_nopage(struct vm_area_struct *, unsigned long, int);
X static int shm_swapout(struct vm_area_struct *, struct page *);
+#ifdef CONFIG_PROC_FS
+static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+#endif
X 
X static int shm_tot = 0; /* total number of shared memory pages */
X static int shm_rss = 0; /* number of shared memory pages that are in memory */
@@ -44,11 +50,18 @@
X void __init shm_init (void)
X {
X 	int id;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent;
+#endif
X 
X 	for (id = 0; id < SHMMNI; id++)
X 		shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
X 	shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
X 	init_waitqueue_head(&shm_lock);
+#ifdef CONFIG_PROC_FS
+	ent = create_proc_entry("sysvipc/shm", 0, 0);
+	ent->read_proc = sysvipc_shm_read_proc;
+#endif
X 	return;
X }
X 
@@ -762,3 +775,50 @@
X 					return;
X 				}
X }
+
+#ifdef CONFIG_PROC_FS
+static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	off_t pos = 0;
+	off_t begin = 0;
+	int i, len = 0;
+
+    	len += sprintf(buffer, "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime\n");
+
+    	for(i = 0; i < SHMMNI; i++)
+		if(shm_segs[i] != IPC_UNUSED) {
+	    		len += sprintf(buffer + len, "%10d %10d  %4o %10d %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n",
+			shm_segs[i]->u.shm_perm.key,
+			shm_segs[i]->u.shm_perm.seq * SHMMNI + i,
+			shm_segs[i]->u.shm_perm.mode,
+			shm_segs[i]->u.shm_segsz,
+			shm_segs[i]->u.shm_cpid,
+			shm_segs[i]->u.shm_lpid,
+			shm_segs[i]->u.shm_nattch,
+			shm_segs[i]->u.shm_perm.uid,
+			shm_segs[i]->u.shm_perm.gid,
+			shm_segs[i]->u.shm_perm.cuid,
+			shm_segs[i]->u.shm_perm.cgid,
+			shm_segs[i]->u.shm_atime,
+			shm_segs[i]->u.shm_dtime,
+			shm_segs[i]->u.shm_ctime);
+
+			pos += len;
+			if(pos < offset) {
+				len = 0;
+				begin = pos;
+			}
+			if(pos > offset + length)
+				goto done;
+		}
+	*eof = 1;
+done:
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+	if(len > length)
+		len = length;
+	if(len < 0)
+		len = 0;
+	return len;
+}
+#endif
diff -u --recursive --new-file v2.3.5/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.5/linux/kernel/ksyms.c	Mon May 17 09:55:23 1999
+++ linux/kernel/ksyms.c	Tue Jun  8 10:47:58 1999
@@ -82,6 +82,7 @@
X /* process memory management */
X EXPORT_SYMBOL(do_mmap);
X EXPORT_SYMBOL(do_munmap);
+EXPORT_SYMBOL(do_brk);
X EXPORT_SYMBOL(exit_mm);
X EXPORT_SYMBOL(exit_files);
X EXPORT_SYMBOL(exit_fs);
@@ -345,7 +346,7 @@
X 
X /* Program loader interfaces */
X EXPORT_SYMBOL(setup_arg_pages);
-EXPORT_SYMBOL(copy_strings);
+EXPORT_SYMBOL(copy_strings_kernel);
X EXPORT_SYMBOL(do_execve);
X EXPORT_SYMBOL(flush_old_exec);
X EXPORT_SYMBOL(open_dentry);
diff -u --recursive --new-file v2.3.5/linux/kernel/signal.c linux/kernel/signal.c
--- v2.3.5/linux/kernel/signal.c	Mon May 31 22:28:07 1999
+++ linux/kernel/signal.c	Mon Jun  7 16:14:06 1999
@@ -11,6 +11,7 @@
X #include <linux/unistd.h>
X #include <linux/smp_lock.h>
X #include <linux/init.h>
+#include <linux/sched.h>
X 
X #include <asm/uaccess.h>
X 
@@ -324,7 +325,7 @@
X 
X 		if (nr_queued_signals < max_queued_signals) {
X 			q = (struct signal_queue *)
-			    kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL);
+			    kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
X 		}
X 		
X 		if (q) {
@@ -417,6 +418,7 @@
X 	if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
X 		t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
X 	sigdelset(&t->blocked, sig);
+	recalc_sigpending(t);
X 	spin_unlock_irqrestore(&t->sigmask_lock, flags);
X 
X 	return send_sig_info(sig, info, t);
diff -u --recursive --new-file v2.3.5/linux/kernel/sys.c linux/kernel/sys.c
--- v2.3.5/linux/kernel/sys.c	Fri May 14 18:55:30 1999
+++ linux/kernel/sys.c	Mon Jun  7 16:17:59 1999
@@ -901,6 +901,8 @@
X 		return -EINVAL;
X 	if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
X 		return -EFAULT;
+	if (new_rlim.rlim_cur < 0 || new_rlim.rlim_max < 0)
+		return -EINVAL;
X 	old_rlim = current->rlim + resource;
X 	if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
X 	     (new_rlim.rlim_max > old_rlim->rlim_max)) &&
diff -u --recursive --new-file v2.3.5/linux/mm/memory.c linux/mm/memory.c
--- v2.3.5/linux/mm/memory.c	Mon May 31 22:28:07 1999
+++ linux/mm/memory.c	Tue Jun  8 14:09:57 1999
@@ -543,19 +543,6 @@
X }
X 
X /*
- * sanity-check function..
- */
-static void put_page(pte_t * page_table, pte_t pte)
-{
-	if (!pte_none(*page_table)) {
-		free_page_and_swap_cache(pte_page(pte));
-		return;
-	}
-/* no need for flush_tlb */
-	set_pte(page_table, pte);
-}
-
-/*
X  * This routine is used to map in a page into an address space: needed by
X  * execve() for the initial stack and environment pages.
X  */
@@ -612,21 +599,15 @@
X  * and potentially makes it more efficient.
X  */
X static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
-	unsigned long address, pte_t *page_table)
+	unsigned long address, pte_t *page_table, pte_t pte)
X {
-	pte_t pte;
X 	unsigned long old_page, new_page;
X 	struct page * page_map;
X 	
-	pte = *page_table;
X 	new_page = __get_free_page(GFP_USER);
-	/* Did someone else copy this page for us while we slept? */
+	/* Did swap_out() unmapped the protected page while we slept? */
X 	if (pte_val(*page_table) != pte_val(pte))
X 		goto end_wp_page;
-	if (!pte_present(pte))
-		goto end_wp_page;
-	if (pte_write(pte))
-		goto end_wp_page;
X 	old_page = pte_page(pte);
X 	if (MAP_NR(old_page) >= max_mapnr)
X 		goto bad_wp_page;
@@ -650,36 +631,42 @@
X 		delete_from_swap_cache(page_map);
X 		/* FallThrough */
X 	case 1:
-		/* We can release the kernel lock now.. */
-		unlock_kernel();
-
X 		flush_cache_page(vma, address);
X 		set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
X 		flush_tlb_page(vma, address);
X end_wp_page:
+		/*
+		 * We can release the kernel lock now.. Now swap_out will see
+		 * a dirty page and so won't get confused and flush_tlb_page
+		 * won't SMP race. -Andrea
+		 */
+		unlock_kernel();
+
X 		if (new_page)
X 			free_page(new_page);
X 		return 1;
X 	}
X 		
-	unlock_kernel();
X 	if (!new_page)
-		return 0;
+		goto no_new_page;
X 
-	if (PageReserved(mem_map + MAP_NR(old_page)))
+	if (PageReserved(page_map))
X 		++vma->vm_mm->rss;
X 	copy_cow_page(old_page,new_page);
X 	flush_page_to_ram(old_page);
X 	flush_page_to_ram(new_page);
X 	flush_cache_page(vma, address);
X 	set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
-	free_page(old_page);
X 	flush_tlb_page(vma, address);
+	unlock_kernel();
+	__free_page(page_map);
X 	return 1;
X 
X bad_wp_page:
X 	printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
X 	send_sig(SIGKILL, tsk, 1);
+no_new_page:
+	unlock_kernel();
X 	if (new_page)
X 		free_page(new_page);
X 	return 0;
@@ -816,7 +803,7 @@
X 		tsk->min_flt++;
X 		flush_page_to_ram(page);
X 	}
-	put_page(page_table, entry);
+	set_pte(page_table, entry);
X 	return 1;
X }
X 
@@ -874,7 +861,7 @@
X 	} else if (atomic_read(&mem_map[MAP_NR(page)].count) > 1 &&
X 		   !(vma->vm_flags & VM_SHARED))
X 		entry = pte_wrprotect(entry);
-	put_page(page_table, entry);
+	set_pte(page_table, entry);
X 	/* no need to invalidate: a not-present page shouldn't be cached */
X 	return 1;
X }
@@ -908,7 +895,7 @@
X 	flush_tlb_page(vma, address);
X 	if (write_access) {
X 		if (!pte_write(entry))
-			return do_wp_page(tsk, vma, address, pte);
+			return do_wp_page(tsk, vma, address, pte, entry);
X 
X 		entry = pte_mkdirty(entry);
X 		set_pte(pte, entry);
diff -u --recursive --new-file v2.3.5/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.5/linux/mm/mmap.c	Mon May 31 22:28:07 1999
+++ linux/mm/mmap.c	Mon Jun  7 11:15:33 1999
@@ -84,6 +84,13 @@
X 	}
X }
X 
+/*
+ *  sys_brk() for the most part doesn't need the global kernel
+ *  lock, except when an application is doing something nasty
+ *  like trying to un-brk an area that has already been mapped
+ *  to a regular file.  in this case, the unmapping will need
+ *  to invoke file system routines that need the global lock.
+ */
X asmlinkage unsigned long sys_brk(unsigned long brk)
X {
X 	unsigned long rlim, retval;
@@ -92,20 +99,6 @@
X 
X 	down(&mm->mmap_sem);
X 
-	/*
-	 * This lock-kernel is one of the main contention points for
-	 * certain normal loads.  And it really should not be here: almost
-	 * everything in brk()/mmap()/munmap() is protected sufficiently by
-	 * the mmap semaphore that we got above.
-	 *
-	 * We should move this into the few things that really want the
-	 * lock, namely anything that actually touches a file descriptor
-	 * etc.  We can do all the normal anonymous mapping cases without
-	 * ever getting the lock at all - the actual memory management
-	 * code is already completely thread-safe.
-	 */
-	lock_kernel();
-
X 	if (brk < mm->end_code)
X 		goto out;
X 	newbrk = PAGE_ALIGN(brk);
@@ -134,15 +127,12 @@
X 		goto out;
X 
X 	/* Ok, looks good - let it rip. */
-	if (do_mmap(NULL, oldbrk, newbrk-oldbrk,
-		   PROT_READ|PROT_WRITE|PROT_EXEC,
-		   MAP_FIXED|MAP_PRIVATE, 0) != oldbrk)
+	if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
X 		goto out;
X set_brk:
X 	mm->brk = brk;
X out:
X 	retval = mm->brk;
-	unlock_kernel();
X 	up(&mm->mmap_sem);
X 	return retval;
X }
@@ -470,6 +460,28 @@
X 	return NULL;
X }
X 
+struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
+{
+	struct vm_area_struct * vma;
+	unsigned long start;
+
+	addr &= PAGE_MASK;
+	vma = find_vma(tsk->mm,addr);
+	if (!vma)
+		return NULL;
+	if (vma->vm_start <= addr)
+		return vma;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		return NULL;
+	start = vma->vm_start;
+	if (expand_stack(vma, addr))
+		return NULL;
+	if (vma->vm_flags & VM_LOCKED) {
+		make_pages_present(addr, start);
+	}
+	return vma;
+}
+
X /* Normal function to fix up a mapping
X  * This function is the default for when an area has no specific
X  * function.  This may be used as part of a more specific routine.
@@ -665,6 +677,8 @@
X 		end = end > mpnt->vm_end ? mpnt->vm_end : end;
X 		size = end - st;
X 
+		lock_kernel();
+
X 		if (mpnt->vm_ops && mpnt->vm_ops->unmap)
X 			mpnt->vm_ops->unmap(mpnt, st, size);
X 
@@ -679,6 +693,8 @@
X 		 * Fix the mapping, and free the old area if it wasn't reused.
X 		 */
X 		extra = unmap_fixup(mpnt, st, size, extra);
+
+		unlock_kernel();
X 	}
X 
X 	/* Release the extra vma struct if it wasn't used */
@@ -696,11 +712,85 @@
X 	int ret;
X 
X 	down(¤t->mm->mmap_sem);
-	lock_kernel();
X ret = do_munmap(addr, len);
-	unlock_kernel();
X 	up(¤t->mm->mmap_sem);
X 	return ret;
+}
+
+/*
+ *  this is really a simplified "do_mmap".  it only handles
+ *  anonymous maps.  eventually we may be able to do some
+ *  brk-specific accounting here.
+ */
+unsigned long do_brk(unsigned long addr, unsigned long len)
+{
+	struct mm_struct * mm = current->mm;
+	struct vm_area_struct * vma;
+	unsigned long flags, retval;
+
+	/*
+	 * mlock MCL_FUTURE?
+	 */
+	if (mm->def_flags & VM_LOCKED) {
+		unsigned long locked = mm->locked_vm << PAGE_SHIFT;
+		locked += len;
+		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
+			return -EAGAIN;
+	}
+
+	/*
+	 * Clear old maps.  this also does some error checking for us
+	 */
+	retval = do_munmap(addr, len);
+	if (retval != 0)
+		return retval;
+
+	/* Check against address space limits *after* clearing old maps... */
+	if ((mm->total_vm << PAGE_SHIFT) + len
+	    > current->rlim[RLIMIT_AS].rlim_cur)
+		return -ENOMEM;
+
+	if (mm->map_count > MAX_MAP_COUNT)
+		return -ENOMEM;
+
+	if (!vm_enough_memory(len >> PAGE_SHIFT))
+		return -ENOMEM;
+
+	/*
+	 * create a vma struct for an anonymous mapping
+	 */
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (!vma)
+		return -ENOMEM;
+
+	vma->vm_mm = mm;
+	vma->vm_start = addr;
+	vma->vm_end = addr + len;
+	vma->vm_flags = vm_flags(PROT_READ|PROT_WRITE|PROT_EXEC,
+				MAP_FIXED|MAP_PRIVATE) | mm->def_flags;
+
+	vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
+	vma->vm_ops = NULL;
+	vma->vm_offset = 0;
+	vma->vm_file = NULL;
+	vma->vm_pte = 0;
+
+	/*
+	 * merge_segments may merge our vma, so we can't refer to it
+	 * after the call.  Save the values we need now ...
+	 */
+	flags = vma->vm_flags;
+	addr = vma->vm_start;
+	insert_vm_struct(mm, vma);
+	merge_segments(mm, vma->vm_start, vma->vm_end);
+	
+	mm->total_vm += len >> PAGE_SHIFT;
+	if (flags & VM_LOCKED) {
+		mm->locked_vm += len >> PAGE_SHIFT;
+		make_pages_present(addr, addr + len);
+	}
+	return addr;
X }
X 
X /* Build the AVL tree corresponding to the VMA list. */
diff -u --recursive --new-file v2.3.5/linux/mm/mremap.c linux/mm/mremap.c
--- v2.3.5/linux/mm/mremap.c	Sun Nov 22 09:38:19 1998
+++ linux/mm/mremap.c	Thu Jun  3 23:15:29 1999
@@ -134,12 +134,14 @@
X 			new_vma->vm_start = new_addr;
X 			new_vma->vm_end = new_addr+new_len;
X 			new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
+			lock_kernel();
X 			if (new_vma->vm_file)
X 				new_vma->vm_file->f_count++;
X 			if (new_vma->vm_ops && new_vma->vm_ops->open)
X 				new_vma->vm_ops->open(new_vma);
X 			insert_vm_struct(current->mm, new_vma);
X 			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
+			unlock_kernel();
X 			do_munmap(addr, old_len);
X 			current->mm->total_vm += new_len >> PAGE_SHIFT;
X 			if (new_vma->vm_flags & VM_LOCKED) {
@@ -166,7 +168,6 @@
X 	unsigned long ret = -EINVAL;
X 
X 	down(¤t->mm->mmap_sem);
-	lock_kernel();
X 	if (addr & ~PAGE_MASK)
X 		goto out;
X 	old_len = PAGE_ALIGN(old_len);
@@ -239,7 +240,6 @@
X 	else
X 		ret = -ENOMEM;
X out:
-	unlock_kernel();
X 	up(¤t->mm->mmap_sem);
X 	return ret;
X }
diff -u --recursive --new-file v2.3.5/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.5/linux/mm/swapfile.c	Mon May 31 22:28:07 1999
+++ linux/mm/swapfile.c	Mon Jun  7 16:20:36 1999
@@ -5,6 +5,7 @@
X  *  Swap reorganised 29.12.95, Stephen Tweedie
X  */
X 
+#include <linux/config.h>
X #include <linux/malloc.h>
X #include <linux/smp_lock.h>
X #include <linux/kernel_stat.h>
@@ -573,7 +574,7 @@
X 	} else if (S_ISREG(swap_dentry->d_inode->i_mode)) {
X 		error = -EBUSY;
X 		for (i = 0 ; i < nr_swapfiles ; i++) {
-			if (i == type)
+			if (i == type || !swap_info[i].swap_file)
X 				continue;
X 			if (swap_dentry->d_inode == swap_info[i].swap_file->d_inode)
X 				goto bad_swap;
diff -u --recursive --new-file v2.3.5/linux/net/core/dev.c linux/net/core/dev.c
--- v2.3.5/linux/net/core/dev.c	Wed Jun  2 14:44:39 1999
+++ linux/net/core/dev.c	Wed Jun  9 14:45:36 1999
@@ -263,13 +263,13 @@
X {
X 	struct device *dev;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if (strcmp(dev->name, name) == 0)
X 			goto out;
X 	}
X out:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	return dev;
X }
X 
@@ -277,13 +277,13 @@
X {
X 	struct device *dev;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if (dev->ifindex == ifindex)
X 			goto out;
X 	}
X out:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	return dev;
X }
X 
@@ -291,14 +291,14 @@
X {
X 	struct device *dev;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if (dev->type == type &&
X 		    memcmp(dev->dev_addr, ha, dev->addr_len) == 0)
X 			goto out;
X 	}
X out:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	return dev;
X }
X 
@@ -321,7 +321,7 @@
X 	}
X 	return -ENFILE;	/* Over 100 of the things .. bail out! */
X }
- 
+
X struct device *dev_alloc(const char *name, int *err)
X {
X 	struct device *dev=kmalloc(sizeof(struct device)+16, GFP_KERNEL);
@@ -387,9 +387,6 @@
X 	if (dev->flags&IFF_UP)
X 		return 0;
X 
-	/* Setup the lock before we open the faucet. */
-	spin_lock_init(&dev->xmit_lock);
-
X 	/*
X 	 *	Call device private open method
X 	 */
@@ -452,10 +449,10 @@
X 	if (dev) {
X 		dev_do_clear_fastroute(dev);
X 	} else {
-		read_lock_bh(&dev_base_lock);
+		read_lock(&dev_base_lock);
X 		for (dev = dev_base; dev; dev = dev->next)
X 			dev_do_clear_fastroute(dev);
-		read_unlock_bh(&dev_base_lock);
+		read_unlock(&dev_base_lock);
X 	}
X }
X #endif
@@ -596,59 +593,61 @@
X 	struct device *dev = skb->dev;
X 	struct Qdisc  *q;
X 
-#ifdef CONFIG_NET_PROFILE
-	start_bh_atomic();
-	NET_PROFILE_ENTER(dev_queue_xmit);
-#endif
-
-	spin_lock_bh(&dev->xmit_lock);
+	/* Grab device queue */
+	spin_lock_bh(&dev->queue_lock);
X 	q = dev->qdisc;
X 	if (q->enqueue) {
X 		q->enqueue(skb, q);
-		qdisc_wakeup(dev);
-		spin_unlock_bh(&dev->xmit_lock);
X 
-#ifdef CONFIG_NET_PROFILE
-	        NET_PROFILE_LEAVE(dev_queue_xmit);
-		end_bh_atomic();
-#endif
+		/* If the device is not busy, kick it.
+		 * Otherwise or if queue is not empty after kick,
+		 * add it to run list.
+		 */
+		if (dev->tbusy || qdisc_restart(dev))
+			qdisc_run(dev->qdisc);
X 
+		spin_unlock_bh(&dev->queue_lock);
X 		return 0;
X 	}
+	spin_unlock_bh(&dev->queue_lock);
X 
X 	/* The device has no queue. Common case for software devices:
X 	   loopback, all the sorts of tunnels...
X 
-	   Really, it is unlikely that bh protection is necessary here:
-	   virtual devices do not generate EOI events.
-	   However, it is possible, that they rely on bh protection
+	   Really, it is unlikely that xmit_lock protection is necessary here.
+	   (f.e. loopback and IP tunnels are clean ignoring statistics counters.)
+	   However, it is possible, that they rely on protection
X 	   made by us here.
+
+	   Check this and shot the lock. It is not prone from deadlocks.
+	   Either shot noqueue qdisc, it is even simpler 8)
X 	 */
X 	if (dev->flags&IFF_UP) {
X 		if (netdev_nit) 
X 			dev_queue_xmit_nit(skb,dev);
-		if (dev->hard_start_xmit(skb, dev) == 0) {
-			spin_unlock_bh(&dev->xmit_lock);
-
-#ifdef CONFIG_NET_PROFILE
-			NET_PROFILE_LEAVE(dev_queue_xmit);
-			end_bh_atomic();
-#endif
X 
-			return 0;
+		local_bh_disable();
+		if (dev->xmit_lock_owner != smp_processor_id()) {
+			spin_lock(&dev->xmit_lock);
+			dev->xmit_lock_owner = smp_processor_id();
+			if (dev->hard_start_xmit(skb, dev) == 0) {
+				dev->xmit_lock_owner = -1;
+				spin_unlock_bh(&dev->xmit_lock);
+				return 0;
+			}
+			dev->xmit_lock_owner = -1;
+			spin_unlock_bh(&dev->xmit_lock);
+			if (net_ratelimit())
+				printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name);
+		} else {
+			/* Recursion is detected! It is possible, unfortunately */
+			local_bh_enable();
+			if (net_ratelimit())
+				printk(KERN_DEBUG "Dead loop on virtual device %s, fix it urgently!\n", dev->name);
X 		}
-		if (net_ratelimit())
-			printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name);
X 	}
-	spin_unlock_bh(&dev->xmit_lock);
X 
X 	kfree_skb(skb);
-
-#ifdef CONFIG_NET_PROFILE
-	NET_PROFILE_LEAVE(dev_queue_xmit);
-	end_bh_atomic();
-#endif
-
X 	return 0;
X }
X 
@@ -660,9 +659,6 @@
X int netdev_dropping = 0;
X int netdev_max_backlog = 300;
X atomic_t netdev_rx_dropped;
-#ifdef CONFIG_CPU_IS_SLOW
-int net_cpu_congestion;
-#endif
X 
X #ifdef CONFIG_NET_HW_FLOWCONTROL
X int netdev_throttle_events;
@@ -852,14 +848,6 @@
X 	struct packet_type *pt_prev;
X 	unsigned short type;
X 	unsigned long start_time = jiffies;
-#ifdef CONFIG_CPU_IS_SLOW
-	static unsigned long start_busy = 0;
-	static unsigned long ave_busy = 0;
-
-	if (start_busy == 0)
-		start_busy = start_time;
-	net_cpu_congestion = ave_busy>>8;
-#endif
X 
X 	NET_PROFILE_ENTER(net_bh);
X 	/*
@@ -869,9 +857,9 @@
X 	 *	latency on a transmit interrupt bh.
X 	 */
X 
-	if (qdisc_head.forw != &qdisc_head)
+	if (qdisc_pending())
X 		qdisc_run_queues();
-  
+
X 	/*
X 	 *	Any data left to process. This may occur because a
X 	 *	mark_bh() is done after we empty the queue including
@@ -899,19 +887,6 @@
X 		 */
X 		skb = skb_dequeue(&backlog);
X 
-#ifdef CONFIG_CPU_IS_SLOW
-		if (ave_busy > 128*16) {
-			kfree_skb(skb);
-			while ((skb = skb_dequeue(&backlog)) != NULL)
-				kfree_skb(skb);
-			break;
-		}
-#endif
-
-
-#if 0
-		NET_PROFILE_SKB_PASSED(skb, net_bh_skb);
-#endif
X #ifdef CONFIG_NET_FASTROUTE
X 		if (skb->pkt_type == PACKET_FASTROUTE) {
X 			dev_queue_xmit(skb);
@@ -1022,16 +997,9 @@
X 	 *	One last output flush.
X 	 */
X 
-	if (qdisc_head.forw != &qdisc_head)
+	if (qdisc_pending())
X 		qdisc_run_queues();
X 
-#ifdef  CONFIG_CPU_IS_SLOW
-        if (1) {
-		unsigned long start_idle = jiffies;
-		ave_busy += ((start_idle - start_busy)<<3) - (ave_busy>>4);
-		start_busy = 0;
-	}
-#endif
X #ifdef CONFIG_NET_HW_FLOWCONTROL
X 	if (netdev_dropping)
X 		netdev_wakeup();
@@ -1065,14 +1033,6 @@
X  */
X 
X /*
- *	This call is useful, but I'd remove it too.
- *
- *	The reason is purely aestetical, it is the only call
- *	from SIOC* family using struct ifreq in reversed manner.
- *	Besides that, it is pretty silly to put "drawing" facility
- *	to kernel, it is useful only to print ifindices
- *	in readable form, is not it? --ANK
- *
X  *	We need this ioctl for efficient implementation of the
X  *	if_indextoname() function required by the IPv6 API.  Without
X  *	it, we would have to search all the interfaces to find a
@@ -1138,7 +1098,7 @@
X 	 */
X 
X 	total = 0;
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		for (i=0; i<NPROTO; i++) {
X 			if (gifconf_list[i]) {
@@ -1152,7 +1112,7 @@
X 			}
X 		}
X   	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	if(pos != NULL) {
X 		int err = copy_to_user(ifc.ifc_buf, pos, total);
@@ -1232,7 +1192,7 @@
X 	len+=size;
X 	
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		size = sprintf_stats(buffer+len, dev);
X 		len+=size;
@@ -1245,7 +1205,7 @@
X 		if(pos>offset+length)
X 			break;
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	
X 	*start=buffer+(offset-begin);	/* Start of wanted data */
X 	len-=(offset-begin);		/* Start slop */
@@ -1347,7 +1307,7 @@
X 	pos+=size;
X 	len+=size;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for(dev = dev_base; dev != NULL; dev = dev->next) {
X 		size = sprintf_wireless_stats(buffer+len, dev);
X 		len+=size;
@@ -1360,7 +1320,7 @@
X 		if(pos > offset + length)
X 			break;
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	*start = buffer + (offset - begin);	/* Start of wanted data */
X 	len -= (offset - begin);		/* Start slop */
@@ -1736,11 +1696,10 @@
X 				if (IW_IS_SET(cmd)) {
X 					if (!suser())
X 						return -EPERM;
-					rtnl_lock();
X 				}
+				rtnl_lock();
X 				ret = dev_ifsioc(&ifr, cmd);
-				if (IW_IS_SET(cmd))
-					rtnl_unlock();
+				rtnl_unlock();
X 				if (!ret && IW_IS_GET(cmd) &&
X 				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
X 					return -EFAULT;
@@ -1769,6 +1728,10 @@
X {
X 	struct device *d, **dp;
X 
+	spin_lock_init(&dev->queue_lock);
+	spin_lock_init(&dev->xmit_lock);
+	dev->xmit_lock_owner = -1;
+
X 	if (dev_boot_phase) {
X 		/* This is NOT bug, but I am not sure, that all the
X 		   devices, initialized before netdev module is started
@@ -1784,14 +1747,13 @@
X 		printk(KERN_INFO "early initialization of device %s is deferred\n", dev->name);
X 
X 		/* Check for existence, and append to tail of chain */
-		write_lock_bh(&dev_base_lock);
X 		for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
X 			if (d == dev || strcmp(d->name, dev->name) == 0) {
-				write_unlock_bh(&dev_base_lock);
X 				return -EEXIST;
X 			}
X 		}
X 		dev->next = NULL;
+		write_lock_bh(&dev_base_lock);
X 		*dp = dev;
X 		write_unlock_bh(&dev_base_lock);
X 		return 0;
@@ -1803,24 +1765,22 @@
X 	if (dev->init && dev->init(dev) != 0)
X 		return -EIO;
X 
+	dev->ifindex = dev_new_index();
+	if (dev->iflink == -1)
+		dev->iflink = dev->ifindex;
+
X 	/* Check for existence, and append to tail of chain */
-	write_lock_bh(&dev_base_lock);
X 	for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
X 		if (d == dev || strcmp(d->name, dev->name) == 0) {
-			write_unlock_bh(&dev_base_lock);
X 			return -EEXIST;
X 		}
X 	}
X 	dev->next = NULL;
X 	dev_init_scheduler(dev);
+	write_lock_bh(&dev_base_lock);
X 	*dp = dev;
X 	write_unlock_bh(&dev_base_lock);
X 
-	dev->ifindex = -1;
-	dev->ifindex = dev_new_index();
-	if (dev->iflink == -1)
-		dev->iflink = dev->ifindex;
-
X 	/* Notify protocols, that a new device appeared. */
X 	notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
X 
@@ -1831,15 +1791,35 @@
X {
X 	struct device *d, **dp;
X 
-	if (dev_boot_phase == 0) {
-		/* If device is running, close it.
-		   It is very bad idea, really we should
-		   complain loudly here, but random hackery
-		   in linux/drivers/net likes it.
-		 */
-		if (dev->flags & IFF_UP)
-			dev_close(dev);
+	/* If device is running, close it first. */
+	if (dev->flags & IFF_UP)
+		dev_close(dev);
X 
+	/* And unlink it from device chain. */
+	for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) {
+		if (d == dev) {
+			write_lock_bh(&dev_base_lock);
+			*dp = d->next;
+			write_unlock_bh(&dev_base_lock);
+
+			/* Sorry. It is known "feature". The race is clear.
+			   Keep it after device reference counting will
+			   be complete.
+			 */
+			synchronize_bh();
+			break;
+		}
+	}
+	if (d == NULL)
+		return -ENODEV;
+
+	/* It is "synchronize_bh" to those of guys, who overslept
+	   in skb_alloc/page fault etc. that device is off-line.
+	   Again, it can be removed only if devices are refcounted.
+	 */
+	dev_lock_wait();
+
+	if (dev_boot_phase == 0) {
X #ifdef CONFIG_NET_FASTROUTE
X 		dev_clear_fastroute(dev);
X #endif
@@ -1856,27 +1836,11 @@
X 		 *	Flush the multicast chain
X 		 */
X 		dev_mc_discard(dev);
-
-		/* To avoid pointers looking to nowhere,
-		   we wait for end of critical section */
-		dev_lock_wait();
X 	}
X 
-	/* And unlink it from device chain. */
-	write_lock_bh(&dev_base_lock);
-	for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) {
-		if (d == dev) {
-			*dp = d->next;
-			d->next = NULL;
-			write_unlock_bh(&dev_base_lock);
-
-			if (dev->destructor)
-				dev->destructor(dev);
-			return 0;
-		}
-	}
-	write_unlock_bh(&dev_base_lock);
-	return -ENODEV;
+	if (dev->destructor)
+		dev->destructor(dev);
+	return 0;
X }
X 
X 
@@ -2018,16 +1982,24 @@
X 	 *	If the call to dev->init fails, the dev is removed
X 	 *	from the chain disconnecting the device until the
X 	 *	next reboot.
+	 *
+	 *	NB At boot phase networking is dead. No locking is required.
+	 *	But we still preserve dev_base_lock for sanity.
X 	 */
X 
X 	dp = &dev_base;
X 	while ((dev = *dp) != NULL) {
+		spin_lock_init(&dev->queue_lock);
+		spin_lock_init(&dev->xmit_lock);
+		dev->xmit_lock_owner = -1;
X 		dev->iflink = -1;
X 		if (dev->init && dev->init(dev)) {
X 			/*
X 			 *	It failed to come up. Unhook it.
X 			 */
+			write_lock_bh(&dev_base_lock);
X 			*dp = dev->next;
+			write_unlock_bh(&dev_base_lock);
X 		} else {
X 			dp = &dev->next;
X 			dev->ifindex = dev_new_index();
@@ -2055,6 +2027,7 @@
X 
X 	dev_boot_phase = 0;
X 
+	dst_init();
X 	dev_mcast_init();
X 
X #ifdef CONFIG_IP_PNP
diff -u --recursive --new-file v2.3.5/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c
--- v2.3.5/linux/net/core/dev_mcast.c	Mon May 31 22:28:07 1999
+++ linux/net/core/dev_mcast.c	Wed Jun  9 14:45:36 1999
@@ -58,7 +58,11 @@
X  *
X  *	Device mc lists are changed by bh at least if IPv6 is enabled,
X  *	so that it must be bh protected.
+ *
+ *	We protect all mc lists with global rw lock
+ *	and block accesses to device mc filters with dev->xmit_lock.
X  */
+static rwlock_t dev_mc_lock = RW_LOCK_UNLOCKED;
X 
X /*
X  *	Update the multicast list into the physical NIC controller.
@@ -69,7 +73,7 @@
X 	/* Don't do anything till we up the interface
X 	   [dev_open will call this function so the list will
X 	    stay sane] */
-	    
+
X 	if(!(dev->flags&IFF_UP))
X 		return;
X 
@@ -80,11 +84,15 @@
X 	if(dev->set_multicast_list==NULL)
X 		return;
X 
-	start_bh_atomic();
+	read_lock_bh(&dev_mc_lock);
+	spin_lock(&dev->xmit_lock);
+	dev->xmit_lock_owner = smp_processor_id();
X 	dev->set_multicast_list(dev);
-	end_bh_atomic();
+	dev->xmit_lock_owner = -1;
+	spin_unlock(&dev->xmit_lock);
+	read_unlock_bh(&dev_mc_lock);
X }
-  
+
X /*
X  *	Delete a device level multicast
X  */
@@ -94,7 +102,7 @@
X 	int err = 0;
X 	struct dev_mc_list *dmi, **dmip;
X 
-	start_bh_atomic();
+	write_lock_bh(&dev_mc_lock);
X 	for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
X 		/*
X 		 *	Find the entry we want to delete. The device could
@@ -120,14 +128,15 @@
X 			 *	We have altered the list, so the card
X 			 *	loaded filter is now wrong. Fix it
X 			 */
-			end_bh_atomic();
+			write_unlock_bh(&dev_mc_lock);
+
X 			dev_mc_upload(dev);
X 			return 0;
X 		}
X 	}
X 	err = -ENOENT;
X done:
-	end_bh_atomic();
+	write_unlock_bh(&dev_mc_lock);
X 	return err;
X }
X 
@@ -140,9 +149,12 @@
X 	int err = 0;
X 	struct dev_mc_list *dmi, *dmi1;
X 
+	/* RED-PEN: does gfp_any() work now? It requires
+	   true local_bh_disable rather than global.
+	 */
X 	dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), gfp_any());
X 
-	start_bh_atomic();
+	write_lock_bh(&dev_mc_lock);
X 	for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) {
X 		if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) {
X 			if (glbl) {
@@ -156,8 +168,10 @@
X 		}
X 	}
X 
-	if ((dmi=dmi1)==NULL)
+	if ((dmi=dmi1)==NULL) {
+		write_unlock_bh(&dev_mc_lock);
X 		return -ENOMEM;
+	}
X 	memcpy(dmi->dmi_addr, addr, alen);
X 	dmi->dmi_addrlen=alen;
X 	dmi->next=dev->mc_list;
@@ -165,12 +179,12 @@
X 	dmi->dmi_gusers=glbl ? 1 : 0;
X 	dev->mc_list=dmi;
X 	dev->mc_count++;
-	end_bh_atomic();
+	write_unlock_bh(&dev_mc_lock);
X 	dev_mc_upload(dev);
X 	return 0;
X 
X done:
-	end_bh_atomic();
+	write_unlock_bh(&dev_mc_lock);
X 	if (dmi1)
X 		kfree(dmi1);
X 	return err;
@@ -182,7 +196,7 @@
X 
X void dev_mc_discard(struct device *dev)
X {
-	start_bh_atomic();
+	write_lock_bh(&dev_mc_lock);
X 	while (dev->mc_list!=NULL) {
X 		struct dev_mc_list *tmp=dev->mc_list;
X 		dev->mc_list=tmp->next;
@@ -191,7 +205,7 @@
X 		kfree_s(tmp,sizeof(*tmp));
X 	}
X 	dev->mc_count=0;
-	end_bh_atomic();
+	write_unlock_bh(&dev_mc_lock);
X }
X 
X #ifdef CONFIG_PROC_FS
@@ -203,8 +217,9 @@
X 	int len=0;
X 	struct device *dev;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev; dev = dev->next) {
+		read_lock_bh(&dev_mc_lock);
X 		for (m = dev->mc_list; m; m = m->next) {
X 			int i;
X 
@@ -221,14 +236,17 @@
X 				len=0;
X 				begin=pos;
X 			}
-			if (pos > offset+length)
+			if (pos > offset+length) {
+				read_unlock_bh(&dev_mc_lock);
X 				goto done;
+			}
X 		}
+		read_unlock_bh(&dev_mc_lock);
X 	}
X 	*eof = 1;
X 
X done:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	*start=buffer+(offset-begin);
X 	len-=(offset-begin);
X 	if(len>length)
diff -u --recursive --new-file v2.3.5/linux/net/core/dst.c linux/net/core/dst.c
--- v2.3.5/linux/net/core/dst.c	Mon May 31 22:28:07 1999
+++ linux/net/core/dst.c	Wed Jun  9 14:45:36 1999
@@ -16,6 +16,7 @@
X #include <linux/errno.h>
X #include <linux/netdevice.h>
X #include <linux/skbuff.h>
+#include <linux/init.h>
X 
X #include <net/dst.h>
X 
@@ -39,16 +40,16 @@
X static struct timer_list dst_gc_timer =
X 	{ NULL, NULL, DST_GC_MIN, 0L, dst_run_gc };
X 
-#if RT_CACHE_DEBUG >= 2
-atomic_t hh_count;
-#endif
X 
X static void dst_run_gc(unsigned long dummy)
X {
X 	int    delayed = 0;
X 	struct dst_entry * dst, **dstp;
X 
-	spin_lock(&dst_lock);
+	if (!spin_trylock(&dst_lock)) {
+		mod_timer(&dst_gc_timer, jiffies + HZ/10);
+		return;
+	}
X 
X 	del_timer(&dst_gc_timer);
X 	dstp = &dst_garbage_list;
@@ -159,4 +160,37 @@
X 		dst->ops->destroy(dst);
X 	atomic_dec(&dst_total);
X 	kfree(dst);
+}
+
+static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct device *dev = ptr;
+	struct dst_entry *dst;
+
+	switch (event) {
+	case NETDEV_UNREGISTER:
+	case NETDEV_DOWN:
+		spin_lock_bh(&dst_lock);
+		for (dst = dst_garbage_list; dst; dst = dst->next) {
+			if (dst->dev == dev) {
+				dst->input = dst_discard;
+				dst->output = dst_blackhole;
+				dst->dev = &loopback_dev;
+			}
+		}
+		spin_unlock_bh(&dst_lock);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+struct notifier_block dst_dev_notifier = {
+	dst_dev_event,
+	NULL,
+	0
+};
+
+__initfunc(void dst_init(void))
+{
+	register_netdevice_notifier(&dst_dev_notifier);
X }
diff -u --recursive --new-file v2.3.5/linux/net/core/neighbour.c linux/net/core/neighbour.c
--- v2.3.5/linux/net/core/neighbour.c	Wed Jun  2 14:44:39 1999
+++ linux/net/core/neighbour.c	Wed Jun  9 14:45:36 1999
@@ -12,12 +12,10 @@
X  *
X  *	Fixes:
X  *	Vitaly E. Lavrov	releasing NULL neighbor in neigh_add.
- *      Horst von Brand        Add #include <linux/string.h>
X  */
X 
X #include <linux/config.h>
X #include <linux/types.h>
-#include <linux/string.h>
X #include <linux/kernel.h>
X #include <linux/socket.h>
X #include <linux/sched.h>
@@ -30,33 +28,6 @@
X #include <net/sock.h>
X #include <linux/rtnetlink.h>
X 
-/*
-   NOTE. The most unpleasent question is serialization of
-   accesses to resolved addresses. The problem is that addresses
-   are modified by bh, but they are referenced from normal
-   kernel thread. Before today no locking was made.
-   My reasoning was that corrupted address token will be copied
-   to packet with cosmologically small probability
-   (it is even difficult to estimate such small number)
-   and it is very silly to waste cycles in fast path to lock them.
-
-   But now I changed my mind, but not because previous statement
-   is wrong. Actually, neigh->ha MAY BE not opaque byte array,
-   but reference to some private data. In this case even neglibible
-   corruption probability becomes bug.
-
-   - hh cache is protected by rwlock. It assumes that
-     hh cache update procedure is short and fast, and that
-     read_lock is cheaper than start_bh_atomic().
-   - ha tokens, saved in neighbour entries, are protected
-     by bh_atomic().
-   - no protection is made in /proc reading. It is OK, because
-     /proc is broken by design in any case, and
-     corrupted output is normal behaviour there.
-
-     --ANK (981025)
- */
-
X #define NEIGH_DEBUG 1
X 
X #define NEIGH_PRINTK(x...) printk(x)
@@ -83,6 +54,46 @@
X static int neigh_glbl_allocs;
X static struct neigh_table *neigh_tables;
X 
+#if defined(__i386__) && defined(__SMP__)
+#define ASSERT_WL(n) if ((int)((n)->lock.lock) >= 0) { printk("WL assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
+#else
+#define ASSERT_WL(n) do { } while(0)
+#endif
+
+/*
+   Neighbour hash table buckets are protected with rwlock tbl->lock.
+
+   - All the scans/updates to hash buckets MUST be made under this lock.
+   - NOTHING clever should be made under this lock: no callbacks
+     to protocol backends, no attempts to send something to network.
+     It will result in deadlocks, if backend/driver wants to use neighbour
+     cache.
+   - If the entry requires some non-trivial actions, increase
+     its reference count and release table lock.
+ 
+   Neighbour entries are protected:
+   - with reference count.
+   - with rwlock neigh->lock
+
+   Reference count prevents destruction.
+
+   neigh->lock mainly serializes ll address data and its validity state.
+   However, the same lock is used to protect another entry fields:
+    - timer
+    - resolution queue
+
+   Again, nothing clever shall be made under neigh->lock,
+   the most complicated procedure, which we allow is dev->hard_header.
+   It is supposed, that dev->hard_header is simplistic and does
+   not make callbacks to neighbour tables.
+
+   The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
+   list of neighbour tables. This list is used only in process context,
+   so that this lock is useless with big kernel lock.
+ */
+
+static rwlock_t neigh_tbl_lock = RW_LOCK_UNLOCKED;
+
X static int neigh_blackhole(struct sk_buff *skb)
X {
X 	kfree_skb(skb);
@@ -106,13 +117,11 @@
X 	int shrunk = 0;
X 	int i;
X 
-	if (atomic_read(&tbl->lock))
-		return 0;
-
X 	for (i=0; i<=NEIGH_HASHMASK; i++) {
X 		struct neighbour *n, **np;
X 
X 		np = &tbl->hash_buckets[i];
+		write_lock_bh(&tbl->lock);
X 		while ((n = *np) != NULL) {
X 			/* Neighbour record may be discarded if:
X 			   - nobody refers to it.
@@ -124,6 +133,7 @@
X 			     It is not clear, what is better table overflow
X 			     or flooding.
X 			 */
+			write_lock(&n->lock);
X 			if (atomic_read(&n->refcnt) == 0 &&
X 			    !(n->nud_state&NUD_PERMANENT) &&
X 			    (n->nud_state != NUD_INCOMPLETE ||
@@ -132,11 +142,14 @@
X 				n->tbl = NULL;
X 				tbl->entries--;
X 				shrunk = 1;
+				write_unlock(&n->lock);
X 				neigh_destroy(n);
X 				continue;
X 			}
+			write_unlock(&n->lock);
X 			np = &n->next;
X 		}
+		write_unlock_bh(&tbl->lock);
X 	}
X 	
X 	tbl->last_flush = jiffies;
@@ -147,12 +160,8 @@
X {
X 	int i;
X 
-	if (atomic_read(&tbl->lock)) {
-		NEIGH_PRINTK1("neigh_ifdown: impossible event 1763\n");
-		return -EBUSY;
-	}
+	write_lock_bh(&tbl->lock);
X 
-	start_bh_atomic();
X 	for (i=0; i<=NEIGH_HASHMASK; i++) {
X 		struct neighbour *n, **np;
X 
@@ -163,6 +172,7 @@
X 				continue;
X 			}
X 			*np = n->next;
+			write_lock(&n->lock);
X 			n->tbl = NULL;
X 			tbl->entries--;
X 			if (atomic_read(&n->refcnt)) {
@@ -185,33 +195,32 @@
X 				else
X 					n->nud_state = NUD_NONE;
X 				NEIGH_PRINTK2("neigh %p is stray.\n", n);
-			} else
+				write_unlock(&n->lock);
+			} else {
+				write_unlock(&n->lock);
X 				neigh_destroy(n);
+			}
X 		}
X 	}
X 
X 	del_timer(&tbl->proxy_timer);
X 	skb_queue_purge(&tbl->proxy_queue);
X 	pneigh_ifdown(tbl, dev);
-	end_bh_atomic();
+	write_unlock_bh(&tbl->lock);
X 	return 0;
X }
X 
-static struct neighbour *neigh_alloc(struct neigh_table *tbl, int creat)
+static struct neighbour *neigh_alloc(struct neigh_table *tbl)
X {
X 	struct neighbour *n;
X 	unsigned long now = jiffies;
X 
-	if (tbl->entries > tbl->gc_thresh1) {
-		if (creat < 0)
+	if (tbl->entries > tbl->gc_thresh3 ||
+	    (tbl->entries > tbl->gc_thresh2 &&
+	     now - tbl->last_flush > 5*HZ)) {
+		if (neigh_forced_gc(tbl) == 0 &&
+		    tbl->entries > tbl->gc_thresh3)
X 			return NULL;
-		if (tbl->entries > tbl->gc_thresh3 ||
-		    (tbl->entries > tbl->gc_thresh2 &&
-		     now - tbl->last_flush > 5*HZ)) {
-			if (neigh_forced_gc(tbl) == 0 &&
-			    tbl->entries > tbl->gc_thresh3)
-				return NULL;
-		}
X 	}
X 
X 	n = kmalloc(tbl->entry_size, GFP_ATOMIC);
@@ -221,6 +230,7 @@
X 	memset(n, 0, tbl->entry_size);
X 
X 	skb_queue_head_init(&n->arp_queue);
+	n->lock = RW_LOCK_UNLOCKED;
X 	n->updated = n->used = now;
X 	n->nud_state = NUD_NONE;
X 	n->output = neigh_blackhole;
@@ -233,9 +243,8 @@
X 	return n;
X }
X 
-
-struct neighbour * __neigh_lookup(struct neigh_table *tbl, const void *pkey,
-				    struct device *dev, int creat)
+struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
+			       struct device *dev)
X {
X 	struct neighbour *n;
X 	u32 hash_val;
@@ -247,17 +256,26 @@
X 	hash_val ^= hash_val>>3;
X 	hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK;
X 
+	read_lock_bh(&tbl->lock);
X 	for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
X 		if (dev == n->dev &&
X 		    memcmp(n->primary_key, pkey, key_len) == 0) {
X 			atomic_inc(&n->refcnt);
-			return n;
+			break;
X 		}
X 	}
-	if (!creat)
-		return NULL;
+	read_unlock_bh(&tbl->lock);
+	return n;
+}
X 
-	n = neigh_alloc(tbl, creat);
+struct neighbour * neigh_create(struct neigh_table *tbl, const void *pkey,
+				struct device *dev)
+{
+	struct neighbour *n, *n1;
+	u32 hash_val;
+	int key_len = tbl->key_len;
+
+	n = neigh_alloc(tbl);
X 	if (n == NULL)
X 		return NULL;
X 
@@ -277,11 +295,30 @@
X 	}
X 
X 	n->confirmed = jiffies - (n->parms->base_reachable_time<<1);
-	atomic_set(&n->refcnt, 1);
+
+	hash_val = *(u32*)(pkey + key_len - 4);
+	hash_val ^= (hash_val>>16);
+	hash_val ^= hash_val>>8;
+	hash_val ^= hash_val>>3;
+	hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK;
+
+	write_lock_bh(&tbl->lock);
+	for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) {
+		if (dev == n1->dev &&
+		    memcmp(n1->primary_key, pkey, key_len) == 0) {
+			atomic_inc(&n1->refcnt);
+			write_unlock_bh(&tbl->lock);
+			neigh_destroy(n);
+			return n1;
+		}
+	}
+
X 	tbl->entries++;
+	n->tbl = tbl;
+	atomic_set(&n->refcnt, 1);
X 	n->next = tbl->hash_buckets[hash_val];
X 	tbl->hash_buckets[hash_val] = n;
-	n->tbl = tbl;
+	write_unlock_bh(&tbl->lock);
X 	NEIGH_PRINTK2("neigh %p is created.\n", n);
X 	return n;
X }
@@ -393,7 +430,9 @@
X 	while ((hh = neigh->hh) != NULL) {
X 		neigh->hh = hh->hh_next;
X 		hh->hh_next = NULL;
+		write_lock_bh(&hh->hh_lock);
X 		hh->hh_output = neigh_blackhole;
+		write_unlock_bh(&hh->hh_lock);
X 		if (atomic_dec_and_test(&hh->hh_refcnt))
X 			kfree(hh);
X 	}
@@ -411,6 +450,8 @@
X 
X /* Neighbour state is suspicious;
X    disable fast path.
+
+   Called with write_locked neigh.
X  */
X static void neigh_suspect(struct neighbour *neigh)
X {
@@ -418,6 +459,8 @@
X 
X 	NEIGH_PRINTK2("neigh %p is suspecteded.\n", neigh);
X 
+	ASSERT_WL(neigh);
+
X 	neigh->output = neigh->ops->output;
X 
X 	for (hh = neigh->hh; hh; hh = hh->hh_next)
@@ -426,6 +469,8 @@
X 
X /* Neighbour state is OK;
X    enable fast path.
+
+   Called with write_locked neigh.
X  */
X static void neigh_connect(struct neighbour *neigh)
X {
@@ -433,6 +478,8 @@
X 
X 	NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
X 
+	ASSERT_WL(neigh);
+
X 	neigh->output = neigh->ops->connected_output;
X 
X 	for (hh = neigh->hh; hh; hh = hh->hh_next)
@@ -448,6 +495,8 @@
X 
X    If a routine wants to know TRUE entry state, it calls
X    neigh_sync before checking state.
+
+   Called with write_locked neigh.
X  */
X 
X static void neigh_sync(struct neighbour *n)
@@ -455,6 +504,7 @@
X 	unsigned long now = jiffies;
X 	u8 state = n->nud_state;
X 
+	ASSERT_WL(n);
X 	if (state&(NUD_NOARP|NUD_PERMANENT))
X 		return;
X 	if (state&NUD_REACHABLE) {
@@ -478,11 +528,8 @@
X 	unsigned long now = jiffies;
X 	int i;
X 
-	if (atomic_read(&tbl->lock)) {
-		tbl->gc_timer.expires = now + 1*HZ;
-		add_timer(&tbl->gc_timer);
-		return;
-	}
+
+	write_lock(&tbl->lock);
X 
X 	/*
X 	 *	periodicly recompute ReachableTime from random function
@@ -500,10 +547,15 @@
X 
X 		np = &tbl->hash_buckets[i];
X 		while ((n = *np) != NULL) {
-			unsigned state = n->nud_state;
+			unsigned state;
+
+			write_lock(&n->lock);
X 
-			if (state&(NUD_PERMANENT|NUD_IN_TIMER))
+			state = n->nud_state;
+			if (state&(NUD_PERMANENT|NUD_IN_TIMER)) {
+				write_unlock(&n->lock);
X 				goto next_elt;
+			}
X 
X 			if ((long)(n->used - n->confirmed) < 0)
X 				n->used = n->confirmed;
@@ -514,6 +566,7 @@
X 				n->tbl = NULL;
X 				n->next = NULL;
X 				tbl->entries--;
+				write_unlock(&n->lock);
X 				neigh_destroy(n);
X 				continue;
X 			}
@@ -523,6 +576,7 @@
X 				n->nud_state = NUD_STALE;
X 				neigh_suspect(n);
X 			}
+			write_unlock(&n->lock);
X 
X next_elt:
X 			np = &n->next;
@@ -531,6 +585,7 @@
X 
X 	tbl->gc_timer.expires = now + tbl->gc_interval;
X 	add_timer(&tbl->gc_timer);
+	write_unlock(&tbl->lock);
X }
X 
X static __inline__ int neigh_max_probes(struct neighbour *n)
@@ -546,11 +601,17 @@
X {
X 	unsigned long now = jiffies;
X 	struct neighbour *neigh = (struct neighbour*)arg;
-	unsigned state = neigh->nud_state;
+	unsigned state;
+	int notify = 0;
+
+	write_lock(&neigh->lock);
+	atomic_inc(&neigh->refcnt);
+
+	state = neigh->nud_state;
X 
X 	if (!(state&NUD_IN_TIMER)) {
X 		NEIGH_PRINTK1("neigh: timer & !nud_in_timer\n");
-		return;
+		goto out;
X 	}
X 
X 	if ((state&NUD_VALID) &&
@@ -558,18 +619,19 @@
X 		neigh->nud_state = NUD_REACHABLE;
X 		NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
X 		neigh_connect(neigh);
-		return;
+		goto out;
X 	}
X 	if (state == NUD_DELAY) {
X 		NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
X 		neigh->nud_state = NUD_PROBE;
-		neigh->probes = 0;
+		atomic_set(&neigh->probes, 0);
X 	}
X 
-	if (neigh->probes >= neigh_max_probes(neigh)) {
+	if (atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
X 		struct sk_buff *skb;
X 
X 		neigh->nud_state = NUD_FAILED;
+		notify = 1;
X 		neigh->tbl->stats.res_failed++;
X 		NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
X 
@@ -578,44 +640,60 @@
X 		   
X 		   So that, we try to be accurate and avoid dead loop. --ANK
X 		 */
-		while(neigh->nud_state==NUD_FAILED && (skb=__skb_dequeue(&neigh->arp_queue)) != NULL)
+		while(neigh->nud_state==NUD_FAILED && (skb=__skb_dequeue(&neigh->arp_queue)) != NULL) {
+			write_unlock(&neigh->lock);
X 			neigh->ops->error_report(neigh, skb);
+			write_lock(&neigh->lock);
+		}
X 		skb_queue_purge(&neigh->arp_queue);
-		return;
+		goto out;
X 	}
X 
X 	neigh->timer.expires = now + neigh->parms->retrans_time;
X 	add_timer(&neigh->timer);
+	write_unlock(&neigh->lock);
X 
X 	neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue));
-	neigh->probes++;
+	atomic_inc(&neigh->probes);
+	neigh_release(neigh);
+	return;
+
+out:
+	write_unlock(&neigh->lock);
+#ifdef CONFIG_ARPD
+	if (notify && neigh->parms->app_probes)
+		neigh_app_notify(neigh);
+#endif
+	neigh_release(neigh);
X }
X 
X int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
X {
-	start_bh_atomic();
+	write_lock_bh(&neigh->lock);
X 	if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) {
X 		if (!(neigh->nud_state&(NUD_STALE|NUD_INCOMPLETE))) {
X 			if (neigh->tbl == NULL) {
X 				NEIGH_PRINTK2("neigh %p used after death.\n", neigh);
X 				if (skb)
X 					kfree_skb(skb);
-				end_bh_atomic();
+				write_unlock_bh(&neigh->lock);
X 				return 1;
X 			}
X 			if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
-				neigh->probes = neigh->parms->ucast_probes;
+				atomic_set(&neigh->probes, neigh->parms->ucast_probes);
X 				neigh->nud_state = NUD_INCOMPLETE;
X 				neigh->timer.expires = jiffies + neigh->parms->retrans_time;
X 				add_timer(&neigh->timer);
-
+				write_unlock_bh(&neigh->lock);
X 				neigh->ops->solicit(neigh, skb);
-				neigh->probes++;
+				atomic_inc(&neigh->probes);
+				write_lock_bh(&neigh->lock);
X 			} else {
X 				neigh->nud_state = NUD_FAILED;
+				write_unlock_bh(&neigh->lock);
+
X 				if (skb)
X 					kfree_skb(skb);
-				end_bh_atomic();
X 				return 1;
X 			}
X 		}
@@ -629,7 +707,7 @@
X 				}
X 				__skb_queue_head(&neigh->arp_queue, skb);
X 			}
-			end_bh_atomic();
+			write_unlock_bh(&neigh->lock);
X 			return 1;
X 		}
X 		if (neigh->nud_state == NUD_STALE) {
@@ -639,7 +717,7 @@
X 			add_timer(&neigh->timer);
X 		}
X 	}
-	end_bh_atomic();
+	write_unlock_bh(&neigh->lock);
X 	return 0;
X }
X 
@@ -651,9 +729,9 @@
X 
X 	if (update) {
X 		for (hh=neigh->hh; hh; hh=hh->hh_next) {
-			write_lock_irq(&hh->hh_lock);
+			write_lock_bh(&hh->hh_lock);
X 			update(hh, neigh->dev, neigh->ha);
-			write_unlock_irq(&hh->hh_lock);
+			write_unlock_bh(&hh->hh_lock);
X 		}
X 	}
X }
@@ -665,15 +743,23 @@
X    -- new    is new state.
X    -- override==1 allows to override existing lladdr, if it is different.
X    -- arp==0 means that the change is administrative.
+
+   Caller MUST hold reference count on the entry.
X  */
X 
X int neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int arp)
X {
-	u8 old = neigh->nud_state;
+	u8 old;
+	int err;
+	int notify = 0;
X 	struct device *dev = neigh->dev;
X 
+	write_lock_bh(&neigh->lock);
+	old = neigh->nud_state;
+
+	err = -EPERM;
X 	if (arp && (old&(NUD_NOARP|NUD_PERMANENT)))
-		return -EPERM;
+		goto out;
X 
X 	if (!(new&NUD_VALID)) {
X 		if (old&NUD_IN_TIMER)
@@ -681,7 +767,9 @@
X 		if (old&NUD_CONNECTED)
X 			neigh_suspect(neigh);
X 		neigh->nud_state = new;
-		return 0;
+		err = 0;
+		notify = old&NUD_VALID;
+		goto out;
X 	}
X 
X 	/* Compare new lladdr with cached one */
@@ -698,14 +786,15 @@
X 			if (memcmp(lladdr, neigh->ha, dev->addr_len) == 0)
X 				lladdr = neigh->ha;
X 			else if (!override)
-				return -EPERM;
+				goto out;
X 		}
X 	} else {
X 		/* No address is supplied; if we know something,
X 		   use it, otherwise discard the request.
X 		 */
+		err = -EINVAL;
X 		if (!(old&NUD_VALID))
-			return -EINVAL;
+			goto out;
X 		lladdr = neigh->ha;
X 	}
X 
@@ -718,10 +807,11 @@
X 	/* If entry was valid and address is not changed,
X 	   do not change entry state, if new one is STALE.
X 	 */
+	err = 0;
X 	if (old&NUD_VALID) {
X 		if (lladdr == neigh->ha)
X 			if (new == old || (new == NUD_STALE && (old&NUD_CONNECTED)))
-				return 0;
+				goto out;
X 	}
X 	if (old&NUD_IN_TIMER)
X 		del_timer(&neigh->timer);
@@ -731,12 +821,11 @@
X 		neigh_update_hhs(neigh);
X 		neigh->confirmed = jiffies - (neigh->parms->base_reachable_time<<1);
X #ifdef CONFIG_ARPD
-		if (neigh->parms->app_probes)
-			neigh_app_notify(neigh);
+		notify = 1;
X #endif
X 	}
X 	if (new == old)
-		return 0;
+		goto out;
X 	if (new&NUD_CONNECTED)
X 		neigh_connect(neigh);
X 	else
@@ -749,14 +838,22 @@
X 		while (neigh->nud_state&NUD_VALID &&
X 		       (skb=__skb_dequeue(&neigh->arp_queue)) != NULL) {
X 			struct neighbour *n1 = neigh;
+			write_unlock_bh(&neigh->lock);
X 			/* On shaper/eql skb->dst->neighbour != neigh :( */
X 			if (skb->dst && skb->dst->neighbour)
X 				n1 = skb->dst->neighbour;
X 			n1->output(skb);
+			write_lock_bh(&neigh->lock);
X 		}
X 		skb_queue_purge(&neigh->arp_queue);
X 	}
-	return 0;
+out:
+	write_unlock_bh(&neigh->lock);
+#ifdef CONFIG_ARPD
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 22'
echo 'File patch-2.3.6 is continued in part 23'
echo 23 > _shar_seq_.tmp
#!/bin/sh
# this is part 23 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 23; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+	if (notify && neigh->parms->app_probes)
+		neigh_app_notify(neigh);
+#endif
+	return err;
X }
X 
X struct neighbour * neigh_event_ns(struct neigh_table *tbl,
@@ -839,15 +936,15 @@
X 		int err;
X 		struct device *dev = neigh->dev;
X if (dev->hard_header_cache && dst->hh == NULL) {
-			start_bh_atomic();
+			write_lock_bh(&neigh->lock);
X 			if (dst->hh == NULL)
X 				neigh_hh_init(neigh, dst, dst->ops->protocol);
X 			err = dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len);
-			end_bh_atomic();
+			write_unlock_bh(&neigh->lock);
X 		} else {
-			start_bh_atomic();
+			read_lock_bh(&neigh->lock);
X 			err = dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len);
-			end_bh_atomic();
+			read_unlock_bh(&neigh->lock);
X 		}
X 		if (err >= 0)
X 			return neigh->ops->queue_xmit(skb);
@@ -873,9 +970,9 @@
X 
X 	__skb_pull(skb, skb->nh.raw - skb->data);
X 
-	start_bh_atomic();
+	read_lock_bh(&neigh->lock);
X 	err = dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len);
-	end_bh_atomic();
+	read_unlock_bh(&neigh->lock);
X 	if (err >= 0)
X 		return neigh->ops->queue_xmit(skb);
X 	kfree_skb(skb);
@@ -949,8 +1046,10 @@
X 				return NULL;
X 			}
X 		}
+		write_lock_bh(&tbl->lock);
X 		p->next = tbl->parms.next;
X 		tbl->parms.next = p;
+		write_unlock_bh(&tbl->lock);
X 	}
X 	return p;
X }
@@ -961,10 +1060,11 @@
X 	
X 	if (parms == NULL || parms == &tbl->parms)
X 		return;
+	write_lock_bh(&tbl->lock);
X 	for (p = &tbl->parms.next; *p; p = &(*p)->next) {
X 		if (*p == parms) {
X 			*p = parms->next;
-			synchronize_bh();
+			write_unlock_bh(&tbl->lock);
X #ifdef CONFIG_SYSCTL
X 			neigh_sysctl_unregister(parms);
X #endif
@@ -972,6 +1072,7 @@
X 			return;
X 		}
X 	}
+	write_unlock_bh(&tbl->lock);
X 	NEIGH_PRINTK1("neigh_release_parms: not found\n");
X }
X 
@@ -983,6 +1084,7 @@
X 	tbl->parms.reachable_time = neigh_rand_reach_time(tbl->parms.base_reachable_time);
X 
X 	init_timer(&tbl->gc_timer);
+	tbl->lock = RW_LOCK_UNLOCKED;
X 	tbl->gc_timer.data = (unsigned long)tbl;
X 	tbl->gc_timer.function = neigh_periodic_timer;
X 	tbl->gc_timer.expires = now + tbl->gc_interval + tbl->parms.reachable_time;
@@ -995,29 +1097,30 @@
X 
X 	tbl->last_flush = now;
X 	tbl->last_rand = now + tbl->parms.reachable_time*20;
+	write_lock(&neigh_tbl_lock);
X 	tbl->next = neigh_tables;
X 	neigh_tables = tbl;
+	write_unlock(&neigh_tbl_lock);
X }
X 
X int neigh_table_clear(struct neigh_table *tbl)
X {
X 	struct neigh_table **tp;
X 
-	start_bh_atomic();
X 	del_timer(&tbl->gc_timer);
X 	del_timer(&tbl->proxy_timer);
X 	skb_queue_purge(&tbl->proxy_queue);
X 	neigh_ifdown(tbl, NULL);
-	end_bh_atomic();
X 	if (tbl->entries)
X 		printk(KERN_CRIT "neighbour leakage\n");
+	write_lock(&neigh_tbl_lock);
X 	for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
X 		if (*tp == tbl) {
X 			*tp = tbl->next;
-			synchronize_bh();
X 			break;
X 		}
X 	}
+	write_unlock(&neigh_tbl_lock);
X #ifdef CONFIG_SYSCTL
X 	neigh_sysctl_unregister(&tbl->parms);
X #endif
@@ -1039,12 +1142,14 @@
X 			return -ENODEV;
X 	}
X 
+	read_lock(&neigh_tbl_lock);
X 	for (tbl=neigh_tables; tbl; tbl = tbl->next) {
X 		int err = 0;
X 		struct neighbour *n;
X 
X 		if (tbl->family != ndm->ndm_family)
X 			continue;
+		read_unlock(&neigh_tbl_lock);
X 
X 		if (nda[NDA_DST-1] == NULL ||
X 		    nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len))
@@ -1056,15 +1161,14 @@
X 		if (dev == NULL)
X 			return -EINVAL;
X 
-		start_bh_atomic();
-		n = __neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 0);
+		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev);
X 		if (n) {
X 			err = neigh_update(n, NULL, NUD_FAILED, 1, 0);
X 			neigh_release(n);
X 		}
-		end_bh_atomic();
X 		return err;
X 	}
+	read_unlock(&neigh_tbl_lock);
X 
X 	return -EADDRNOTAVAIL;
X }
@@ -1081,12 +1185,15 @@
X 			return -ENODEV;
X 	}
X 
+	read_lock(&neigh_tbl_lock);
X 	for (tbl=neigh_tables; tbl; tbl = tbl->next) {
X 		int err = 0;
X 		struct neighbour *n;
X 
X 		if (tbl->family != ndm->ndm_family)
X 			continue;
+		read_unlock(&neigh_tbl_lock);
+
X 		if (nda[NDA_DST-1] == NULL ||
X 		    nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len))
X 			return -EINVAL;
@@ -1100,8 +1207,7 @@
X 		if (nda[NDA_LLADDR-1] != NULL &&
X 		    nda[NDA_LLADDR-1]->rta_len != RTA_LENGTH(dev->addr_len))
X 			return -EINVAL;
-		start_bh_atomic();
-		n = __neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 0);
+		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev);
X 		if (n) {
X 			if (nlh->nlmsg_flags&NLM_F_EXCL)
X 				err = -EEXIST;
@@ -1119,9 +1225,9 @@
X 		}
X 		if (n)
X 			neigh_release(n);
-		end_bh_atomic();
X 		return err;
X 	}
+	read_unlock(&neigh_tbl_lock);
X 
X 	return -EADDRNOTAVAIL;
X }
@@ -1141,15 +1247,17 @@
X 	ndm->ndm_family = n->ops->family;
X 	ndm->ndm_flags = n->flags;
X 	ndm->ndm_type = n->type;
-	ndm->ndm_state = n->nud_state;
X 	ndm->ndm_ifindex = n->dev->ifindex;
X 	RTA_PUT(skb, NDA_DST, n->tbl->key_len, n->primary_key);
+	read_lock_bh(&n->lock);
+	ndm->ndm_state = n->nud_state;
X 	if (n->nud_state&NUD_VALID)
X 		RTA_PUT(skb, NDA_LLADDR, n->dev->addr_len, n->ha);
X 	ci.ndm_used = now - n->used;
X 	ci.ndm_confirmed = now - n->confirmed;
X 	ci.ndm_updated = now - n->updated;
X 	ci.ndm_refcnt = atomic_read(&n->refcnt);
+	read_unlock_bh(&n->lock);
X 	RTA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
X 	nlh->nlmsg_len = skb->tail - b;
X 	return skb->len;
@@ -1173,20 +1281,20 @@
X 		if (h < s_h) continue;
X 		if (h > s_h)
X 			s_idx = 0;
-		start_bh_atomic();
+		read_lock_bh(&tbl->lock);
X 		for (n = tbl->hash_buckets[h], idx = 0; n;
X 		     n = n->next, idx++) {
X 			if (idx < s_idx)
X 				continue;
X 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
X 					    cb->nlh->nlmsg_seq, RTM_NEWNEIGH) <= 0) {
-				end_bh_atomic();
+				read_unlock_bh(&tbl->lock);
X 				cb->args[1] = h;
X 				cb->args[2] = idx;
X 				return -1;
X 			}
X 		}
-		end_bh_atomic();
+		read_unlock_bh(&tbl->lock);
X 	}
X 
X 	cb->args[1] = h;
@@ -1203,6 +1311,7 @@
X 
X 	s_t = cb->args[0];
X 
+	read_lock(&neigh_tbl_lock);
X 	for (tbl=neigh_tables, t=0; tbl; tbl = tbl->next, t++) {
X 		if (t < s_t) continue;
X 		if (family && tbl->family != family)
@@ -1212,6 +1321,7 @@
X 		if (neigh_dump_table(tbl, skb, cb) < 0) 
X 			break;
X 	}
+	read_unlock(&neigh_tbl_lock);
X 
X 	cb->args[0] = t;
X 
diff -u --recursive --new-file v2.3.5/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- v2.3.5/linux/net/core/rtnetlink.c	Mon May 31 22:28:07 1999
+++ linux/net/core/rtnetlink.c	Wed Jun  9 14:45:36 1999
@@ -50,22 +50,22 @@
X #include <net/sock.h>
X #include <net/pkt_sched.h>
X 
-atomic_t rtnl_rlockct;
-DECLARE_WAIT_QUEUE_HEAD(rtnl_wait);
+DECLARE_MUTEX(rtnl_sem);
X 
-
-void rtnl_lock()
+void rtnl_lock(void)
X {
X 	rtnl_shlock();
X 	rtnl_exlock();
X }
-
-void rtnl_unlock()
+ 
+void rtnl_unlock(void)
X {
X 	rtnl_exunlock();
X 	rtnl_shunlock();
X }
X 
+
+
X int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
X {
X 	memset(tb, 0, sizeof(struct rtattr*)*maxattr);
@@ -82,8 +82,6 @@
X #ifdef CONFIG_RTNETLINK
X struct sock *rtnl;
X 
-unsigned long rtnl_wlockct;
-
X struct rtnetlink_link * rtnetlink_links[NPROTO];
X 
X #define _S	1	/* superuser privileges required */
@@ -189,14 +187,14 @@
X 	int s_idx = cb->args[0];
X 	struct device *dev;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
X 		if (idx < s_idx)
X 			continue;
X 		if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0)
X 			break;
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	cb->args[0] = idx;
X 
X 	return skb->len;
@@ -218,9 +216,7 @@
X 			continue;
X 		if (idx > s_idx)
X 			memset(&cb->args[0], 0, sizeof(cb->args));
-		if (rtnetlink_links[idx][type].dumpit(skb, cb) == 0)
-			continue;
-		if (skb_tailroom(skb) < 256)
+		if (rtnetlink_links[idx][type].dumpit(skb, cb))
X 			break;
X 	}
X 	cb->family = idx;
@@ -247,8 +243,6 @@
X 
X static int rtnetlink_done(struct netlink_callback *cb)
X {
-	if (cap_raised(NETLINK_CB(cb->skb).eff_cap, CAP_NET_ADMIN) && cb->nlh->nlmsg_flags&NLM_F_ATOMIC)
-		rtnl_shunlock();
X 	return 0;
X }
X 
@@ -316,15 +310,9 @@
X 		if (link->dumpit == NULL)
X 			goto err_inval;
X 
-		/* Super-user locks all the tables to get atomic snapshot */
-		if (cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)
-		    && nlh->nlmsg_flags&NLM_F_ATOMIC)
-			atomic_inc(&rtnl_rlockct);
X 		if ((*errp = netlink_dump_start(rtnl, skb, nlh,
X 						link->dumpit,
X 						rtnetlink_done)) != 0) {
-			if (cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN) && nlh->nlmsg_flags&NLM_F_ATOMIC)
-				atomic_dec(&rtnl_rlockct);
X 			return -1;
X 		}
X 		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
diff -u --recursive --new-file v2.3.5/linux/net/decnet/dn_neigh.c linux/net/decnet/dn_neigh.c
--- v2.3.5/linux/net/decnet/dn_neigh.c	Mon May 31 22:28:07 1999
+++ linux/net/decnet/dn_neigh.c	Wed Jun  9 14:45:36 1999
@@ -561,12 +561,13 @@
X 
X 	len += sprintf(buffer + len, "Addr    Flags State Use Blksize Dev\n");
X 
-	neigh_table_lock(&dn_neigh_table);
X 	for(i=0;i <= NEIGH_HASHMASK; i++) {
+		read_lock_bh(&dn_neigh_table.lock);
X 		n = dn_neigh_table.hash_buckets[i];
X 		for(; n != NULL; n = n->next) {
X 			struct dn_neigh *dn = (struct dn_neigh *)n;
X 
+			read_lock(&n->lock);
X 			len += sprintf(buffer+len, "%-7s %s%s%s   %02x    %02d  %07ld %-8s\n",
X 					dn_addr2asc(dn_ntohs(dn_eth2dn(dn->addr)), buf),
X 					(dn->flags&DN_NDFLAG_R1) ? "1" : "-",
@@ -576,6 +577,7 @@
X 					atomic_read(&dn->n.refcnt),
X 					dn->blksize,
X 					(dn->n.dev) ? dn->n.dev->name : "?");
+			read_unlock(&n->lock);
X 
X 			pos = begin + len;
X 
@@ -584,11 +586,15 @@
X                         	begin = pos;
X                 	}
X 
-                	if (pos > offset + length)
-                       		break;
+                	if (pos > offset + length) {
+				read_unlock_bh(&dn_neigh_table.lock);
+                       		goto done;
+			}
X 		}
+		read_unlock_bh(&dn_neigh_table.lock);
X 	}
-	neigh_table_unlock(&dn_neigh_table);
+
+done:
X 
X         *start = buffer + (offset - begin);
X         len   -= offset - begin;
diff -u --recursive --new-file v2.3.5/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v2.3.5/linux/net/ethernet/eth.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ethernet/eth.c	Wed Jun  9 14:45:36 1999
@@ -248,6 +248,7 @@
X 	eth->h_proto = type;
X 	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
X 	memcpy(eth->h_dest, neigh->ha, dev->addr_len);
+ hh->hh_len = ETH_HLEN;
X 	return 0;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.5/linux/net/ipv4/af_inet.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/af_inet.c	Wed Jun  9 14:45:36 1999
@@ -5,7 +5,7 @@
X  *
X  *		PF_INET protocol family socket handler.
X  *
- * Version:	$Id: af_inet.c,v 1.90 1999/05/29 04:30:38 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.91 1999/06/09 08:28:55 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -371,7 +371,7 @@
X 		if (protocol && protocol != IPPROTO_UDP)
X 			goto free_and_noproto;
X 		protocol = IPPROTO_UDP;
-		sk->no_check = UDP_NO_CHECK;
+		sk->no_check = UDP_CSUM_DEFAULT;
X 		sk->ip_pmtudisc = IP_PMTUDISC_DONT;
X 		prot=&udp_prot;
X 		sock->ops = &inet_dgram_ops;
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.3.5/linux/net/ipv4/arp.c	Sun Mar 21 07:22:00 1999
+++ linux/net/ipv4/arp.c	Wed Jun  9 14:45:36 1999
@@ -1,6 +1,6 @@
X /* linux/net/inet/arp.c
X  *
- * Version:	$Id: arp.c,v 1.77 1999/03/21 05:22:30 davem Exp $
+ * Version:	$Id: arp.c,v 1.78 1999/06/09 10:10:36 davem Exp $
X  *
X  * Copyright (C) 1994 by Florian  La Roche
X  *
@@ -119,6 +119,11 @@
X #include <asm/system.h>
X #include <asm/uaccess.h>
X 
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+static char *ax2asc2(ax25_address *a, char *buf);
+#endif
+
+
X /*
X  *	Interface to generic neighbour cache.
X  */
@@ -304,7 +309,7 @@
X 	u8  *dst_ha = NULL;
X 	struct device *dev = neigh->dev;
X 	u32 target = *(u32*)neigh->primary_key;
-	int probes = neigh->probes;
+	int probes = atomic_read(&neigh->probes);
X 
X 	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
X 		saddr = skb->nh.iph->saddr;
@@ -315,6 +320,7 @@
X 		if (!(neigh->nud_state&NUD_VALID))
X 			printk(KERN_DEBUG "trying to ucast probe in NUD_INVALID\n");
X 		dst_ha = neigh->ha;
+		read_lock_bh(&neigh->lock);
X 	} else if ((probes -= neigh->parms->app_probes) < 0) {
X #ifdef CONFIG_ARPD
X 		neigh_app_ns(neigh);
@@ -324,6 +330,8 @@
X 
X 	arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
X 		 dst_ha, dev->dev_addr, NULL);
+	if (dst_ha)
+		read_unlock_bh(&neigh->lock);
X }
X 
X /* OBSOLETE FUNCTIONS */
@@ -372,29 +380,25 @@
X 	if (arp_set_predefined(inet_addr_type(paddr), haddr, paddr, dev))
X 		return 0;
X 
-	start_bh_atomic();
X 	n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);
X 
X 	if (n) {
X 		n->used = jiffies;
X 		if (n->nud_state&NUD_VALID || neigh_event_send(n, skb) == 0) {
-			memcpy(haddr, n->ha, dev->addr_len);
+			read_lock_bh(&n->lock);
+ 			memcpy(haddr, n->ha, dev->addr_len);
+			read_unlock_bh(&n->lock);
X 			neigh_release(n);
-			end_bh_atomic();
X 			return 0;
X 		}
+		neigh_release(n);
X 	} else
X 		kfree_skb(skb);
-	neigh_release(n);
-	end_bh_atomic();
X 	return 1;
X }
X 
X /* END OF OBSOLETE FUNCTIONS */
X 
-/*
- * Note: requires bh_atomic locking.
- */
X int arp_bind_neighbour(struct dst_entry *dst)
X {
X 	struct device *dev = dst->dev;
@@ -672,7 +676,8 @@
X 			    (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
X 			     (IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
X 				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
-				neigh_release(n);
+				if (n)
+					neigh_release(n);
X 
X 				if (skb->stamp.tv_sec == 0 ||
X 				    skb->pkt_type == PACKET_HOST ||
@@ -785,7 +790,6 @@
X 		return -EINVAL;
X 
X 	err = -ENOBUFS;
-	start_bh_atomic();
X 	neigh = __neigh_lookup(&arp_tbl, &ip, dev, 1);
X 	if (neigh) {
X 		unsigned state = NUD_STALE;
@@ -795,7 +799,6 @@
X 				   r->arp_ha.sa_data : NULL, state, 1, 0);
X 		neigh_release(neigh);
X 	}
-	end_bh_atomic();
X 	return err;
X }
X 
@@ -819,17 +822,17 @@
X 	struct neighbour *neigh;
X 	int err = -ENXIO;
X 
-	start_bh_atomic();
-	neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0);
+	neigh = neigh_lookup(&arp_tbl, &ip, dev);
X 	if (neigh) {
+		read_lock_bh(&neigh->lock);
X 		memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
+		r->arp_flags = arp_state_to_flags(neigh);
+		read_unlock_bh(&neigh->lock);
X 		r->arp_ha.sa_family = dev->type;
X 		strncpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
-		r->arp_flags = arp_state_to_flags(neigh);
X 		neigh_release(neigh);
X 		err = 0;
X 	}
-	end_bh_atomic();
X 	return err;
X }
X 
@@ -867,14 +870,12 @@
X 			return -EINVAL;
X 	}
X 	err = -ENXIO;
-	start_bh_atomic();
-	neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0);
+	neigh = neigh_lookup(&arp_tbl, &ip, dev);
X 	if (neigh) {
X 		if (neigh->nud_state&~NUD_NOARP)
X 			err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0);
X 		neigh_release(neigh);
X 	}
-	end_bh_atomic();
X 	return err;
X }
X 
@@ -961,16 +962,16 @@
X 	char hbuffer[HBUFFERLEN];
X 	int i,j,k;
X 	const char hexbuf[] =  "0123456789ABCDEF";
+	char abuf[16];
X 
X 	size = sprintf(buffer,"IP address       HW type     Flags       HW address            Mask     Device\n");
X 
X 	pos+=size;
X 	len+=size;
X 
-	neigh_table_lock(&arp_tbl);
-
-	for(i=0; i<=NEIGH_HASHMASK; i++)	{
+	for(i=0; i<=NEIGH_HASHMASK; i++) {
X 		struct neighbour *n;
+		read_lock_bh(&arp_tbl.lock);
X 		for (n=arp_tbl.hash_buckets[i]; n; n=n->next) {
X 			struct device *dev = n->dev;
X 			int hatype = dev->type;
@@ -979,17 +980,14 @@
X 			if (!(n->nud_state&~NUD_NOARP))
X 				continue;
X 
-			/* I'd get great pleasure deleting
-			   this ugly code. Let's output it in hexadecimal format.
-			   "arp" utility will eventually repaired  --ANK
-			 */
-#if 1 /* UGLY CODE */
+			read_lock(&n->lock);
+
X /*
X  *	Convert hardware address to XX:XX:XX:XX ... form.
X  */
X #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
X 			if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM)
-			     strcpy(hbuffer,ax2asc((ax25_address *)n->ha));
+				ax2asc2((ax25_address *)n->ha, hbuffer);
X 			else {
X #endif
X 			for (k=0,j=0;k<HBUFFERLEN-3 && j<dev->addr_len;j++) {
@@ -998,37 +996,33 @@
X 				hbuffer[k++]=':';
X 			}
X 			hbuffer[--k]=0;
-	
+
X #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
X 		}
X #endif
-#else
-			if ((neigh->nud_state&NUD_VALID) && dev->addr_len) {
-				int j;
-				for (j=0; j < dev->addr_len; j++)
-					sprintf(hbuffer+2*j, "%02x", neigh->ha[j]);
-			} else
-				sprintf(hbuffer, "0");
-#endif
X 
X 			size = sprintf(buffer+len,
X 				"%-17s0x%-10x0x%-10x%s",
-				in_ntoa(*(u32*)n->primary_key),
+				in_ntoa2(*(u32*)n->primary_key, abuf),
X 				hatype,
X 				arp_state_to_flags(n), 
X 				hbuffer);
X 			size += sprintf(buffer+len+size,
X 				 "     %-17s %s\n",
X 				 "*", dev->name);
+			read_unlock(&n->lock);
X 
X 			len += size;
X 			pos += size;
X 		  
X 			if (pos <= offset)
X 				len=0;
-			if (pos >= offset+length)
-				goto done;
+			if (pos >= offset+length) {
+				read_unlock_bh(&arp_tbl.lock);
+ 				goto done;
+			}
X 		}
+		read_unlock_bh(&arp_tbl.lock);
X 	}
X 
X 	for (i=0; i<=PNEIGH_HASHMASK; i++) {
@@ -1039,7 +1033,7 @@
X 
X 			size = sprintf(buffer+len,
X 				"%-17s0x%-10x0x%-10x%s",
-				in_ntoa(*(u32*)n->key),
+				in_ntoa2(*(u32*)n->key, abuf),
X 				hatype,
X  				ATF_PUBL|ATF_PERM,
X 				"00:00:00:00:00:00");
@@ -1058,7 +1052,6 @@
X 	}
X 
X done:
-	neigh_table_unlock(&arp_tbl);
X   
X 	*start = buffer+len-(pos-offset);	/* Start of wanted data */
X 	len = pos-offset;			/* Start slop */
@@ -1117,14 +1110,13 @@
X }
X 
X 
-#ifdef CONFIG_AX25_MODULE
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
X 
X /*
X  *	ax25 -> ASCII conversion
X  */
-char *ax2asc(ax25_address *a)
+char *ax2asc2(ax25_address *a, char *buf)
X {
-	static char buf[11];
X 	char c, *s;
X 	int n;
X 
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.3.5/linux/net/ipv4/devinet.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv4/devinet.c	Wed Jun  9 14:45:36 1999
@@ -1,7 +1,7 @@
X /*
X  *	NET3	IP device support routines.
X  *
- *	Version: $Id: devinet.c,v 1.30 1999/06/01 07:49:59 davem Exp $
+ *	Version: $Id: devinet.c,v 1.32 1999/06/09 11:15:33 davem Exp $
X  *
X  *		This program is free software; you can redistribute it and/or
X  *		modify it under the terms of the GNU General Public License
@@ -636,10 +636,10 @@
X 	return done;
X }
X 
-u32 inet_select_addr(struct device *dev, u32 dst, int scope)
+u32 inet_select_addr(const struct device *dev, u32 dst, int scope)
X {
X 	u32 addr = 0;
-	struct in_device *in_dev = dev->ip_ptr;
+	const struct in_device *in_dev = dev->ip_ptr;
X 
X 	if (in_dev == NULL)
X 		return 0;
@@ -659,19 +659,19 @@
X 	   in this case. It is importnat that lo is the first interface
X 	   in dev_base list.
X 	 */
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev=dev_base; dev; dev=dev->next) {
X 		if ((in_dev=dev->ip_ptr) == NULL)
X 			continue;
X 
X 		for_primary_ifa(in_dev) {
X 			if (ifa->ifa_scope <= scope) {
-				read_unlock_bh(&dev_base_lock);
+				read_unlock(&dev_base_lock);
X 				return ifa->ifa_local;
X 			}
X 		} endfor_ifa(in_dev);
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	return 0;
X }
@@ -792,7 +792,7 @@
X 
X 	s_idx = cb->args[0];
X 	s_ip_idx = ip_idx = cb->args[1];
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
X 		if (idx < s_idx)
X 			continue;
@@ -810,7 +810,7 @@
X 		}
X 	}
X done:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	cb->args[0] = idx;
X 	cb->args[1] = ip_idx;
X 
@@ -885,13 +885,13 @@
X 	ipv4_devconf.accept_redirects = !on;
X 	ipv4_devconf_dflt.forwarding = on;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev; dev = dev->next) {
X 		struct in_device *in_dev = dev->ip_ptr;
X 		if (in_dev)
X 			in_dev->cnf.forwarding = on;
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	rt_cache_flush(0);
X 
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.3.5/linux/net/ipv4/fib_frontend.c	Sun Mar 21 07:22:00 1999
+++ linux/net/ipv4/fib_frontend.c	Wed Jun  9 14:45:36 1999
@@ -5,7 +5,7 @@
X  *
X  *		IPv4 Forwarding Information Base: FIB frontend.
X  *
- * Version:	$Id: fib_frontend.c,v 1.15 1999/03/21 05:22:31 davem Exp $
+ * Version:	$Id: fib_frontend.c,v 1.16 1999/06/09 10:10:42 davem Exp $
X  *
X  * Authors:	Alexey Kuznetsov, <kuz...@ms2.inr.ac.ru>
X  *
@@ -123,13 +123,11 @@
X 		first = 0;
X   	}
X 
-	/* rtnl_shlock(); -- it is pointless at the moment --ANK */
X 	if (main_table && count > 0) {
X 		int n = main_table->tb_get_info(main_table, ptr, first, count);
X 		count -= n;
X 		ptr += n*128;
X 	}
-	/* rtnl_shunlock(); */
X 	len = ptr - *start;
X 	if (len >= length)
X 		return length;
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
--- v2.3.5/linux/net/ipv4/fib_hash.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/fib_hash.c	Wed Jun  9 14:45:36 1999
@@ -5,7 +5,7 @@
X  *
X  *		IPv4 FIB: lookup engine and maintenance routines.
X  *
- * Version:	$Id: fib_hash.c,v 1.9 1999/05/27 00:38:05 davem Exp $
+ * Version:	$Id: fib_hash.c,v 1.10 1999/06/09 10:10:45 davem Exp $
X  *
X  * Authors:	Alexey Kuznetsov, <kuz...@ms2.inr.ac.ru>
X  *
@@ -246,10 +246,10 @@
X 	fz->fz_mask = inet_make_mask(z);
X 
X 	/* Find the first not empty zone with more specific mask */
-	write_lock_bh(&fib_hash_lock);
X 	for (i=z+1; i<=32; i++)
X 		if (table->fn_zones[i])
X 			break;
+	write_lock_bh(&fib_hash_lock);
X 	if (i>32) {
X 		/* No more specific masks, we are the first. */
X 		fz->fz_next = table->fn_zone_list;
@@ -270,7 +270,7 @@
X 	struct fn_zone *fz;
X 	struct fn_hash *t = (struct fn_hash*)tb->tb_data;
X 
-	read_lock_bh(&fib_hash_lock);
+	read_lock(&fib_hash_lock);
X 	for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
X 		struct fib_node *f;
X 		fn_key_t k = fz_key(key->dst, fz);
@@ -307,7 +307,7 @@
X 	}
X 	err = 1;
X out:
-	read_unlock_bh(&fib_hash_lock);
+	read_unlock(&fib_hash_lock);
X 	return err;
X }
X 
@@ -353,7 +353,7 @@
X 	last_resort = NULL;
X 	order = -1;
X 
-	read_lock_bh(&fib_hash_lock);
+	read_lock(&fib_hash_lock);
X 	for (f = fz->fz_hash[0]; f; f = f->fn_next) {
X 		struct fib_info *next_fi = FIB_INFO(f);
X 
@@ -395,7 +395,7 @@
X 		res->fi = last_resort;
X 	fn_hash_last_dflt = last_idx;
X out:
-	read_unlock_bh(&fib_hash_lock);
+	read_unlock(&fib_hash_lock);
X }
X 
X #define FIB_SCAN(f, fp) \
@@ -469,7 +469,6 @@
X 
X 	fp = fz_chain_p(key, fz);
X 
-	write_lock_bh(&fib_hash_lock);
X 
X 	/*
X 	 * Scan list to find the first route with the same destination
@@ -574,12 +573,15 @@
X 	 */
X 
X 	new_f->fn_next = f;
+	write_lock_bh(&fib_hash_lock);
X 	*fp = new_f;
+	write_unlock_bh(&fib_hash_lock);
X 	fz->fz_nent++;
X 
X 	if (del_fp) {
X 		f = *del_fp;
X 		/* Unlink replaced node */
+		write_lock_bh(&fib_hash_lock);
X 		*del_fp = f->fn_next;
X 		write_unlock_bh(&fib_hash_lock);
X 
@@ -590,14 +592,12 @@
X 		fn_free_node(f);
X 		fz->fz_nent--;
X 	} else {
-		write_unlock_bh(&fib_hash_lock);
X 		rt_cache_flush(-1);
X 	}
X 	rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->tb_id, n, req);
X 	return 0;
X 
X out:
-	write_unlock_bh(&fib_hash_lock);
X 	fib_release_info(fi);
X 	return err;
X }
@@ -635,13 +635,11 @@
X 
X 	fp = fz_chain_p(key, fz);
X 
-	write_lock_bh(&fib_hash_lock);
X 
X 	FIB_SCAN(f, fp) {
X 		if (fn_key_eq(f->fn_key, key))
X 			break;
X 		if (fn_key_leq(key, f->fn_key)) {
-			write_unlock_bh(&fib_hash_lock);
X 			return -ESRCH;
X 		}
X 	}
@@ -658,7 +656,6 @@
X 		struct fib_info * fi = FIB_INFO(f);
X 
X 		if (f->fn_state&FN_S_ZOMBIE) {
-			write_unlock_bh(&fib_hash_lock);
X 			return -ESRCH;
X 		}
X 		matched++;
@@ -676,6 +673,7 @@
X 		rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
X 
X 		if (matched != 1) {
+			write_lock_bh(&fib_hash_lock);
X 			*del_fp = f->fn_next;
X 			write_unlock_bh(&fib_hash_lock);
X 
@@ -684,7 +682,6 @@
X 			fn_free_node(f);
X 			fz->fz_nent--;
X 		} else {
-			write_unlock_bh(&fib_hash_lock);
X 			f->fn_state |= FN_S_ZOMBIE;
X 			if (f->fn_state&FN_S_ACCESSED) {
X 				f->fn_state &= ~FN_S_ACCESSED;
@@ -696,7 +693,6 @@
X 
X 		return 0;
X 	}
-	write_unlock_bh(&fib_hash_lock);
X 	return -ESRCH;
X }
X 
@@ -710,7 +706,9 @@
X 		struct fib_info *fi = FIB_INFO(f);
X 
X 		if (fi && ((f->fn_state&FN_S_ZOMBIE) || (fi->fib_flags&RTNH_F_DEAD))) {
+			write_lock_bh(&fib_hash_lock);
X 			*fp = f->fn_next;
+			write_unlock_bh(&fib_hash_lock);
X 
X 			fn_free_node(f);
X 			found++;
@@ -728,7 +726,6 @@
X 	int found = 0;
X 
X 	fib_hash_zombies = 0;
-	write_lock_bh(&fib_hash_lock);
X 	for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
X 		int i;
X 		int tmp = 0;
@@ -737,7 +734,6 @@
X 		fz->fz_nent -= tmp;
X 		found += tmp;
X 	}
-	write_unlock_bh(&fib_hash_lock);
X 	return found;
X }
X 
@@ -751,7 +747,7 @@
X 	int pos = 0;
X 	int n = 0;
X 
-	read_lock_bh(&fib_hash_lock);
+	read_lock(&fib_hash_lock);
X 	for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {
X 		int i;
X 		struct fib_node *f;
@@ -782,7 +778,7 @@
X 		}
X 	}
X out:
-	read_unlock_bh(&fib_hash_lock);
+	read_unlock(&fib_hash_lock);
X   	return n;
X }
X #endif
@@ -845,18 +841,18 @@
X 	struct fn_hash *table = (struct fn_hash*)tb->tb_data;
X 
X 	s_m = cb->args[1];
-	read_lock_bh(&fib_hash_lock);
+	read_lock(&fib_hash_lock);
X 	for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
X 		if (m < s_m) continue;
X 		if (m > s_m)
X 			memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
X 		if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
X 			cb->args[1] = m;
-			read_unlock_bh(&fib_hash_lock);
+			read_unlock(&fib_hash_lock);
X 			return -1;
X 		}
X 	}
-	read_unlock_bh(&fib_hash_lock);
+	read_unlock(&fib_hash_lock);
X 	cb->args[1] = m;
X 	return skb->len;
X }
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
--- v2.3.5/linux/net/ipv4/fib_rules.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/fib_rules.c	Wed Jun  9 14:45:36 1999
@@ -5,7 +5,7 @@
X  *
X  *		IPv4 Forwarding Information Base: policy rules.
X  *
- * Version:	$Id: fib_rules.c,v 1.10 1999/05/27 00:38:03 davem Exp $
+ * Version:	$Id: fib_rules.c,v 1.11 1999/06/09 10:10:47 davem Exp $
X  *
X  * Authors:	Alexey Kuznetsov, <kuz...@ms2.inr.ac.ru>
X  *
@@ -88,7 +88,6 @@
X 	struct fib_rule *r, **rp;
X 	int err = -ESRCH;
X 
-	write_lock_bh(&fib_rules_lock);
X 	for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
X 		if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
X 		    rtm->rtm_src_len == r->r_src_len &&
@@ -106,14 +105,15 @@
X 			if (r == &local_rule)
X 				break;
X 
+			write_lock_bh(&fib_rules_lock);
X 			*rp = r->r_next;
+			write_unlock_bh(&fib_rules_lock);
X 			if (r != &default_rule && r != &main_rule)
X 				kfree(r);
X 			err = 0;
X 			break;
X 		}
X 	}
-	write_unlock_bh(&fib_rules_lock);
X 	return err;
X }
X 
@@ -192,7 +192,6 @@
X 		memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
X #endif
X 
-	write_lock_bh(&fib_rules_lock);
X 	rp = &fib_rules;
X 	if (!new_r->r_preference) {
X 		r = fib_rules;
@@ -210,6 +209,7 @@
X 	}
X 
X 	new_r->r_next = r;
+	write_lock_bh(&fib_rules_lock);
X 	*rp = new_r;
X 	write_unlock_bh(&fib_rules_lock);
X 	return 0;
@@ -255,24 +255,26 @@
X {
X 	struct fib_rule *r;
X 
-	write_lock_bh(&fib_rules_lock);
X 	for (r=fib_rules; r; r=r->r_next) {
-		if (r->r_ifindex == dev->ifindex)
+		if (r->r_ifindex == dev->ifindex) {
+			write_lock_bh(&fib_rules_lock);
X 			r->r_ifindex = -1;
+			write_unlock_bh(&fib_rules_lock);
+		}
X 	}
-	write_unlock_bh(&fib_rules_lock);
X }
X 
X static void fib_rules_attach(struct device *dev)
X {
X 	struct fib_rule *r;
X 
-	write_lock_bh(&fib_rules_lock);
X 	for (r=fib_rules; r; r=r->r_next) {
-		if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
+		if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
+			write_lock_bh(&fib_rules_lock);
X 			r->r_ifindex = dev->ifindex;
+			write_unlock_bh(&fib_rules_lock);
+		}
X 	}
-	write_unlock_bh(&fib_rules_lock);
X }
X 
X int fib_lookup(const struct rt_key *key, struct fib_result *res)
@@ -285,7 +287,7 @@
X 	u32 saddr = key->src;
X 
X FRprintk("Lookup: %08x <- %08x ", key->dst, key->src);
-	read_lock_bh(&fib_rules_lock);
+	read_lock(&fib_rules_lock);
X 	for (r = fib_rules; r; r=r->r_next) {
X 		if (((saddr^r->r_src) & r->r_srcmask) ||
X 		    ((daddr^r->r_dst) & r->r_dstmask) ||
@@ -305,14 +307,14 @@
X 			policy = r;
X 			break;
X 		case RTN_UNREACHABLE:
-			read_unlock_bh(&fib_rules_lock);
+			read_unlock(&fib_rules_lock);
X 			return -ENETUNREACH;
X 		default:
X 		case RTN_BLACKHOLE:
-			read_unlock_bh(&fib_rules_lock);
+			read_unlock(&fib_rules_lock);
X 			return -EINVAL;
X 		case RTN_PROHIBIT:
-			read_unlock_bh(&fib_rules_lock);
+			read_unlock(&fib_rules_lock);
X 			return -EACCES;
X 		}
X 
@@ -322,16 +324,16 @@
X 		if (err == 0) {
X FRprintk("ok\n");
X 			res->r = policy;
-			read_unlock_bh(&fib_rules_lock);
+			read_unlock(&fib_rules_lock);
X 			return 0;
X 		}
X 		if (err < 0 && err != -EAGAIN) {
-			read_unlock_bh(&fib_rules_lock);
+			read_unlock(&fib_rules_lock);
X 			return err;
X 		}
X 	}
X FRprintk("FAILURE\n");
-	read_unlock_bh(&fib_rules_lock);
+	read_unlock(&fib_rules_lock);
X 	return -ENETUNREACH;
X }
X 
@@ -418,14 +420,14 @@
X 	int s_idx = cb->args[0];
X 	struct fib_rule *r;
X 
-	read_lock_bh(&fib_rules_lock);
+	read_lock(&fib_rules_lock);
X 	for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
X 		if (idx < s_idx)
X 			continue;
X 		if (inet_fill_rule(skb, r, cb) < 0)
X 			break;
X 	}
-	read_unlock_bh(&fib_rules_lock);
+	read_unlock(&fib_rules_lock);
X 	cb->args[0] = idx;
X 
X 	return skb->len;
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.3.5/linux/net/ipv4/icmp.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv4/icmp.c	Wed Jun  9 14:45:37 1999
@@ -3,7 +3,7 @@
X  *	
X  *		Alan Cox, <al...@redhat.com>
X  *
- *	Version: $Id: icmp.c,v 1.54 1999/05/30 01:16:22 davem Exp $
+ *	Version: $Id: icmp.c,v 1.57 1999/06/09 10:10:50 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *	modify it under the terms of the GNU General Public License
@@ -699,8 +699,8 @@
X 			case ICMP_FRAG_NEEDED:
X 				if (ipv4_config.no_pmtu_disc) {
X 					if (net_ratelimit())
-						printk(KERN_INFO "ICMP: %s: fragmentation needed and DF set.\n",
-					       in_ntoa(iph->daddr));
+						printk(KERN_INFO "ICMP: %d.%d.%d.%d: fragmentation needed and DF set.\n",
+						       NIPQUAD(iph->daddr));
X 				} else {
X 					unsigned short new_mtu;
X 					new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));
@@ -711,7 +711,7 @@
X 				break;
X 			case ICMP_SR_FAILED:
X 				if (net_ratelimit())
-					printk(KERN_INFO "ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
+					printk(KERN_INFO "ICMP: %d.%d.%d.%d: Source Route Failed.\n", NIPQUAD(iph->daddr));
X 				break;
X 			default:
X 				break;
@@ -741,8 +741,8 @@
X 		if (inet_addr_type(iph->daddr) == RTN_BROADCAST)
X 		{
X 			if (net_ratelimit())
-				printk(KERN_WARNING "%s sent an invalid ICMP error to a broadcast.\n",
-			       	in_ntoa(skb->nh.iph->saddr));
+				printk(KERN_WARNING "%d.%d.%d.%d sent an invalid ICMP error to a broadcast.\n",
+			       	NIPQUAD(skb->nh.iph->saddr));
X 			return; 
X 		}
X 	}
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.3.5/linux/net/ipv4/igmp.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/igmp.c	Wed Jun  9 14:45:37 1999
@@ -8,7 +8,7 @@
X  *	the older version didn't come out right using gcc 2.5.8, the newer one
X  *	seems to fall out with gcc 2.6.2.
X  *
- *	Version: $Id: igmp.c,v 1.31 1999/05/27 00:37:59 davem Exp $
+ *	Version: $Id: igmp.c,v 1.32 1999/06/09 10:10:53 davem Exp $
X  *
X  *	Authors:
X  *		Alan Cox <Alan...@linux.org>
@@ -97,6 +97,15 @@
X #include <linux/mroute.h>
X #endif
X 
+/* Big mc list lock for all the devices */
+static rwlock_t ip_mc_lock = RW_LOCK_UNLOCKED;
+/* Big mc list semaphore for all the sockets.
+   We do not refer to this list in IP data paths or from BH,
+   so that semaphore is OK.
+ */
+DECLARE_MUTEX(ip_sk_mc_sem);
+
+
X #define IP_MAX_MEMBERSHIPS 20
X 
X #ifdef CONFIG_IP_MULTICAST
@@ -216,6 +225,8 @@
X 	struct in_device *in_dev = im->interface;
X 	int err;
X 
+	read_lock(&ip_mc_lock);
+
X 	im->tm_running=0;
X 
X 	if (IGMP_V1_SEEN(in_dev))
@@ -234,6 +245,7 @@
X 		igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
X 	}
X 	im->reporter = 1;
+	read_unlock(&ip_mc_lock);
X }
X 
X static void igmp_heard_report(struct in_device *in_dev, u32 group)
@@ -245,14 +257,16 @@
X 	if (LOCAL_MCAST(group))
X 		return;
X 
+	read_lock(&ip_mc_lock);
X 	for (im=in_dev->mc_list; im!=NULL; im=im->next) {
X 		if (im->multiaddr == group) {
X 			igmp_stop_timer(im);
X 			im->reporter = 0;
X 			im->unsolicit_count = 0;
-			return;
+			break;
X 		}
X 	}
+	read_unlock(&ip_mc_lock);
X }
X 
X static void igmp_heard_query(struct in_device *in_dev, unsigned char max_resp_time,
@@ -281,6 +295,7 @@
X 	 * - Use the igmp->igmp_code field as the maximum
X 	 *   delay possible
X 	 */
+	read_lock(&ip_mc_lock);
X 	for (im=in_dev->mc_list; im!=NULL; im=im->next) {
X 		if (group && group != im->multiaddr)
X 			continue;
@@ -291,6 +306,7 @@
X 			igmp_stop_timer(im);
X 		igmp_start_timer(im, max_delay);
X 	}
+	read_unlock(&ip_mc_lock);
X }
X 
X int igmp_rcv(struct sk_buff *skb, unsigned short len)
@@ -380,9 +396,7 @@
X 	if (LOCAL_MCAST(im->multiaddr))
X 		return;
X 
-	start_bh_atomic();
X 	igmp_stop_timer(im);
-	end_bh_atomic();
X 
X 	if (im->reporter && !IGMP_V1_SEEN(im->interface))
X 		igmp_send_report(im->interface->dev, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
@@ -400,9 +414,7 @@
X 	if (LOCAL_MCAST(im->multiaddr))
X 		return;
X 
-	start_bh_atomic();
X 	igmp_start_timer(im, IGMP_Initial_Report_Delay);
-	end_bh_atomic();
X #endif
X }
X 
@@ -422,16 +434,17 @@
X 
X 	im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL);
X 
+	write_lock_bh(&ip_mc_lock);
X 	for (i=in_dev->mc_list; i; i=i->next) {
X 		if (i->multiaddr == addr) {
X 			i->users++;
X 			if (im)
X 				kfree(im);
-			return;
+			goto out;
X 		}
X 	}
X if (!im)
-		return;
+		goto out;
X 	im->users=1;
X 	im->interface=in_dev;
X 	im->multiaddr=addr;
@@ -447,9 +460,13 @@
X 	im->next=in_dev->mc_list;
X 	in_dev->mc_list=im;
X 	igmp_group_added(im);
+	write_unlock_bh(&ip_mc_lock);
X 	if (in_dev->dev->flags & IFF_UP)
X 		ip_rt_multicast_event(in_dev);
X 	return;
+out:
+	write_unlock_bh(&ip_mc_lock);
+	return;
X }
X 
X /*
@@ -458,22 +475,27 @@
X 
X int ip_mc_dec_group(struct in_device *in_dev, u32 addr)
X {
+	int err = -ESRCH;
X 	struct ip_mc_list *i, **ip;
X 
+	write_lock_bh(&ip_mc_lock);
X 	for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
X 		if (i->multiaddr==addr) {
X 			if (--i->users == 0) {
X 				*ip = i->next;
-				synchronize_bh();
-
X 				igmp_group_dropped(i);
+
+				write_unlock_bh(&ip_mc_lock);
X 				if (in_dev->dev->flags & IFF_UP)
X 					ip_rt_multicast_event(in_dev);
X 				kfree_s(i, sizeof(*i));
+				return 0;
X 			}
-			return 0;
+			err = 0;
+			break;
X 		}
X 	}
+	write_unlock_bh(&ip_mc_lock);
X 	return -ESRCH;
X }
X 
@@ -483,8 +505,10 @@
X {
X 	struct ip_mc_list *i;
X 
+	read_lock_bh(&ip_mc_lock);
X 	for (i=in_dev->mc_list; i; i=i->next)
X 		igmp_group_dropped(i);
+	read_unlock_bh(&ip_mc_lock);
X 
X 	ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
X }
@@ -497,8 +521,10 @@
X 
X 	ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
X 
+	read_lock_bh(&ip_mc_lock);
X 	for (i=in_dev->mc_list; i; i=i->next)
X 		igmp_group_added(i);
+	read_unlock_bh(&ip_mc_lock);
X }
X 
X /*
@@ -509,11 +535,13 @@
X {
X 	struct ip_mc_list *i;
X 
+	write_lock_bh(&ip_mc_lock);
X 	while ((i = in_dev->mc_list) != NULL) {
X 		in_dev->mc_list = i->next;
X 		igmp_group_dropped(i);
X 		kfree_s(i, sizeof(*i));
X 	}
+	write_unlock_bh(&ip_mc_lock);
X }
X 
X static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
@@ -570,6 +598,7 @@
X 	iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
X 
X 	err = -EADDRINUSE;
+	down(&ip_sk_mc_sem);
X 	for (i=sk->ip_mc_list; i; i=i->next) {
X 		if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {
X 			/* New style additions are reference counted */
@@ -577,13 +606,13 @@
X 				i->count++;
X 				err = 0;
X 			}
-			goto done;
+			goto done_unlock;
X 		}
X 		count++;
X 	}
X 	err = -ENOBUFS;
X 	if (iml == NULL || count >= sysctl_igmp_max_memberships)
-		goto done;
+		goto done_unlock;
X 	memcpy(&iml->multi, imr, sizeof(*imr));
X 	iml->next = sk->ip_mc_list;
X 	iml->count = 1;
@@ -591,6 +620,9 @@
X 	ip_mc_inc_group(in_dev, addr);
X 	iml = NULL;
X 	err = 0;
+
+done_unlock:
+	up(&ip_sk_mc_sem);
X done:
X 	rtnl_shunlock();
X 	if (iml)
@@ -606,6 +638,7 @@
X {
X 	struct ip_mc_socklist *iml, **imlp;
X 
+	down(&ip_sk_mc_sem);
X 	for (imlp=&sk->ip_mc_list; (iml=*imlp)!=NULL; imlp=&iml->next) {
X 		if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr &&
X 		    iml->multi.imr_address.s_addr==imr->imr_address.s_addr &&
@@ -615,7 +648,7 @@
X 				return 0;
X 
X 			*imlp = iml->next;
-			synchronize_bh();
+			up(&ip_sk_mc_sem);
X 
X 			in_dev = inetdev_by_index(iml->multi.imr_ifindex);
X 			if (in_dev)
@@ -624,6 +657,7 @@
X 			return 0;
X 		}
X 	}
+	up(&ip_sk_mc_sem);
X 	return -EADDRNOTAVAIL;
X }
X 
@@ -635,13 +669,37 @@
X {
X 	struct ip_mc_socklist *iml;
X 
+	down(&ip_sk_mc_sem);
X 	while ((iml=sk->ip_mc_list) != NULL) {
X 		struct in_device *in_dev;
X 		sk->ip_mc_list = iml->next;
+		up(&ip_sk_mc_sem);
+
X 		if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL)
X 			ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
X 		sock_kfree_s(sk, iml, sizeof(*iml));
+
+		down(&ip_sk_mc_sem);
X 	}
+	up(&ip_sk_mc_sem);
+}
+
+int ip_check_mc(struct device *dev, u32 mc_addr)
+{
+	struct in_device *in_dev = dev->ip_ptr;
+	struct ip_mc_list *im;
+
+	if (in_dev) {
+		read_lock(&ip_mc_lock);
+		for (im=in_dev->mc_list; im; im=im->next) {
+			if (im->multiaddr == mc_addr) {
+				read_unlock(&ip_mc_lock);
+				return 1;
+			}
+		}
+		read_unlock(&ip_mc_lock);
+	}
+	return 0;
X }
X 
X 
@@ -653,10 +711,10 @@
X 	struct ip_mc_list *im;
X 	int len=0;
X 	struct device *dev;
-	
+
X 	len=sprintf(buffer,"Idx\tDevice    : Count Querier\tGroup    Users Timer\tReporter\n");  
-	
-	read_lock_bh(&dev_base_lock);
+
+	read_lock(&dev_base_lock);
X 	for(dev = dev_base; dev; dev = dev->next) {
X 		struct in_device *in_dev = dev->ip_ptr;
X 		char   *querier = "NONE";
@@ -669,6 +727,7 @@
X 		len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
X 			     dev->ifindex, dev->name, dev->mc_count, querier);
X 
+		read_lock(&ip_mc_lock);
X 		for (im = in_dev->mc_list; im; im = im->next) {
X 			len+=sprintf(buffer+len,
X 				     "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
@@ -681,12 +740,15 @@
X 				len=0;
X 				begin=pos;
X 			}
-			if(pos>offset+length)
+			if(pos>offset+length) {
+ read_unlock(&ip_mc_lock);
X 				goto done;
+			}
X 		}
+ read_unlock(&ip_mc_lock);
X 	}
X done:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	*start=buffer+(offset-begin);
X 	len-=(offset-begin);
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.3.5/linux/net/ipv4/ip_input.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/ip_input.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *
X  *		The Internet Protocol (IP) module.
X  *
- * Version:	$Id: ip_input.c,v 1.39 1999/05/30 01:16:25 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.40 1999/06/09 10:10:55 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -392,21 +392,17 @@
X 	if (skb->dst == NULL) {
X 		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
X 			goto drop; 
-#ifdef CONFIG_CPU_IS_SLOW
-		if (net_cpu_congestion > 10 && !(iph->tos&IPTOS_RELIABILITY) &&
-		    IPTOS_PREC(iph->tos) < IPTOS_PREC_INTERNETCONTROL) {
-			goto drop;
-		}
-#endif
X 	}
X 
X #ifdef CONFIG_NET_CLS_ROUTE
X 	if (skb->dst->tclassid) {
X 		u32 idx = skb->dst->tclassid;
+		write_lock(&ip_rt_acct_lock);
X 		ip_rt_acct[idx&0xFF].o_packets++;
X 		ip_rt_acct[idx&0xFF].o_bytes+=skb->len;
X 		ip_rt_acct[(idx>>16)&0xFF].i_packets++;
X 		ip_rt_acct[(idx>>16)&0xFF].i_bytes+=skb->len;
+		write_unlock(&ip_rt_acct_lock);
X 	}
X #endif
X 
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/ip_masq_vdolive.c linux/net/ipv4/ip_masq_vdolive.c
--- v2.3.5/linux/net/ipv4/ip_masq_vdolive.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv4/ip_masq_vdolive.c	Wed Jun  9 14:45:37 1999
@@ -2,7 +2,7 @@
X  *		IP_MASQ_VDOLIVE  - VDO Live masquerading module
X  *
X  *
- * Version:	@(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $
+ * Version:	@(#)$Id: ip_masq_vdolive.c,v 1.6 1999/06/09 08:29:03 davem Exp $
X  *
X  * Author:	Nigel Metheringham <Nigel.Met...@ThePLAnet.net>
X  *		PLAnet Online Ltd
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/ip_options.c linux/net/ipv4/ip_options.c
--- v2.3.5/linux/net/ipv4/ip_options.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv4/ip_options.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *
X  *		The options processing module for ip.c
X  *
- * Version:	$Id: ip_options.c,v 1.16 1999/03/21 05:22:40 davem Exp $
+ * Version:	$Id: ip_options.c,v 1.18 1999/06/09 08:29:06 davem Exp $
X  *
X  * Authors:	A.N.Kuznetsov
X  *		
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.3.5/linux/net/ipv4/ipconfig.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/ipconfig.c	Wed Jun  9 14:45:37 1999
@@ -1,5 +1,5 @@
X /*
- *  $Id: ipconfig.c,v 1.21 1999/05/27 00:38:01 davem Exp $
+ *  $Id: ipconfig.c,v 1.22 1999/06/09 10:10:57 davem Exp $
X  *
X  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
X  *  information to configure own IP address and routes.
@@ -112,7 +112,7 @@
X 	unsigned short oflags;
X 
X 	last = &ic_first_dev;
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev; dev = dev->next) {
X 		if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
X 		    (!(dev->flags & IFF_LOOPBACK) &&
@@ -144,7 +144,7 @@
X 			DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able));
X 		}
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	*last = NULL;
X 
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.3.5/linux/net/ipv4/ipmr.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv4/ipmr.c	Wed Jun  9 14:45:37 1999
@@ -9,7 +9,7 @@
X  *	as published by the Free Software Foundation; either version
X  *	2 of the License, or (at your option) any later version.
X  *
- *	Version: $Id: ipmr.c,v 1.40 1999/03/25 10:04:25 davem Exp $
+ *	Version: $Id: ipmr.c,v 1.43 1999/06/09 10:10:59 davem Exp $
X  *
X  *	Fixes:
X  *	Michael Chastain	:	Incorrect size of copying.
@@ -23,6 +23,8 @@
X  *	Brad Parker		:	Better behaviour on mrouted upcall
X  *					overflow.
X  *      Carlos Picoto           :       PIMv1 Support
+ *	Pavlin Ivanov Radoslavov:	PIMv2 Registers must checksum only PIM header
+ *					Relax this requrement to work with older peers.
X  *
X  */
X 
@@ -431,7 +433,7 @@
X 				skb_trim(skb, nlh->nlmsg_len);
X 				((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE;
X 			}
-			err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+			err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
X 		} else
X #endif
X 			ip_mr_forward(skb, cache, 0);
@@ -1343,7 +1345,8 @@
X 	    pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
X 	    (pim->flags&PIM_NULL_REGISTER) ||
X 	    reg_dev == NULL ||
-	    ip_compute_csum((void *)pim, len)) {
+	    (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
+	     ip_compute_csum((void *)pim, len))) {
X 		kfree_skb(skb);
X                 return -EINVAL;
X         }
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.3.5/linux/net/ipv4/route.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/route.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *
X  *		ROUTE - implementation of the IP router.
X  *
- * Version:	$Id: route.c,v 1.68 1999/05/27 00:37:54 davem Exp $
+ * Version:	$Id: route.c,v 1.69 1999/06/09 10:11:02 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -1996,6 +1996,7 @@
X 
X #ifdef CONFIG_NET_CLS_ROUTE
X struct ip_rt_acct ip_rt_acct[256];
+rwlock_t ip_rt_acct_lock = RW_LOCK_UNLOCKED;
X 
X #ifdef CONFIG_PROC_FS
X static int ip_rt_acct_read(char *buffer, char **start, off_t offset,
@@ -2008,9 +2009,9 @@
X 		*eof = 1;
X 	}
X 	if (length > 0) {
-		start_bh_atomic();
+		read_lock_bh(&ip_rt_acct_lock);
X 		memcpy(buffer, ((u8*)&ip_rt_acct)+offset, length);
-		end_bh_atomic();
+		read_unlock_bh(&ip_rt_acct_lock);
X 		return length;
X 	}
X 	return 0;
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.5/linux/net/ipv4/tcp_input.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv4/tcp_input.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *
X  *		Implementation of the Transmission Control Protocol(TCP).
X  *
- * Version:	$Id: tcp_input.c,v 1.167 1999/05/29 22:37:54 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.169 1999/06/09 08:29:13 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.5/linux/net/ipv4/tcp_ipv4.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/tcp_ipv4.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *
X  *		Implementation of the Transmission Control Protocol(TCP).
X  *
- * Version:	$Id: tcp_ipv4.c,v 1.178 1999/05/30 01:16:27 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.180 1999/06/09 08:29:19 davem Exp $
X  *
X  *		IPv4 specific functions
X  *
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.3.5/linux/net/ipv4/udp.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv4/udp.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *
X  *		The User Datagram Protocol (UDP).
X  *
- * Version:	$Id: udp.c,v 1.67 1999/05/27 00:37:50 davem Exp $
+ * Version:	$Id: udp.c,v 1.69 1999/06/09 11:15:31 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -173,7 +173,7 @@
X 	return 0;
X }
X 
-/* Shared by v4/v6 tcp. */
+/* Shared by v4/v6 udp. */
X unsigned short udp_good_socknum(void)
X {
X 	int result;
@@ -763,7 +763,10 @@
X 	/* 4.1.3.4. It's configurable by the application via setsockopt() */
X 	/* (MAY) and it defaults to on (MUST). */
X 
-	err = ip_build_xmit(sk,sk->no_check ? udp_getfrag_nosum : udp_getfrag,
+	err = ip_build_xmit(sk,
+			    (sk->no_check == UDP_CSUM_NOXMIT ?
+			     udp_getfrag_nosum :
+			     udp_getfrag),
X 			    &ufh, ulen, &ipc, rt, msg->msg_flags);
X 
X out:
@@ -1093,6 +1096,33 @@
X }
X #endif
X 
+static int udp_checksum_verify(struct sk_buff *skb, struct udphdr *uh,
+			       unsigned short ulen, u32 saddr, u32 daddr,
+			       int full_csum_deferred)
+{
+	if (!full_csum_deferred) {
+		if (uh->check) {
+			if (skb->ip_summed == CHECKSUM_HW &&
+			    udp_check(uh, ulen, saddr, daddr, skb->csum))
+				return -1;
+			if (skb->ip_summed == CHECKSUM_NONE &&
+			    udp_check(uh, ulen, saddr, daddr,
+				      csum_partial((char *)uh, ulen, 0)))
+				return -1;
+		}
+	} else {
+		if (uh->check == 0)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else if (skb->ip_summed == CHECKSUM_HW) {
+			if (udp_check(uh, ulen, saddr, daddr, skb->csum))
+				return -1;
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		} else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+			skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
+	}
+	return 0;
+}
+
X /*
X  *	All we need to do is get the socket, and then do a checksum. 
X  */
@@ -1134,25 +1164,18 @@
X 	}
X 	skb_trim(skb, ulen);
X 
-#ifndef CONFIG_UDP_DELAY_CSUM
-	if (uh->check &&
-	    (((skb->ip_summed==CHECKSUM_HW)&&udp_check(uh,ulen,saddr,daddr,skb->csum)) ||
-	     ((skb->ip_summed==CHECKSUM_NONE) &&
-	      (udp_check(uh,ulen,saddr,daddr, csum_partial((char*)uh, ulen, 0)))))) 
-		goto csum_error;
+	if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) {
+		int defer;
+
+#ifdef CONFIG_UDP_DELAY_CSUM
+		defer = 1;
X #else
-	if (uh->check==0)
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	else if (skb->ip_summed==CHECKSUM_HW) {
-		if (udp_check(uh,ulen,saddr,daddr,skb->csum)) 
-			goto csum_error;
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	} else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
-		skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
+		defer = 0;
X #endif
-
-	if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
+		if (udp_checksum_verify(skb, uh, ulen, saddr, daddr, defer))
+			goto csum_error;
X 		return udp_v4_mcast_deliver(skb, uh, saddr, daddr);
+	}
X 
X #ifdef CONFIG_IP_TRANSPARENT_PROXY
X 	if (IPCB(skb)->redirport)
@@ -1179,6 +1202,15 @@
X 		kfree_skb(skb);
X 		return(0);
X   	}
+	if (udp_checksum_verify(skb, uh, ulen, saddr, daddr,
+#ifdef CONFIG_UDP_DELAY_CSUM
+				1
+#else
+				(sk->no_check & UDP_CSUM_NORCV) != 0
+#endif
+		))
+		goto csum_error;
+
X 	udp_deliver(sk, skb);
X 	return 0;
X 
diff -u --recursive --new-file v2.3.5/linux/net/ipv4/utils.c linux/net/ipv4/utils.c
--- v2.3.5/linux/net/ipv4/utils.c	Mon Jan 12 15:28:28 1998
+++ linux/net/ipv4/utils.c	Wed Jun  9 14:45:37 1999
@@ -6,7 +6,7 @@
X  *		Various kernel-resident INET utility functions; mainly
X  *		for format conversion and debugging output.
X  *
- * Version:	$Id: utils.c,v 1.6 1997/12/13 21:53:03 kuznet Exp $
+ * Version:	$Id: utils.c,v 1.7 1999/06/09 10:11:05 davem Exp $
X  *
X  * Author:	Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
X  *
@@ -57,6 +57,11 @@
X 	return(buff);
X }
X 
+char *in_ntoa2(__u32 in, char *buff)
+{
+	sprintf(buff, "%d.%d.%d.%d", NIPQUAD(in));
+	return buff;
+}
X 
X /*
X  *	Convert an ASCII string to binary IP. 
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.3.5/linux/net/ipv6/addrconf.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv6/addrconf.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *	Authors:
X  *	Pedro Roque		<ro...@di.fc.ul.pt>	
X  *
- *	$Id: addrconf.c,v 1.49 1999/05/27 00:38:20 davem Exp $
+ *	$Id: addrconf.c,v 1.50 1999/06/09 10:11:09 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *      modify it under the terms of the GNU General Public License
@@ -100,9 +100,7 @@
X    1. The result of inet6_add_addr() is used only inside lock
X       or from bh_atomic context.
X 
-   2. inet6_get_lladdr() is used only from bh protected context.
-
-   3. The result of ipv6_chk_addr() is not used outside of bh protected context.
+   2. The result of ipv6_chk_addr() is not used outside of bh protected context.
X  */
X 
X static __inline__ void addrconf_lock(void)
@@ -463,7 +461,7 @@
X 	return err;
X }
X 
-struct inet6_ifaddr * ipv6_get_lladdr(struct device *dev)
+int ipv6_get_lladdr(struct device *dev, struct in6_addr *addr)
X {
X 	struct inet6_ifaddr *ifp = NULL;
X 	struct inet6_dev *idev;
@@ -471,12 +469,15 @@
X 	if ((idev = ipv6_get_idev(dev)) != NULL) {
X 		addrconf_lock();
X 		for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-			if (ifp->scope == IFA_LINK)
-				break;
+			if (ifp->scope == IFA_LINK) {
+				ipv6_addr_copy(addr, &ifp->addr);
+				addrconf_unlock();
+				return 0;
+			}
X 		}
X 		addrconf_unlock();
X 	}
-	return ifp;
+	return -EADDRNOTAVAIL;
X }
X 
X /*
@@ -982,7 +983,7 @@
X 		return;
X 	}
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X         for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if (dev->ip_ptr && (dev->flags & IFF_UP)) {
X 			struct in_device * in_dev = dev->ip_ptr;
@@ -1001,7 +1002,6 @@
X 					flag |= IFA_HOST;
X 				}
X 
-				read_unlock_bh(&dev_base_lock);
X 				addrconf_lock();
X 				ifp = ipv6_add_addr(idev, &addr, flag);
X 				if (ifp) {
@@ -1013,11 +1013,10 @@
X 					ipv6_ifa_notify(RTM_NEWADDR, ifp);
X 				}
X 				addrconf_unlock();
-				read_lock_bh(&dev_base_lock);
X 			}
X 		}
X         }
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X }
X 
X static void init_loopback(struct device *dev)
@@ -1846,12 +1845,11 @@
X 	struct device *dev;
X 
X 	/* This takes sense only during module load. */
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev; dev = dev->next) {
X 		if (!(dev->flags&IFF_UP))
X 			continue;
X 
-		read_unlock_bh(&dev_base_lock);
X 		switch (dev->type) {
X 		case ARPHRD_LOOPBACK:	
X 			init_loopback(dev);
@@ -1862,9 +1860,8 @@
X 		default:
X 			/* Ignore all other */
X 		}
-		read_lock_bh(&dev_base_lock);
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X #endif
X 	
X #ifdef CONFIG_PROC_FS
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.3.5/linux/net/ipv6/af_inet6.c	Thu Apr 22 19:45:20 1999
+++ linux/net/ipv6/af_inet6.c	Wed Jun  9 14:45:37 1999
@@ -7,7 +7,7 @@
X  *
X  *	Adapted from linux/net/ipv4/af_inet.c
X  *
- *	$Id: af_inet6.c,v 1.43 1999/04/22 10:07:39 davem Exp $
+ *	$Id: af_inet6.c,v 1.44 1999/06/09 08:29:29 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *      modify it under the terms of the GNU General Public License
@@ -103,7 +103,7 @@
X 		if (protocol && protocol != IPPROTO_UDP) 
X 			goto free_and_noproto;
X 		protocol = IPPROTO_UDP;
-		sk->no_check = UDP_NO_CHECK;
+		sk->no_check = UDP_CSUM_DEFAULT;
X 		prot=&udpv6_prot;
X 		sock->ops = &inet6_dgram_ops;
X 	} else if(sock->type == SOCK_RAW) {
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/ip6_fw.c linux/net/ipv6/ip6_fw.c
--- v2.3.5/linux/net/ipv6/ip6_fw.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv6/ip6_fw.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *	Authors:
X  *	Pedro Roque		<ro...@di.fc.ul.pt>	
X  *
- *	$Id: ip6_fw.c,v 1.10 1998/08/26 12:04:57 davem Exp $
+ *	$Id: ip6_fw.c,v 1.12 1999/06/09 08:29:32 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *      modify it under the terms of the GNU General Public License
@@ -383,7 +383,7 @@
X }
X 
X #ifdef MODULE
-void module_cleanup(void)
+void cleanup_module(void)
X {
X #ifdef CONFIG_NETLINK
X 	netlink_detach(NETLINK_IP6_FW);
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c
--- v2.3.5/linux/net/ipv6/ip6_output.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv6/ip6_output.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *	Authors:
X  *	Pedro Roque		<ro...@di.fc.ul.pt>	
X  *
- *	$Id: ip6_output.c,v 1.17 1999/04/22 10:07:42 davem Exp $
+ *	$Id: ip6_output.c,v 1.20 1999/06/09 10:11:12 davem Exp $
X  *
X  *	Based on linux/net/ipv4/ip_output.c
X  *
@@ -75,19 +75,10 @@
X 	}
X 
X 	if (hh) {
-#ifdef __alpha__
-		/* Alpha has disguisting memcpy. Help it. */
-	        u64 *aligned_hdr = (u64*)(skb->data - 16);
-		u64 *aligned_hdr0 = hh->hh_data;
-		read_lock_irq(&hh->hh_lock);
-		aligned_hdr[0] = aligned_hdr0[0];
-		aligned_hdr[1] = aligned_hdr0[1];
-#else
-		read_lock_irq(&hh->hh_lock);
+		read_lock_bh(&hh->hh_lock);
X 		memcpy(skb->data - 16, hh->hh_data, 16);
-#endif
-		read_unlock_irq(&hh->hh_lock);
-	        skb_push(skb, dev->hard_header_len);
+		read_unlock_bh(&hh->hh_lock);
+	        skb_push(skb, hh->hh_len);
X 		return hh->hh_output(skb);
X 	} else if (dst->neighbour)
X 		return dst->neighbour->output(skb);
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c
--- v2.3.5/linux/net/ipv6/mcast.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv6/mcast.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *	Authors:
X  *	Pedro Roque		<ro...@di.fc.ul.pt>	
X  *
- *	$Id: mcast.c,v 1.20 1999/05/27 00:38:23 davem Exp $
+ *	$Id: mcast.c,v 1.23 1999/06/09 10:11:14 davem Exp $
X  *
X  *	Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c 
X  *
@@ -53,6 +53,11 @@
X #define MDBG(x)
X #endif
X 
+/* Big mc list lock for all the devices */
+static rwlock_t ipv6_mc_lock = RW_LOCK_UNLOCKED;
+/* Big mc list lock for all the sockets */
+static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED;
+
X static struct socket *igmp6_socket;
X 
X static void igmp6_join_group(struct ifmcaddr6 *ma);
@@ -115,8 +120,10 @@
X 		return err;
X 	}
X 
+	write_lock_bh(&ipv6_sk_mc_lock);
X 	mc_lst->next = np->ipv6_mc_list;
X 	np->ipv6_mc_list = mc_lst;
+	write_unlock_bh(&ipv6_sk_mc_lock);
X 
X 	return 0;
X }
@@ -129,13 +136,14 @@
X 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
X 	struct ipv6_mc_socklist *mc_lst, **lnk;
X 
+	write_lock_bh(&ipv6_sk_mc_lock);
X 	for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
X 		if (mc_lst->ifindex == ifindex &&
X 		    ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {
X 			struct device *dev;
X 
X 			*lnk = mc_lst->next;
-			synchronize_bh();
+			write_unlock_bh(&ipv6_sk_mc_lock);
X 
X 			if ((dev = dev_get_by_index(ifindex)) != NULL)
X 				ipv6_dev_mc_dec(dev, &mc_lst->addr);
@@ -143,6 +151,7 @@
X 			return 0;
X 		}
X 	}
+	write_unlock_bh(&ipv6_sk_mc_lock);
X 
X 	return -ENOENT;
X }
@@ -152,15 +161,38 @@
X 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
X 	struct ipv6_mc_socklist *mc_lst;
X 
+	write_lock_bh(&ipv6_sk_mc_lock);
X 	while ((mc_lst = np->ipv6_mc_list) != NULL) {
-		struct device *dev = dev_get_by_index(mc_lst->ifindex);
+		struct device *dev;
+
+		np->ipv6_mc_list = mc_lst->next;
+		write_unlock_bh(&ipv6_sk_mc_lock);
X 
+		dev = dev_get_by_index(mc_lst->ifindex);
X 		if (dev)
X 			ipv6_dev_mc_dec(dev, &mc_lst->addr);
X 
-		np->ipv6_mc_list = mc_lst->next;
X 		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 23'
echo 'File patch-2.3.6 is continued in part 24'
echo 24 > _shar_seq_.tmp
#!/bin/sh
# this is part 24 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 24; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
+
+		write_lock_bh(&ipv6_sk_mc_lock);
X 	}
+	write_unlock_bh(&ipv6_sk_mc_lock);
+}
+
+int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
+{
+	struct ipv6_mc_socklist *mc;
+
+	read_lock(&ipv6_sk_mc_lock);
+	for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
+		if (ipv6_addr_cmp(&mc->addr, addr) == 0) {
+			read_unlock(&ipv6_sk_mc_lock);
+			return 1;
+		}
+	}
+ read_unlock(&ipv6_sk_mc_lock);
+
+	return 0;
X }
X 
X static int igmp6_group_added(struct ifmcaddr6 *mc)
@@ -210,9 +242,11 @@
X 
X 	hash = ipv6_addr_hash(addr);
X 
+	write_lock_bh(&ipv6_mc_lock);
X 	for (mc = inet6_mcast_lst[hash]; mc; mc = mc->next) {
X 		if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0 && mc->dev == dev) {
X 			atomic_inc(&mc->mca_users);
+			write_unlock_bh(&ipv6_mc_lock);
X 			return 0;
X 		}
X 	}
@@ -223,8 +257,10 @@
X 
X 	mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
X 
-	if (mc == NULL)
+	if (mc == NULL) {
+		write_unlock_bh(&ipv6_mc_lock);
X 		return -ENOMEM;
+	}
X 
X 	memset(mc, 0, sizeof(struct ifmcaddr6));
X 	mc->mca_timer.function = igmp6_timer_handler;
@@ -242,6 +278,8 @@
X 
X 	igmp6_group_added(mc);
X 
+	write_unlock_bh(&ipv6_mc_lock);
+
X 	return 0;
X }
X 
@@ -257,7 +295,6 @@
X 		for (lnk = &idev->mc_list; (iter = *lnk) != NULL; lnk = &iter->if_next) {
X 			if (iter == ma) {
X 				*lnk = iter->if_next;
-				synchronize_bh();
X 				return;
X 			}
X 		}
@@ -274,20 +311,22 @@
X 
X 	hash = ipv6_addr_hash(addr);
X 
+	write_lock_bh(&ipv6_mc_lock);
X 	for (lnk = &inet6_mcast_lst[hash]; (ma=*lnk) != NULL; lnk = &ma->next) {
X 		if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0 && ma->dev == dev) {
X 			if (atomic_dec_and_test(&ma->mca_users)) {
X 				igmp6_group_dropped(ma);
X 
X 				*lnk = ma->next;
-				synchronize_bh();
X 
X 				ipv6_mca_remove(dev, ma);
X 				kfree(ma);
X 			}
+			write_unlock_bh(&ipv6_mc_lock);
X 			return 0;
X 		}
X 	}
+ write_unlock_bh(&ipv6_mc_lock);
X 
X 	return -ENOENT;
X }
@@ -302,10 +341,14 @@
X 
X 	hash = ipv6_addr_hash(addr);
X 
+	read_lock_bh(&ipv6_mc_lock);
X 	for (mc = inet6_mcast_lst[hash]; mc; mc=mc->next) {
-		if (mc->dev == dev && ipv6_addr_cmp(&mc->mca_addr, addr) == 0)
+		if (mc->dev == dev && ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
+			read_unlock_bh(&ipv6_mc_lock);
X 			return 1;
+		}
X 	}
+	read_unlock_bh(&ipv6_mc_lock);
X 
X 	return 0;
X }
@@ -364,11 +407,14 @@
X 		if (idev == NULL)
X 			return 0;
X 
+		read_lock(&ipv6_mc_lock);
X 		for (ma = idev->mc_list; ma; ma=ma->if_next)
X 			igmp6_group_queried(ma, resptime);
+		read_unlock(&ipv6_mc_lock);
X 	} else {
X 		int hash = ipv6_addr_hash(addrp);
X 
+		read_lock(&ipv6_mc_lock);
X 		for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) {
X 			if (ma->dev == skb->dev &&
X 			    ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
@@ -376,6 +422,7 @@
X 				break;
X 			}
X 		}
+		read_unlock(&ipv6_mc_lock);
X 	}
X 
X 	return 0;
@@ -410,6 +457,7 @@
X 
X 	hash = ipv6_addr_hash(addrp);
X 
+	read_lock(&ipv6_mc_lock);
X 	for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) {
X 		if ((ma->dev == dev) && ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
X 			if (ma->mca_flags & MAF_TIMER_RUNNING) {
@@ -421,6 +469,7 @@
X 			break;
X 		}
X 	}
+	read_unlock(&ipv6_mc_lock);
X 
X 	return 0;
X }
@@ -430,9 +479,9 @@
X 	struct sock *sk = igmp6_socket->sk;
X         struct sk_buff *skb;
X         struct icmp6hdr *hdr;
-	struct inet6_ifaddr *ifp;
X 	struct in6_addr *snd_addr;
X 	struct in6_addr *addrp;
+	struct in6_addr addr_buf;
X 	struct in6_addr all_routers;
X 	int err, len, payload_len, full_len;
X 	u8 ra[8] = { IPPROTO_ICMPV6, 0,
@@ -461,9 +510,7 @@
X 		dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len);
X 	}
X 
-	ifp = ipv6_get_lladdr(dev);
-
-	if (ifp == NULL) {
+	if (ipv6_get_lladdr(dev, &addr_buf)) {
X #if MCAST_DEBUG >= 1
X 		printk(KERN_DEBUG "igmp6: %s no linklocal address\n",
X 		       dev->name);
@@ -471,7 +518,7 @@
X 		return;
X 	}
X 
-	ip6_nd_hdr(sk, skb, dev, &ifp->addr, snd_addr, NEXTHDR_HOP, payload_len);
+	ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);
X 
X 	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
X 
@@ -482,7 +529,7 @@
X 	addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
X 	ipv6_addr_copy(addrp, addr);
X 
-	hdr->icmp6_cksum = csum_ipv6_magic(&ifp->addr, snd_addr, len,
+	hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,
X 					   IPPROTO_ICMPV6,
X 					   csum_partial((__u8 *) hdr, len, 0));
X 
@@ -504,7 +551,6 @@
X 	if ((addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK)))
X 		return;
X 
-	start_bh_atomic();
X 	igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT);
X 
X 	delay = net_random() % IGMP6_UNSOLICITED_IVAL;
@@ -515,7 +561,6 @@
X 
X 	add_timer(&ma->mca_timer);
X 	ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
-	end_bh_atomic();
X }
X 
X static void igmp6_leave_group(struct ifmcaddr6 *ma)
@@ -527,22 +572,22 @@
X 	if ((addr_type & IPV6_ADDR_LINKLOCAL))
X 		return;
X 
-	start_bh_atomic();
X 	if (ma->mca_flags & MAF_LAST_REPORTER)
X 		igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REDUCTION);
X 
X 	if (ma->mca_flags & MAF_TIMER_RUNNING)
X 		del_timer(&ma->mca_timer);
-	end_bh_atomic();
X }
X 
X void igmp6_timer_handler(unsigned long data)
X {
X 	struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
X 
+	read_lock(&ipv6_mc_lock);
X 	ma->mca_flags |=  MAF_LAST_REPORTER;
X 	igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT);
X 	ma->mca_flags &= ~MAF_TIMER_RUNNING;
+	read_unlock(&ipv6_mc_lock);
X }
X 
X /* Device going down */
@@ -554,8 +599,10 @@
X 
X 	/* Withdraw multicast list */
X 
+	read_lock_bh(&ipv6_mc_lock);
X 	for (i = idev->mc_list; i; i=i->if_next)
X 		igmp6_group_dropped(i);
+	read_unlock_bh(&ipv6_mc_lock);
X 
X 	/* Delete all-nodes address. */
X 
@@ -577,8 +624,10 @@
X 
X 	/* Install multicast list, except for all-nodes (already installed) */
X 
+	read_lock(&ipv6_mc_lock);
X 	for (i = idev->mc_list; i; i=i->if_next)
X 		igmp6_group_added(i);
+	read_unlock(&ipv6_mc_lock);
X }
X 
X /*
@@ -590,6 +639,7 @@
X 	int hash;
X 	struct ifmcaddr6 *i, **lnk;
X 
+	write_lock_bh(&ipv6_mc_lock);
X 	while ((i = idev->mc_list) != NULL) {
X 		idev->mc_list = i->if_next;
X 
@@ -598,13 +648,13 @@
X 		for (lnk = &inet6_mcast_lst[hash]; *lnk; lnk = &(*lnk)->next) {
X 			if (*lnk == i) {
X 				*lnk = i->next;
-				synchronize_bh();
X 				break;
X 			}
X 		}
X 		igmp6_group_dropped(i);
X 		kfree(i);
X 	}
+	write_unlock_bh(&ipv6_mc_lock);
X }
X 
X #ifdef CONFIG_PROC_FS
@@ -616,13 +666,14 @@
X 	int len=0;
X 	struct device *dev;
X 	
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev; dev = dev->next) {
X 		struct inet6_dev *idev;
X 
X 		if ((idev = ipv6_get_idev(dev)) == NULL)
X 			continue;
X 
+		read_lock_bh(&ipv6_mc_lock);
X 		for (im = idev->mc_list; im; im = im->if_next) {
X 			int i;
X 
@@ -642,14 +693,17 @@
X 				len=0;
X 				begin=pos;
X 			}
-			if (pos > offset+length)
+			if (pos > offset+length) {
+ read_unlock_bh(&ipv6_mc_lock);
X 				goto done;
+			}
X 		}
+		read_unlock_bh(&ipv6_mc_lock);
X 	}
X 	*eof = 1;
X 
X done:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	*start=buffer+(offset-begin);
X 	len-=(offset-begin);
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.3.5/linux/net/ipv6/ndisc.c	Thu Apr 22 19:45:20 1999
+++ linux/net/ipv6/ndisc.c	Wed Jun  9 14:45:37 1999
@@ -268,14 +268,21 @@
X 			ndisc_mc_map(daddr, ha, dev, 1);
X 			h_dest = ha;
X 		} else if (neigh) {
-			h_dest = neigh->ha;
+			read_lock_bh(&neigh->lock);
+			if (neigh->nud_state&NUD_VALID) {
+				memcpy(ha, neigh->ha, dev->addr_len);
+				h_dest = ha;
+			}
+			read_unlock_bh(&neigh->lock);
X 		} else {
X 			neigh = neigh_lookup(&nd_tbl, daddr, dev);
X 			if (neigh) {
+				read_lock_bh(&neigh->lock);
X 				if (neigh->nud_state&NUD_VALID) {
X 					memcpy(ha, neigh->ha, dev->addr_len);
X 					h_dest = ha;
X 				}
+				read_unlock_bh(&neigh->lock);
X 				neigh_release(neigh);
X 			}
X 		}
@@ -362,6 +369,7 @@
X         struct sock *sk = ndisc_socket->sk;
X         struct sk_buff *skb;
X         struct nd_msg *msg;
+	struct in6_addr addr_buf;
X         int len;
X 	int err;
X 
@@ -377,13 +385,8 @@
X 	}
X 
X 	if (saddr == NULL) {
-		struct inet6_ifaddr *ifa;
-
-		/* use link local address */
-		ifa = ipv6_get_lladdr(dev);
-
-		if (ifa)
-			saddr = &ifa->addr;
+		if (!ipv6_get_lladdr(dev, &addr_buf))
+			saddr = &addr_buf;
X 	}
X 
X 	if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
@@ -501,13 +504,15 @@
X 	kfree_skb(skb);
X }
X 
+/* Called with locked neigh: either read or both */
+
X static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
X {
X 	struct in6_addr *saddr = NULL;
X 	struct in6_addr mcaddr;
X 	struct device *dev = neigh->dev;
X struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
-	int probes = neigh->probes;
+	int probes = atomic_read(&neigh->probes);
X 
X 	if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 0))
X 		saddr = &skb->nh.ipv6h->saddr;
@@ -774,8 +779,8 @@
X 	struct sock *sk = ndisc_socket->sk;
X 	int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
X 	struct sk_buff *buff;
-	struct inet6_ifaddr *ifp;
X 	struct icmp6hdr *icmph;
+	struct in6_addr saddr_buf;
X 	struct in6_addr *addrp;
X 	struct device *dev;
X 	struct rt6_info *rt;
@@ -817,12 +822,10 @@
X 	rd_len &= ~0x7;
X 	len += rd_len;
X 
-	ifp = ipv6_get_lladdr(dev);
-
-	if (ifp == NULL) {
-		ND_PRINTK1("redirect: no link_local addr for dev\n");
-		return;
-	}
+	if (ipv6_get_lladdr(dev, &saddr_buf)) {
+ 		ND_PRINTK1("redirect: no link_local addr for dev\n");
+ 		return;
+ 	}
X 
X 	buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
X 				   0, 0, &err);
@@ -838,7 +841,7 @@
X 		return;
X 	}
X 
-	ip6_nd_hdr(sk, buff, dev, &ifp->addr, &skb->nh.ipv6h->saddr,
+	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr,
X 		   IPPROTO_ICMPV6, len);
X 
X 	icmph = (struct icmp6hdr *) skb_put(buff, len);
@@ -875,7 +878,7 @@
X 
X 	memcpy(opt, skb->nh.ipv6h, rd_len - 8);
X 
-	icmph->icmp6_cksum = csum_ipv6_magic(&ifp->addr, &skb->nh.ipv6h->saddr,
+	icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &skb->nh.ipv6h->saddr,
X 					     len, IPPROTO_ICMPV6,
X 					     csum_partial((u8 *) icmph, len, 0));
X 
@@ -1034,7 +1037,7 @@
X 				   ifp->idev->dev->name);
X 			return 0;
X 		}
-		neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 0);
+		neigh = neigh_lookup(&nd_tbl, &msg->target, skb->dev);
X 
X 		if (neigh) {
X 			if (neigh->flags & NTF_ROUTER) {
@@ -1083,11 +1086,10 @@
X 	unsigned long now = jiffies;
X 	int i;
X 
-	neigh_table_lock(&nd_tbl);
-
X 	for (i = 0; i <= NEIGH_HASHMASK; i++) {
X 		struct neighbour *neigh;
X 
+		read_lock_bh(&nd_tbl.lock);
X 		for (neigh = nd_tbl.hash_buckets[i]; neigh; neigh = neigh->next) {
X 			int j;
X 
@@ -1097,6 +1099,7 @@
X 				size += 2;
X 			}
X 
+			read_lock(&neigh->lock);
X 			size += sprintf(buffer+len+size,
X 				       " %02x %02x %02x %02x %08lx %08lx %08x %04x %04x %04x %8s ", i,
X 				       128,
@@ -1118,19 +1121,22 @@
X 			} else {
X                                 size += sprintf(buffer+len+size, "000000000000");
X 			}
+			read_unlock(&neigh->lock);
X 			size += sprintf(buffer+len+size, "\n");
X 			len += size;
X 			pos += size;
X 		  
X 			if (pos <= offset)
X 				len=0;
-			if (pos >= offset+length)
+			if (pos >= offset+length) {
+ read_unlock_bh(&nd_tbl.lock);
X 				goto done;
+			}
X 		}
+		read_unlock_bh(&nd_tbl.lock);
X 	}
X 
X done:
-	neigh_table_unlock(&nd_tbl);
X 
X 	*start = buffer+len-(pos-offset);	/* Start of wanted data */
X 	len = pos-offset;			/* Start slop */
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.3.5/linux/net/ipv6/raw.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv6/raw.c	Wed Jun  9 14:45:37 1999
@@ -7,7 +7,7 @@
X  *
X  *	Adapted from linux/net/ipv4/raw.c
X  *
- *	$Id: raw.c,v 1.25 1999/05/27 00:38:16 davem Exp $
+ *	$Id: raw.c,v 1.26 1999/06/09 10:11:18 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *      modify it under the terms of the GNU General Public License
@@ -99,17 +99,6 @@
X 	SOCKHASH_UNLOCK_WRITE();
X }
X 
-static __inline__ int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
-{
-	struct ipv6_mc_socklist *mc;
-		
-	for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
-		if (ipv6_addr_cmp(&mc->addr, addr) == 0)
-			return 1;
-	}
-
-	return 0;
-}
X 
X /* Grumble... icmp and ip_input want to get at this... */
X struct sock *raw_v6_lookup(struct sock *sk, unsigned short num,
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/reassembly.c linux/net/ipv6/reassembly.c
--- v2.3.5/linux/net/ipv6/reassembly.c	Wed Jun  2 14:44:39 1999
+++ linux/net/ipv6/reassembly.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *	Authors:
X  *	Pedro Roque		<ro...@di.fc.ul.pt>	
X  *
- *	$Id: reassembly.c,v 1.11 1998/08/26 12:05:16 davem Exp $
+ *	$Id: reassembly.c,v 1.13 1999/06/09 08:29:40 davem Exp $
X  *
X  *	Based on: net/ipv4/ip_fragment.c
X  *
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.3.5/linux/net/ipv6/route.c	Sun Mar 21 07:22:00 1999
+++ linux/net/ipv6/route.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *	Authors:
X  *	Pedro Roque		<ro...@di.fc.ul.pt>	
X  *
- *	$Id: route.c,v 1.35 1999/03/21 05:22:57 davem Exp $
+ *	$Id: route.c,v 1.36 1999/06/09 10:11:21 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *      modify it under the terms of the GNU General Public License
@@ -1607,7 +1607,7 @@
X 	return 0;
X }
X 
-static int fib6_dump_done(struct netlink_callback *cb)
+static void fib6_dump_end(struct netlink_callback *cb)
X {
X 	struct fib6_walker_t *w = (void*)cb->args[0];
X 
@@ -1622,6 +1622,11 @@
X 		cb->done = (void*)cb->args[1];
X 		cb->args[1] = 0;
X 	}
+}
+
+static int fib6_dump_done(struct netlink_callback *cb)
+{
+	fib6_dump_end(cb);
X 	return cb->done(cb);
X }
X 
@@ -1668,11 +1673,15 @@
X 	if (res <= 0 && skb->len == 0)
X 		RT6_TRACE("%p>dump end\n", w);
X #endif
+	res = res < 0 ? res : skb->len;
X 	/* res < 0 is an error. (really, impossible)
X 	   res == 0 means that dump is complete, but skb still can contain data.
X 	   res > 0 dump is not complete, but frame is full.
X 	 */
-	return res < 0 ? res : skb->len;
+	/* Destroy walker, if dump of this table is complete. */
+	if (res <= 0)
+		fib6_dump_end(cb);
+	return res;
X }
X 
X int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.5/linux/net/ipv6/tcp_ipv6.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv6/tcp_ipv6.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *	Authors:
X  *	Pedro Roque		<ro...@di.fc.ul.pt>	
X  *
- *	$Id: tcp_ipv6.c,v 1.106 1999/05/27 01:12:44 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.108 1999/06/09 08:29:43 davem Exp $
X  *
X  *	Based on: 
X  *	linux/net/ipv4/tcp.c
diff -u --recursive --new-file v2.3.5/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.3.5/linux/net/ipv6/udp.c	Mon May 31 22:28:07 1999
+++ linux/net/ipv6/udp.c	Wed Jun  9 14:45:37 1999
@@ -7,7 +7,7 @@
X  *
X  *	Based on linux/ipv4/udp.c
X  *
- *	$Id: udp.c,v 1.41 1999/05/27 00:38:18 davem Exp $
+ *	$Id: udp.c,v 1.42 1999/06/09 10:11:24 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *      modify it under the terms of the GNU General Public License
@@ -499,18 +499,6 @@
X 	}
X   	ipv6_statistics.Ip6InDelivers++;
X 	udp_stats_in6.UdpInDatagrams++;
-	return 0;
-}
-
-static __inline__ int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
-{
-	struct ipv6_mc_socklist *mc;
-		
-	for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
-		if (ipv6_addr_cmp(&mc->addr, addr) == 0)
-			return 1;
-	}
-
X 	return 0;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/Config.in linux/net/irda/Config.in
--- v2.3.5/linux/net/irda/Config.in	Thu Apr 15 05:42:42 1999
+++ linux/net/irda/Config.in	Mon Jun  7 16:18:58 1999
@@ -2,34 +2,31 @@
X # IrDA protocol configuration
X #
X 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  if [ "$CONFIG_NET" != "n" ] ; then
+if [ "$CONFIG_NET" != "n" ] ; then
X 
-    mainmenu_option next_comment
-    comment 'IrDA subsystem support'
-    dep_tristate 'IrDA subsystem support' CONFIG_IRDA $CONFIG_EXPERIMENTAL $CONFIG_NET
+  mainmenu_option next_comment
+  comment 'IrDA subsystem support'
+  dep_tristate 'IrDA subsystem support' CONFIG_IRDA $CONFIG_NET
X 
-    if [ "$CONFIG_IRDA" != "n" ] ; then
-      comment 'IrDA protocols'
-      source net/irda/irlan/Config.in
-      source net/irda/ircomm/Config.in
-      source net/irda/irlpt/Config.in
+  if [ "$CONFIG_IRDA" != "n" ] ; then
+    comment 'IrDA protocols'
+    source net/irda/irlan/Config.in
+    source net/irda/ircomm/Config.in
+    source net/irda/irlpt/Config.in
X 
-      bool 'IrDA protocol options' CONFIG_IRDA_OPTIONS
-      if [ "$CONFIG_IRDA_OPTIONS" != "n" ] ; then
-        comment '   IrDA options'
-        bool '   Cache last LSAP' CONFIG_IRDA_CACHE_LAST_LSAP
-	bool '   Fast RRs' CONFIG_IRDA_FAST_RR
-	bool '   Debug information' CONFIG_IRDA_DEBUG
-      fi
+    bool 'IrDA protocol options' CONFIG_IRDA_OPTIONS
+    if [ "$CONFIG_IRDA_OPTIONS" != "n" ] ; then
+      comment '   IrDA options'
+      bool '   Cache last LSAP' CONFIG_IRDA_CACHE_LAST_LSAP
+      bool '   Fast RRs' CONFIG_IRDA_FAST_RR
+      bool '   Debug information' CONFIG_IRDA_DEBUG
X     fi
+  fi
X 
-    if [ "$CONFIG_IRDA" != "n" ] ; then
-      source net/irda/compressors/Config.in
-      source drivers/net/irda/Config.in
-    fi
-  endmenu
-
+  if [ "$CONFIG_IRDA" != "n" ] ; then
+    source net/irda/compressors/Config.in
+    source drivers/net/irda/Config.in
X   fi
+  endmenu
X fi
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.3.5/linux/net/irda/af_irda.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/af_irda.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun May 31 10:12:43 1998
- * Modified at:   Tue May 11 12:42:26 1999
+ * Modified at:   Wed May 19 16:12:06 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
X  * 
@@ -145,7 +145,7 @@
X 	else
X 		self->max_data_size = max_sdu_size;
X 
-	DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+	DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
X 
X 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
X 
@@ -189,7 +189,7 @@
X 	else
X 		self->max_data_size = max_sdu_size;
X 
-	DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+	DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
X 
X 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
X 
@@ -250,12 +250,12 @@
X 	
X 	switch (flow) {
X 	case FLOW_STOP:
-		DEBUG( 0, __FUNCTION__ "(), IrTTP wants us to slow down\n");
+		DEBUG(1, __FUNCTION__ "(), IrTTP wants us to slow down\n");
X 		self->tx_flow = flow;
X 		break;
X 	case FLOW_START:
X 		self->tx_flow = flow;
-		DEBUG(0, __FUNCTION__ "(), IrTTP wants us to start again\n");
+		DEBUG(1, __FUNCTION__ "(), IrTTP wants us to start again\n");
X 		wake_up_interruptible(sk->sleep);
X 		break;
X 	default:
@@ -703,7 +703,11 @@
X 
X 	sock_init_data(sock, sk);
X 
-	sock->ops    = &irda_stream_ops;
+	if (sock->type == SOCK_STREAM)
+		sock->ops = &irda_stream_ops;
+	else
+		sock->ops = &irda_dgram_ops;
+
X 	sk->protocol = protocol;
X 
X 	/* Register as a client with IrLMP */
@@ -1123,7 +1127,7 @@
X {
X 	struct sock *sk = sock->sk;
X 
-	DEBUG(0, __FUNCTION__ "(), cmd=%#x\n", cmd);
+	DEBUG(4, __FUNCTION__ "(), cmd=%#x\n", cmd);
X 	
X 	switch (cmd) {
X 	case TIOCOUTQ: {
@@ -1170,7 +1174,7 @@
X 		return -EINVAL;
X 		
X 	default:
-		DEBUG(0, __FUNCTION__ "(), doing device ioctl!\n");
+		DEBUG(1, __FUNCTION__ "(), doing device ioctl!\n");
X 		return dev_ioctl(cmd, (void *) arg);
X 	}
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/discovery.c linux/net/irda/discovery.c
--- v2.3.5/linux/net/irda/discovery.c	Wed Jun  2 14:44:39 1999
+++ linux/net/irda/discovery.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Tue Apr  6 15:33:50 1999
- * Modified at:   Sun May  9 22:40:43 1999
+ * Modified at:   Fri May 28 20:46:38 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * Modified at:   Fri May 28  3:11 CST 1999
X  * Modified by:   Horst von Brand <vonb...@sleipnir.valparaiso.cl>
@@ -227,10 +227,12 @@
X 	
X 	discovery = (discovery_t *) hashbin_get_first(cachelog);
X 	while ( discovery != NULL) {
-		len += sprintf( buf+len, "  name: %s,", 
-				discovery->info);
+		len += sprintf(buf+len, "name: %s,", discovery->info);
X 		
-		len += sprintf( buf+len, " hint: ");
+		len += sprintf(buf+len, " hint: 0x%02x%02x", 
+			       discovery->hints.byte[0], 
+			       discovery->hints.byte[1]);
+#if 0
X 		if ( discovery->hints.byte[0] & HINT_PNP)
X 			len += sprintf( buf+len, "PnP Compatible ");
X 		if ( discovery->hints.byte[0] & HINT_PDA)
@@ -254,14 +256,14 @@
X 			len += sprintf( buf+len, "IrCOMM ");
X 		if ( discovery->hints.byte[1] & HINT_OBEX)
X 			len += sprintf( buf+len, "IrOBEX ");
-		
+#endif		
X 		len += sprintf(buf+len, ", saddr: 0x%08x", 
X 			       discovery->saddr);
X 
X 		len += sprintf(buf+len, ", daddr: 0x%08x\n", 
X 			       discovery->daddr);
X 		
-		len += sprintf( buf+len, "\n");
+		len += sprintf(buf+len, "\n");
X 		
X 		discovery = (discovery_t *) hashbin_get_next(cachelog);
X 	}
diff -u --recursive --new-file v2.3.5/linux/net/irda/ircomm/ircomm_common.c linux/net/irda/ircomm/ircomm_common.c
--- v2.3.5/linux/net/irda/ircomm/ircomm_common.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/ircomm/ircomm_common.c	Mon Jun  7 16:18:58 1999
@@ -41,7 +41,7 @@
X 
X #include <net/irda/ircomm_common.h>
X 
-static char *revision_date = "Sun Apr 18 00:40:19 1999";
+static char *revision_date = "Tue May 18 03:11:39 1999";
X 
X 
X static void ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, 
@@ -205,15 +205,17 @@
X 		ircomm[i]->enq_char = 0x05;
X 		ircomm[i]->ack_char = 0x06;  
X 
-		ircomm[i]->max_txbuff_size = COMM_DEFAULT_DATA_SIZE;   /* 64 */
-		ircomm[i]->max_sdu_size = SAR_DISABLE;  
-		ircomm[i]->ctrl_skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+		ircomm[i]->max_header_size = COMM_MAX_HEADER_SIZE;
+		ircomm[i]->tx_max_sdu_size = COMM_DEFAULT_SDU_SIZE;
+		ircomm[i]->rx_max_sdu_size = SAR_DISABLE;  
+		ircomm[i]->ctrl_skb = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE
+						    + COMM_MAX_HEADER_SIZE);
X 		if (ircomm[i]->ctrl_skb == NULL){
X 			DEBUG(0,"ircomm:init_module:alloc_skb failed!\n");
X 			return -ENOMEM;
X 		}
X 
-		skb_reserve(ircomm[i]->ctrl_skb,COMM_HEADER_SIZE);
+		skb_reserve(ircomm[i]->ctrl_skb,COMM_MAX_HEADER_SIZE);
X 
X 	}
X 
@@ -302,14 +304,16 @@
X 	DEBUG(0,__FUNCTION__"(): got connected!\n");
X 
X 	if (max_sdu_size == SAR_DISABLE)
-		self->max_txbuff_size = qos->data_size.value - max_header_size;
+		self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+					- COMM_HEADER_SIZE);
X 	else {
-		ASSERT(max_sdu_size >= COMM_DEFAULT_DATA_SIZE, return;);
-		self->max_txbuff_size = max_sdu_size; /* use fragmentation */
+		ASSERT(max_sdu_size >= COMM_DEFAULT_SDU_SIZE, return;);
+		/* use fragmentation */
+		self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
X 	}
X 
X 	self->qos = qos;
-	self->max_header_size = max_header_size;
+	self->max_header_size = max_header_size + COMM_HEADER_SIZE;
X 	self->null_modem_mode = 0;         /* disable null modem emulation */
X 
X 	ircomm_do_event(self, TTP_CONNECT_CONFIRM, skb);
@@ -331,12 +335,13 @@
X 	DEBUG(0,__FUNCTION__"()\n");
X 
X 	if (max_sdu_size == SAR_DISABLE)
-		self->max_txbuff_size = qos->data_size.value - max_header_size;
+		self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+					- COMM_HEADER_SIZE);
X 	else
-		self->max_txbuff_size = max_sdu_size;
+		self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
X 
X 	self->qos = qos;
-	self->max_header_size = max_header_size;
+	self->max_header_size = max_header_size + COMM_HEADER_SIZE;
X 
X 	ircomm_do_event( self, TTP_CONNECT_INDICATION, skb);
X 
@@ -558,7 +563,7 @@
X 
X 		irttp_connect_request(self->tsap, self->dlsap, 
X 				      self->saddr, self->daddr, 
-				      NULL, self->max_sdu_size, userdata); 
+				      NULL, self->rx_max_sdu_size, userdata); 
X 		break;
X 
X 	default:
@@ -592,7 +597,8 @@
X 
X 	if (self->notify.connect_indication)
X 		self->notify.connect_indication(self->notify.instance, self, 
-						qos, 0, 0, skb);
+						qos, self->tx_max_sdu_size,
+						self->max_header_size, skb);
X }
X     
X #if 0
@@ -611,7 +617,8 @@
X 	/* give a connect_confirm to the client */
X 	if( self->notify.connect_confirm )
X 		self->notify.connect_confirm(self->notify.instance,
-					     self, NULL, SAR_DISABLE, 0, skb);
+					     self, NULL, self->tx_max_sdu_size,
+					     self->max_header_size, skb);
X }
X 
X static void issue_connect_response(struct ircomm_cb *self,
@@ -623,7 +630,7 @@
X 		DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented yet\n");
X 		/* irlmp_connect_rsp(); */
X 	} else
-		irttp_connect_response(self->tsap, self->max_sdu_size, skb);
+		irttp_connect_response(self->tsap, self->rx_max_sdu_size, skb);
X }
X 
X static void issue_disconnect_request(struct ircomm_cb *self,
@@ -1054,7 +1061,7 @@
X 
X 	hints = irlmp_service_to_hint(S_COMM);
X 
-	DEBUG(0,__FUNCTION__"():start discovering..\n");
+	DEBUG(1,__FUNCTION__"():start discovering..\n");
X 	switch (ircomm_cs) {
X 	case 0:
X 		MOD_INC_USE_COUNT;
@@ -1155,12 +1162,12 @@
X 	ASSERT( self->magic == IRCOMM_MAGIC, return;);
X 
X 
-	DEBUG(0, __FUNCTION__"():sending connect_request...\n");
+	DEBUG(1, __FUNCTION__"():sending connect_request...\n");
X 
X 	self->servicetype= servicetype;
X 	/* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
X 
-	self->max_sdu_size = SAR_DISABLE;
+	self->rx_max_sdu_size = SAR_DISABLE;
X 	ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, NULL);
X }
X 
@@ -1181,20 +1188,18 @@
X 
X 	if (!userdata){
X 		/* FIXME: check for errors and initialize? DB */
-		userdata = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+		userdata = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
X 		if (userdata == NULL)
X 			return;
X 
-		skb_reserve(userdata,COMM_HEADER_SIZE);
+		skb_reserve(userdata,COMM_MAX_HEADER_SIZE);
X 	}
X 
X 	/* enable null-modem emulation (i.e. server mode )*/
X 	self->null_modem_mode = 1;
X 
-	self->max_sdu_size = max_sdu_size;
-	if (max_sdu_size != SAR_DISABLE)
-		self->max_txbuff_size = max_sdu_size;
-
+	self->rx_max_sdu_size = max_sdu_size;
+	
X 	ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
X }	
X 
@@ -1307,10 +1312,10 @@
X 	ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
X 	self->control_ch_pending = 0;
X 
-	skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+	skb = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
X 	ASSERT(skb != NULL, return ;);
X 
-	skb_reserve(skb,COMM_HEADER_SIZE);
+	skb_reserve(skb,COMM_MAX_HEADER_SIZE);
X 	self->ctrl_skb = skb;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/ircomm/irvtd_driver.c linux/net/irda/ircomm/irvtd_driver.c
--- v2.3.5/linux/net/irda/ircomm/irvtd_driver.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/ircomm/irvtd_driver.c	Mon Jun  7 16:18:58 1999
@@ -51,7 +51,7 @@
X static int irvtd_refcount;
X struct irvtd_cb **irvtd = NULL;
X 
-static char *revision_date = "Sun Apr 18 17:31:53 1999";
+static char *revision_date = "Wed May 26 00:49:11 1999";
X 
X 
X /*
@@ -83,8 +83,10 @@
X static void irvtd_send_xchar(struct tty_struct *tty, char ch);
X static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout);
X 
-static void irvtd_start_timer( struct irvtd_cb *driver);
-static void irvtd_timer_expired(unsigned long data);
+static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout);
+static void irvtd_tx_timer_expired(unsigned long data);
+static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout);
+static void irvtd_rx_timer_expired(unsigned long data);
X 
X static int line_info(char *buf, struct irvtd_cb *driver);
X static int irvtd_read_proc(char *buf, char **start, off_t offset, int len,
@@ -118,7 +120,7 @@
X 	if(driver->rx_disable)
X 		return;
X 
-	skb = skb_dequeue(&driver->rxbuff);
+ 	skb = skb_dequeue(&driver->rxbuff);
X 	if(skb == NULL)
X 		return; /* there's nothing */
X 
@@ -211,8 +213,13 @@
X 	
X 	if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW &&
X 	   driver->ttp_stoprx){
-		irttp_flow_request(driver->comm->tsap, FLOW_START);
+		DEBUG(1, __FUNCTION__"():FLOW_START\n");
+		/* 
+		 * next 2 lines must follow this order since irttp_flow_request()
+		 * will run its rx queue
+		 */
X 		driver->ttp_stoprx = 0;
+		irttp_flow_request(driver->comm->tsap, FLOW_START);
X 	}
X 
X 	if(skb_queue_empty(&driver->rxbuff) && driver->disconnect_pend){
@@ -236,10 +243,14 @@
X 	skb_queue_tail( &driver->rxbuff, skb );
X 
X 	if(skb_queue_len(&driver->rxbuff) > IRVTD_RX_QUEUE_HIGH){
+		DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
X 		irttp_flow_request(driver->comm->tsap, FLOW_STOP);
X 		driver->ttp_stoprx = 1;
X 	}
X 	irvtd_write_to_tty(driver);
+
+	if(!skb_queue_empty(&driver->rxbuff))
+		irvtd_start_rx_timer(driver,0);
X 	return 0;
X }
X 
@@ -255,22 +266,36 @@
X  */
X 
X 
-static void irvtd_start_timer( struct irvtd_cb *driver)
+static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout)
+{
+	ASSERT( driver != NULL, return;);
+	ASSERT( driver->magic == IRVTD_MAGIC, return;);
+
+	del_timer( &driver->tx_timer);
+	
+	driver->tx_timer.data     = (unsigned long) driver;
+	driver->tx_timer.function = &irvtd_tx_timer_expired;
+	driver->tx_timer.expires  = jiffies + timeout;
+	
+	add_timer( &driver->tx_timer);
+}
+
+static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout)
X {
X 	ASSERT( driver != NULL, return;);
X 	ASSERT( driver->magic == IRVTD_MAGIC, return;);
X 
-	del_timer( &driver->timer);
+	del_timer( &driver->rx_timer);
X 	
-	driver->timer.data     = (unsigned long) driver;
-	driver->timer.function = &irvtd_timer_expired;
-	driver->timer.expires  = jiffies + (HZ / 5);  /* 200msec */
+	driver->rx_timer.data     = (unsigned long) driver;
+	driver->rx_timer.function = &irvtd_rx_timer_expired;
+	driver->rx_timer.expires  = jiffies + timeout;
X 	
-	add_timer( &driver->timer);
+	add_timer( &driver->rx_timer);
X }
X 
X 
-static void irvtd_timer_expired(unsigned long data)
+static void irvtd_tx_timer_expired(unsigned long data)
X {
X 	struct irvtd_cb *driver = (struct irvtd_cb *)data;
X 
@@ -279,11 +304,26 @@
X 	DEBUG(4, __FUNCTION__"()\n");
X 
X 	irvtd_send_data_request(driver);
+}
X 
-	irvtd_write_to_tty(driver);
+static void irvtd_rx_timer_expired(unsigned long data)
+{
+	struct irvtd_cb *driver = (struct irvtd_cb *)data;
+
+	ASSERT(driver != NULL,return;);
+	ASSERT(driver->magic == IRVTD_MAGIC,return;);
+	DEBUG(4, __FUNCTION__"()\n");
X 
-	/* start our timer again and again */
-	irvtd_start_timer(driver);
+	while(TTY_FLIPBUF_SIZE - driver->tty->flip.count
+	      && !skb_queue_empty(&driver->rxbuff))
+		irvtd_write_to_tty(driver);
+
+	DEBUG(1, __FUNCTION__"(): room in flip_buffer = %d\n",
+	      TTY_FLIPBUF_SIZE - driver->tty->flip.count);
+	
+	if(!skb_queue_empty(&driver->rxbuff))
+		/* handle it later */
+		irvtd_start_rx_timer(driver, 1);
X }
X 
X 
@@ -310,21 +350,23 @@
X 	}
X #endif
X 
-	DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len );
+	DEBUG(1, __FUNCTION__"():len = %d, room = %d\n",(int)skb->len,
+	      skb_tailroom(skb));
X 	driver->icount.tx += skb->len;
X 	err = ircomm_data_request(driver->comm, driver->txbuff);
X 	if (err){
X 		ASSERT(err == 0,;);
-		DEBUG(0,"%d chars are lost\n",(int)skb->len);
+		DEBUG(1,"%d chars are lost\n",(int)skb->len);
X 		skb_trim(skb, 0);
X 	}
X 
X 	/* allocate a new frame */
-	skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size);
+	skb = driver->txbuff 
+		= dev_alloc_skb(driver->tx_max_sdu_size + driver->max_header_size);
X 	if (skb == NULL){
X 		printk(__FUNCTION__"():alloc_skb failed!\n");
X 	} else {
-		skb_reserve(skb, COMM_HEADER_SIZE);
+		skb_reserve(skb, driver->max_header_size);
X 	}
X 
X 	wake_up_interruptible(&driver->tty->write_wait);
@@ -355,6 +397,9 @@
X 	ASSERT(driver != NULL, return;);
X 	ASSERT(driver->magic == IRVTD_MAGIC, return;);
X 
+
+	driver->tx_max_sdu_size = max_sdu_size;
+	driver->max_header_size = max_header_size;
X 	/*
X 	 * set default value
X 	 */
@@ -408,6 +453,8 @@
X 	ASSERT(comm != NULL, return;);
X 	ASSERT(comm->magic == IRCOMM_MAGIC, return;);
X 
+	driver->tx_max_sdu_size = max_sdu_size;
+	driver->max_header_size = max_header_size;
X 	DEBUG(4, __FUNCTION__ "():sending connect_response...\n");
X 
X 	ircomm_connect_response(comm, NULL, SAR_DISABLE );
@@ -481,11 +528,12 @@
X 	if(cmd == TX_READY){
X 		driver->ttp_stoptx = 0;
X 		driver->tty->hw_stopped = driver->cts_stoptx;
-		irvtd_start_timer( driver);
X 
X 		if(driver->cts_stoptx)
X 			return;
X 
+		/* push tx queue so that client can send at least 1 octet */
+		irvtd_send_data_request(driver);
X 		/* 
X 		 * driver->tty->write_wait will keep asleep if
X 		 * our txbuff is full.
@@ -500,7 +548,7 @@
X 
X 	if(cmd == TX_BUSY){
X 		driver->ttp_stoptx = driver->tty->hw_stopped = 1;
-		del_timer( &driver->timer);
+		del_timer( &driver->tx_timer);
X 		return;
X 	}
X 
@@ -681,7 +729,7 @@
X 
X 	driver->blocked_open--;
X 
-	DEBUG(0, __FUNCTION__"():after blocking\n");
+	DEBUG(1, __FUNCTION__"():after blocking\n");
X 
X 	if (retval)
X 		return retval;
@@ -768,7 +816,7 @@
X 	struct notify_t irvtd_notify;
X 
X 	/* FIXME: it should not be hard coded */
-	__u8 oct_seq[6] = { 0,1,4,1,1,1 }; 
+	__u8 oct_seq[6] = { 0,1,6,1,1,1 }; 
X 
X 	DEBUG(4,__FUNCTION__"()\n" );
X 	if(driver->flags & ASYNC_INITIALIZED)
@@ -779,12 +827,12 @@
X 	 */
X 
X 	skb_queue_head_init(&driver->rxbuff);
-	driver->txbuff = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE); 
+	driver->txbuff = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE); 
X 	if (!driver->txbuff){
X 		DEBUG(0,__FUNCTION__"(), alloc_skb failed!\n");
X 		return -ENOMEM;
X 	}
-	skb_reserve(driver->txbuff, COMM_HEADER_SIZE);
+	skb_reserve(driver->txbuff, COMM_MAX_HEADER_SIZE);
X 
X 	irda_notify_init(&irvtd_notify);
X 	irvtd_notify.data_indication = irvtd_receive_data;
@@ -813,22 +861,20 @@
X 
X 	driver->flags |= ASYNC_INITIALIZED;
X 
-	/*
-	 * discover a peer device
-	 *	   TODO: other servicetype(i.e. 3wire,3wireraw) support
-	 */
-	ircomm_connect_request(driver->comm, NINE_WIRE);
-	
-	/*
-	 * TODO:we have to initialize control-channel here!
-	 *   i.e.set something into RTS,CTS and so on....
-	 */
-
X 	if (driver->tty)
X 		clear_bit(TTY_IO_ERROR, &driver->tty->flags);
X 
X 	change_speed(driver);
-	irvtd_start_timer( driver);
+
+	/*
+	 * discover a peer device
+	 */
+	if(driver->tty->termios->c_cflag & CRTSCTS)
+	  ircomm_connect_request(driver->comm, NINE_WIRE);
+	else
+	  ircomm_connect_request(driver->comm, THREE_WIRE);
+
+	/* irvtd_start_timer( driver); */
X 
X 	driver->rx_disable = 0;
X 	driver->tx_disable = 1;
@@ -991,7 +1037,8 @@
X 	if (driver->tty)
X 		set_bit(TTY_IO_ERROR, &driver->tty->flags);
X 	
-	del_timer( &driver->timer);
+	del_timer( &driver->tx_timer);
+	del_timer( &driver->rx_timer);
X 
X 	irias_delete_object("IrDA:IrCOMM");
X 
@@ -1146,13 +1193,21 @@
X 	DEBUG(4, __FUNCTION__"()\n");
X 
X 	save_flags(flags);
-	while(1){
+	while(count > 0){
X 		cli();
X 		skb = driver->txbuff;
X 		ASSERT(skb != NULL, break;);
X 		c = MIN(count, (skb_tailroom(skb)));
X 		if (c <= 0)
-			break;
+		{
+			if(!driver->ttp_stoptx)
+			{
+				irvtd_send_data_request(driver);
+				continue;
+			}
+			else
+				break;
+		}
X 
X 		/* write to the frame */
X 
@@ -1166,9 +1221,9 @@
X 		wrote += c;
X 		count -= c;
X 		buf += c;
-		irvtd_send_data_request(driver);
X 	}
X 	restore_flags(flags);
+	irvtd_send_data_request(driver);
X 	return (wrote);
X }
X 
@@ -1201,19 +1256,27 @@
X 	DEBUG(4, __FUNCTION__"()\n");
X 
X 
+ again:
X 	save_flags(flags);cli();
X 	skb = driver->txbuff;
X 	ASSERT(skb != NULL,return;);
+	if(!skb_tailroom(skb))
+	{
+		restore_flags(flags);
+		irvtd_send_data_request(driver);
+		goto again;
+	}
X 	ASSERT(skb_tailroom(skb) > 0, return;);
-	DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) MAX(%d):\n",
+	DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) room(%d):\n",
X 	      (int)ch ,(int)skb->len,
-	      driver->comm->max_txbuff_size - COMM_HEADER_SIZE);
+	      skb_tailroom(skb));
X 
X 	/* append a character  */
X 	frame = skb_put(skb,1);
X 	frame[0] = ch;
X 
X 	restore_flags(flags);
+	irvtd_start_tx_timer(driver,20);
X 	return;
X }
X 
@@ -1637,6 +1700,7 @@
X 	driver->comm->dte = driver->mcr;
X 	ircomm_control_request(driver->comm, DTELINE_STATE );
X 
+	DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
X         irttp_flow_request(driver->comm->tsap, FLOW_STOP);
X }
X 
@@ -1651,6 +1715,7 @@
X 	driver->comm->dte = driver->mcr;
X 	ircomm_control_request(driver->comm, DTELINE_STATE );
X 
+	DEBUG(1, __FUNCTION__"():FLOW_START\n");
X         irttp_flow_request(driver->comm->tsap, FLOW_START);
X }
X 
@@ -1860,6 +1925,12 @@
X                 ret += sprintf(buf+ret, "|CD");
X 	if (driver->msr & MSR_RI) 
X 		ret += sprintf(buf+ret, "|RI");
+
+	ret += sprintf(buf+ret, "\n");
+	ret += sprintf(buf+ret, "rx queue:%d",
+		       skb_queue_len( &driver->rxbuff));
+	ret += sprintf(buf+ret, "ttp_stoprx:%s",
+		       driver->ttp_stoprx?"TRUE":"FALSE");
X 
X  exit:
X 	ret += sprintf(buf+ret, "\n");
diff -u --recursive --new-file v2.3.5/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
--- v2.3.5/linux/net/irda/irda_device.c	Wed Jun  2 14:44:39 1999
+++ linux/net/irda/irda_device.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X * Created at: Wed Sep 2 20:22:08 1998
- * Modified at:   Mon May 10 23:02:47 1999
+ * Modified at: Tue Jun 1 09:05:13 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * Modified at:   Fri May 28  3:11 CST 1999
X  * Modified by:   Horst von Brand <vonb...@sleipnir.valparaiso.cl>
@@ -105,6 +105,12 @@
X #ifdef CONFIG_NSC_FIR
X 	pc87108_init();
X #endif
+#ifdef CONFIG_TOSHIBA_FIR
+	toshoboe_init();
+#endif
+#ifdef CONFIG_SMC_IRCC_FIR
+	ircc_init();
+#endif
X #ifdef CONFIG_ESI_DONGLE
X 	esi_init();
X #endif
@@ -117,6 +123,10 @@
X #ifdef CONFIG_GIRBIL_DONGLE
X 	girbil_init();
X #endif
+#ifdef CONFIG_GIRBIL_DONGLE
+	litelink_init();
+#endif
+
X 	return 0;
X }
X 
@@ -169,6 +179,8 @@
X 	/* Initialize timers */
X 	init_timer(&self->media_busy_timer);	
X 
+	self->lock = SPIN_LOCK_UNLOCKED;
+
X 	/* A pointer to the low level implementation */
X 	self->priv = priv;
X 
@@ -200,7 +212,7 @@
X 	/* Open network device */
X 	dev_open(&self->netdev);
X 
-	MESSAGE("IrDA: Registred device %s\n", self->name);
+	MESSAGE("IrDA: Registered device %s\n", self->name);
X 
X 	irda_device_set_media_busy(self, FALSE);
X 
@@ -307,6 +319,8 @@
X  */
X static void __irda_device_change_speed(struct irda_device *self, int speed)
X {
+	int n = 0;
+
X 	ASSERT(self != NULL, return;);
X 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
X 	
@@ -314,22 +328,37 @@
X 	 *  Is is possible to change speed yet? Wait until the last byte 
X 	 *  has been transmitted.
X 	 */
-	if (self->wait_until_sent) {
-		self->wait_until_sent(self);
-		
-		if (self->dongle)
-			self->dongle->change_speed(self, speed);
-		
-		if (self->change_speed) {
-			self->change_speed(self, speed);
-			
-			/* Update the QoS value only */
-			self->qos.baud_rate.value = speed;
+	if (!self->wait_until_sent) {
+		ERROR("IrDA: wait_until_sent() "
+		      "has not implemented by the IrDA device driver!\n");
+		return;
+	}
+
+	/* Make sure all transmitted data has actually been sent */
+	self->wait_until_sent(self);
+
+	/* Make sure nobody tries to transmit during the speed change */
+	while (irda_lock((void *) &self->netdev.tbusy) == FALSE) {
+		WARNING(__FUNCTION__ "(), device locked!\n");
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(MSECS_TO_JIFFIES(10));
+
+		if (n++ > 10) {
+			WARNING(__FUNCTION__ "(), breaking loop!\n");
+			break;
X 		}
-	} else {
-		WARNING("IrDA: wait_until_sent() "
-			"has not implemented by the IrDA device driver!\n");
X 	}
+	
+	if (self->dongle)
+		self->dongle->change_speed(self, speed);
+	
+	if (self->change_speed) {
+		self->change_speed(self, speed);
+		
+		/* Update the QoS value only */
+		self->qos.baud_rate.value = speed;
+	}
+	self->netdev.tbusy = FALSE;
X }
X 
X /*
@@ -340,8 +369,6 @@
X  */
X inline void irda_device_change_speed(struct irda_device *self, int speed)
X {
-	DEBUG(4, __FUNCTION__ "()\n");
-
X 	ASSERT(self != NULL, return;);
X 	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
X 
@@ -352,27 +379,27 @@
X 
X inline int irda_device_is_media_busy( struct irda_device *self)
X {
-	ASSERT( self != NULL, return FALSE;);
-	ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	ASSERT(self != NULL, return FALSE;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
X 	
X 	return self->media_busy;
X }
X 
X inline int irda_device_is_receiving( struct irda_device *self)
X {
-	ASSERT( self != NULL, return FALSE;);
-	ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+	ASSERT(self != NULL, return FALSE;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
X 
-	if ( self->is_receiving)
-		return self->is_receiving( self);
+	if (self->is_receiving)
+		return self->is_receiving(self);
X 	else
X 		return FALSE;
X }
X 
-inline struct qos_info *irda_device_get_qos( struct irda_device *self)
+inline struct qos_info *irda_device_get_qos(struct irda_device *self)
X {
-	ASSERT( self != NULL, return NULL;);
-	ASSERT( self->magic == IRDA_DEVICE_MAGIC, return NULL;);
+	ASSERT(self != NULL, return NULL;);
+	ASSERT(self->magic == IRDA_DEVICE_MAGIC, return NULL;);
X 
X 	return &self->qos;
X }
@@ -394,8 +421,6 @@
X {
X 	struct irda_device *self;
X 
-	DEBUG(4, __FUNCTION__ "()\n");
-
X 	ASSERT(dev != NULL, return -1;);
X 
X 	self = (struct irda_device *) dev->priv;
@@ -467,6 +492,8 @@
X      return 0;  
X }
X 
+
+#define SIOCSDONGLE     SIOCDEVPRIVATE
X static int irda_device_net_ioctl(struct device *dev, /* ioctl device */
X 				 struct ifreq *rq,   /* Data passed */
X 				 int	cmd)	     /* Ioctl number */
@@ -577,6 +604,10 @@
X #endif 
X 		break;
X #endif
+	case SIOCSDONGLE: /* Set dongle */
+		/* Initialize dongle */
+		irda_device_init_dongle(self, (int) rq->ifr_data);
+		break;
X 	default:
X 		ret = -EOPNOTSUPP;
X 	}
@@ -652,6 +683,11 @@
X 		ERROR("IrDA: Unable to find requested dongle\n");
X 		return;
X 	}
+	
+	/* Check if we're already using a dongle */
+	if (self->dongle) {
+		self->dongle->close(self);
+	}
X 
X 	/* Set the dongle to be used by this driver */
X 	self->dongle = node->dongle;
@@ -661,7 +697,7 @@
X 	node->dongle->qos_init(self, &self->qos);
X 	
X 	/* Reset dongle */
-	node->dongle->reset(self, 0);
+	node->dongle->reset(self);
X 
X 	/* Set to default baudrate */
X 	irda_device_change_speed(self, 9600);
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlan/irlan_client.c linux/net/irda/irlan/irlan_client.c
--- v2.3.5/linux/net/irda/irlan/irlan_client.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlan/irlan_client.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Tue May 11 00:22:39 1999
+ * Modified at:   Mon May 31 14:19:34 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * Sources:       skeleton.c by Donald Becker <bec...@CESDIS.gsfc.nasa.gov>
X  *                slip.c by Laurence Culhane, <l...@holmes.demon.co.uk>
@@ -213,7 +213,7 @@
X {
X 	struct irlan_cb *self;
X 	
-	DEBUG(4, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
X 	
X 	self = (struct irlan_cb *) instance;
X 	
@@ -222,6 +222,12 @@
X 	ASSERT(skb != NULL, return -1;);
X 	
X 	irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); 
+
+	/* Ready for a new command */
+	self->client.tx_busy = FALSE;
+
+	/* Check if we have some queued commands waiting to be sent */
+	irlan_run_ctrl_tx_queue(self);
X 
X 	return 0;
X }
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlan/irlan_client_event.c linux/net/irda/irlan/irlan_client_event.c
--- v2.3.5/linux/net/irda/irlan/irlan_client_event.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlan/irlan_client_event.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu May  6 13:42:38 1999
+ * Modified at:   Fri May 14 23:08:15 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>, 
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.3.5/linux/net/irda/irlan/irlan_common.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlan/irlan_common.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Sun May  9 11:48:49 1999
+ * Modified at:   Mon May 31 14:25:19 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1997, 1999 Dag Brattli <da...@cs.uit.no>, 
@@ -301,7 +301,9 @@
X 	init_timer(&self->client.kick_timer);
X 
X 	hashbin_insert(irlan, (QUEUE *) self, daddr, NULL);
-		
+	
+	skb_queue_head_init(&self->client.txq);
+	
X 	irlan_next_client_state(self, IRLAN_IDLE);
X 	irlan_next_provider_state(self, IRLAN_IDLE);
X 
@@ -321,7 +323,7 @@
X  */
X static void __irlan_close(struct irlan_cb *self)
X {
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
X 	
X 	ASSERT(self != NULL, return;);
X 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -423,8 +425,6 @@
X {
X 	struct irlan_cb *self;
X 
-	DEBUG(2, __FUNCTION__ "()\n");
-
X 	self = (struct irlan_cb *) instance;
X 
X 	ASSERT(self != NULL, return;);
@@ -444,9 +444,15 @@
X 	 */
X 	irlan_get_unicast_addr(self);
X 	irlan_open_unicast_addr(self);
+	
+	/* Open broadcast and multicast filter by default */
+ 	irlan_set_broadcast_filter(self, TRUE);
+ 	irlan_set_multicast_filter(self, TRUE);
X 
X 	/* Ready to transfer Ethernet frames */
X 	self->dev.tbusy = 0;
+
+	irlan_eth_send_gratuitous_arp(&self->dev);
X }
X 
X /*
@@ -495,9 +501,6 @@
X 		break;
X 	}
X 	
-	/* Stop IP from transmitting more packets */
-	/* irlan_client_flow_indication(handle, FLOW_STOP, priv); */
-
X 	irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
X 	irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
X }
@@ -507,7 +510,7 @@
X 	struct notify_t notify;
X 	struct tsap_cb *tsap;
X 
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
X 
X 	ASSERT(self != NULL, return;);
X 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -522,7 +525,7 @@
X 	notify.udata_indication      = irlan_eth_receive;
X 	notify.connect_indication    = irlan_connect_indication;
X 	notify.connect_confirm       = irlan_connect_confirm;
- 	notify.flow_indication       = irlan_eth_flow_indication;
+ 	/*notify.flow_indication       = irlan_eth_flow_indication;*/
X 	notify.disconnect_indication = irlan_disconnect_indication;
X 	notify.instance              = self;
X 	strncpy(notify.name, "IrLAN data", NOTIFY_MAX_NAME);
@@ -555,7 +558,6 @@
X 		irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
X 		irttp_close_tsap(self->tsap_data);
X 		self->tsap_data = NULL;
-		
X 	}
X 	if (self->client.tsap_ctrl) {
X 		irttp_disconnect_request(self->client.tsap_ctrl, NULL, 
@@ -608,15 +610,60 @@
X 		irias_add_string_attrib(obj, "Name", "Linux");
X #endif
X 		irias_add_string_attrib(obj, "DeviceID", "HWP19F0");
-		irias_add_integer_attrib(obj, "CompCnt", 2);
-		irias_add_string_attrib(obj, "Comp#01", "PNP8294");
-		irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+		irias_add_integer_attrib(obj, "CompCnt", 1);
+		if (self->provider.access_type == ACCESS_PEER)
+			irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+		else
+			irias_add_string_attrib(obj, "Comp#01", "PNP8294");
+
X 		irias_add_string_attrib(obj, "Manufacturer", "Linux-IrDA Project");
X 		irias_insert_object(obj);
X 	}
X }
X 
X /*
+ * Function irlan_run_ctrl_tx_queue (self)
+ *
+ *    Try to send the next command in the control transmit queue
+ *
+ */
+int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
+{
+	struct sk_buff *skb;
+
+	if (irda_lock(&self->client.tx_busy) == FALSE)
+		return -EBUSY;
+
+	skb = skb_dequeue(&self->client.txq);
+	if (!skb) {
+		self->client.tx_busy = FALSE;
+		return 0;
+	}
+	if (self->client.tsap_ctrl == NULL) {
+		self->client.tx_busy = FALSE;
+		dev_kfree_skb(skb);
+		return -1;
+	}
+
+	return irttp_data_request(self->client.tsap_ctrl, skb);
+}
+
+/*
+ * Function irlan_ctrl_data_request (self, skb)
+ *
+ *    This function makes sure that commands on the control channel is being
+ *    sent in a command/response fashion
+ */
+void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
+{
+	/* Queue command */
+	skb_queue_tail(&self->client.txq, skb);
+
+	/* Try to send command */
+	irlan_run_ctrl_tx_queue(self);
+}
+
+/*
X  * Function irlan_get_provider_info (self)
X  *
X  *    Send Get Provider Information command to peer IrLAN layer
@@ -645,7 +692,8 @@
X  	frame[0] = CMD_GET_PROVIDER_INFO;
X 	frame[1] = 0x00;                 /* Zero parameters */
X 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X /*
@@ -683,7 +731,8 @@
X 
X /* 	self->use_udata = TRUE; */
X 
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X void irlan_close_data_channel(struct irlan_cb *self) 
@@ -696,6 +745,10 @@
X 	ASSERT(self != NULL, return;);
X 	ASSERT(self->magic == IRLAN_MAGIC, return;);
X 
+	/* Check if the TSAP is still there */
+	if (self->client.tsap_ctrl == NULL)
+		return;
+
X 	skb = dev_alloc_skb(64);
X 	if (!skb)
X 		return;
@@ -711,7 +764,8 @@
X 
X 	irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
X 
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X /*
@@ -747,7 +801,8 @@
X  	irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
X  	irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
X 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X /*
@@ -787,8 +842,9 @@
X 		irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
X 	else
X 		irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
-	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X /*
@@ -826,8 +882,9 @@
X 		irlan_insert_string_param(skb, "FILTER_MODE", "ALL"); 
X 	else
X 		irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
-	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X /*
@@ -864,7 +921,8 @@
X  	irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
X  	irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); 
X 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X /*
@@ -899,7 +957,8 @@
X 	
X 	irlan_insert_string_param(skb, "MEDIA", "802.3");
X 	
-	irttp_data_request(self->client.tsap_ctrl, skb);
+	/* irttp_data_request(self->client.tsap_ctrl, skb); */
+	irlan_ctrl_data_request(self, skb);
X }
X 
X /*
@@ -1153,34 +1212,34 @@
X 		printk(KERN_INFO "Success\n");
X 		break;
X 	case 1:
-		printk(KERN_WARNING "Insufficient resources\n");
+		WARNING("IrLAN: Insufficient resources\n");
X 		break;
X 	case 2:
-		printk(KERN_WARNING "Invalid command format\n");
+		WARNING("IrLAN: Invalid command format\n");
X 		break;
X 	case 3:
-		printk(KERN_WARNING "Command not supported\n");
+		WARNING("IrLAN: Command not supported\n");
X 		break;
X 	case 4:
-		printk(KERN_WARNING "Parameter not supported\n");
+		WARNING("IrLAN: Parameter not supported\n");
X 		break;
X 	case 5:
-		printk(KERN_WARNING "Value not supported\n");
+		WARNING("IrLAN: Value not supported\n");
X 		break;
X 	case 6:
-		printk(KERN_WARNING "Not open\n");
+		WARNING("IrLAN: Not open\n");
X 		break;
X 	case 7:
-		printk(KERN_WARNING "Authentication required\n");
+		WARNING("IrLAN: Authentication required\n");
X 		break;
X 	case 8:
-		printk(KERN_WARNING "Invalid password\n");
+		WARNING("IrLAN: Invalid password\n");
X 		break;
X 	case 9:
-		printk(KERN_WARNING "Protocol error\n");
+		WARNING("IrLAN: Protocol error\n");
X 		break;
X 	case 255:
-		printk(KERN_WARNING "Asynchronous status\n");
+		WARNING("IrLAN: Asynchronous status\n");
X 		break;
X 	}
X }
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlan/irlan_eth.c linux/net/irda/irlan/irlan_eth.c
--- v2.3.5/linux/net/irda/irlan/irlan_eth.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlan/irlan_eth.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Thu Oct 15 08:37:58 1998
- * Modified at:   Mon May 10 20:23:49 1999
+ * Modified at:   Mon May 31 19:57:08 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * Sources:       skeleton.c by Donald Becker <bec...@CESDIS.gsfc.nasa.gov>
X  *                slip.c by Laurence Culhane,   <l...@holmes.demon.co.uk>
@@ -50,7 +50,7 @@
X 	struct irmanager_event mgr_event;
X 	struct irlan_cb *self;
X 
-	DEBUG(0, __FUNCTION__"()\n");
+	DEBUG(2, __FUNCTION__"()\n");
X 
X 	ASSERT(dev != NULL, return -1;);
X        
@@ -66,7 +66,12 @@
X 	
X 	ether_setup(dev);
X 	
-	dev->tx_queue_len = TTP_MAX_QUEUE;
+	/* 
+	 * Lets do all queueing in IrTTP instead of this device driver.
+	 * Queueing here as well can introduce some strange latency
+	 * problems, which we will avoid by setting the queue size to 0.
+	 */
+	dev->tx_queue_len = 0;
X 
X 	if (self->provider.access_type == ACCESS_DIRECT) {
X 		/*  
@@ -110,7 +115,7 @@
X {
X 	struct irlan_cb *self;
X 	
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
X 
X 	ASSERT(dev != NULL, return -1;);
X 
@@ -145,7 +150,7 @@
X {
X 	struct irlan_cb *self = (struct irlan_cb *) dev->priv;
X 
-	DEBUG(0, __FUNCTION__ "()\n");
+	DEBUG(2, __FUNCTION__ "()\n");
X 	
X 	/* Stop device */
X 	dev->tbusy = 1;
@@ -180,26 +185,16 @@
X int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
X {
X 	struct irlan_cb *self;
+	int ret;
X 
X 	self = (struct irlan_cb *) dev->priv;
X 
X 	ASSERT(self != NULL, return 0;);
X 	ASSERT(self->magic == IRLAN_MAGIC, return 0;);
X 
-	/* Lock transmit buffer */
-	if (irda_lock((void *) &dev->tbusy) == FALSE) {
-		/*
-		 * If we get here, some higher level has decided we are broken.
-		 * There should really be a "kick me" function call instead.
-		 */
-		int tickssofar = jiffies - dev->trans_start; 
-		
-		if (tickssofar < 5) 
- 			return -EBUSY;
-		
- 		dev->tbusy = 0;
- 		dev->trans_start = jiffies;
-	}
+	/* Check if IrTTP can accept more frames */
+	if (dev->tbusy)
+		return -EBUSY;
X 	
X 	/* skb headroom large enough to contain all IrDA-headers? */
X 	if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
@@ -218,31 +213,30 @@
X 	} 
X 
X 	dev->trans_start = jiffies;
-	self->stats.tx_packets++;
-	self->stats.tx_bytes += skb->len; 
X 
X 	/* Now queue the packet in the transport layer */
X 	if (self->use_udata)
-		irttp_udata_request(self->tsap_data, skb);
-	else {
-		if (irttp_data_request(self->tsap_data, skb) < 0) {
-			/*   
-			 * IrTTPs tx queue is full, so we just have to
-			 * drop the frame! You might think that we should
-			 * just return -1 and don't deallocate the frame,
-			 * but that is dangerous since it's possible that
-			 * we have replaced the original skb with a new
-			 * one with larger headroom, and that would really
-			 * confuse do_dev_queue_xmit() in dev.c! I have
-			 * tried :-) DB 
-			 */
-			dev_kfree_skb(skb);
-			++self->stats.tx_dropped;
-		
-			return 0;
-		}
+		ret = irttp_udata_request(self->tsap_data, skb);
+	else
+		ret = irttp_data_request(self->tsap_data, skb);
+
+	if (ret < 0) {
+		/*   
+		 * IrTTPs tx queue is full, so we just have to
+		 * drop the frame! You might think that we should
+		 * just return -1 and don't deallocate the frame,
+		 * but that is dangerous since it's possible that
+		 * we have replaced the original skb with a new
+		 * one with larger headroom, and that would really
+		 * confuse do_dev_queue_xmit() in dev.c! I have
+		 * tried :-) DB 
+		 */
+		dev_kfree_skb(skb);
+		self->stats.tx_dropped++;
+	} else {
+		self->stats.tx_packets++;
+		self->stats.tx_bytes += skb->len; 
X 	}
-	dev->tbusy = 0; /* Finished! */
X 	
X 	return 0;
X }
@@ -276,11 +270,11 @@
X 	skb->dev = &self->dev;
X 	skb->protocol=eth_type_trans(skb, skb->dev); /* Remove eth header */
X 	
-	netif_rx(skb);   /* Eat it! */
-	
X 	self->stats.rx_packets++;
X 	self->stats.rx_bytes += skb->len; 
X 
+	netif_rx(skb);   /* Eat it! */
+	
X 	return 0;
X }
X 
@@ -295,8 +289,6 @@
X 	struct irlan_cb *self;
X 	struct device *dev;
X 
-	DEBUG(4, __FUNCTION__ "()\n");
-
X 	self = (struct irlan_cb *) instance;
X 
X 	ASSERT(self != NULL, return;);
@@ -344,7 +336,7 @@
X  *    Send gratuitous ARP to announce that we have changed
X  *    hardware address, so that all peers updates their ARP tables
X  */
-void irlan_etc_send_gratuitous_arp(struct device *dev) 
+void irlan_eth_send_gratuitous_arp(struct device *dev)
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 24'
echo 'File patch-2.3.6 is continued in part 25'
echo 25 > _shar_seq_.tmp
#!/bin/sh
# this is part 25 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 25; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
X {
X 	struct in_device *in_dev;
X 
@@ -375,16 +367,21 @@
X 
X  	self = dev->priv; 
X 
-	DEBUG(0, __FUNCTION__ "()\n");
- return;
+	DEBUG(2, __FUNCTION__ "()\n");
+
X  	ASSERT(self != NULL, return;); 
X  	ASSERT(self->magic == IRLAN_MAGIC, return;);
X 
-	if (dev->flags&IFF_PROMISC) {
-		/* Enable promiscuous mode */
-		DEBUG(0, "Promiscous mode not implemented\n");
-		/* outw(MULTICAST|PROMISC, ioaddr); */
+	/* Check if data channel has been connected yet */
+	if (self->client.state != IRLAN_DATA) {
+		DEBUG(1, __FUNCTION__ "(), delaying!\n");
+		return;
X 	}
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Enable promiscuous mode */
+		WARNING("Promiscous mode not implemented by IrLAN!\n");
+	} 
X 	else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) {
X 		/* Disable promiscuous mode, use normal mode. */
X 		DEBUG(4, __FUNCTION__ "(), Setting multicast filter\n");
@@ -404,13 +401,10 @@
X 		irlan_set_multicast_filter(self, FALSE);
X 	}
X 
-	if (dev->flags & IFF_BROADCAST) {
-		DEBUG(4, __FUNCTION__ "(), Setting broadcast filter\n");
+	if (dev->flags & IFF_BROADCAST)
X 		irlan_set_broadcast_filter(self, TRUE);
-	} else {
-		DEBUG(4, __FUNCTION__ "(), Clearing broadcast filter\n");
+	else
X 		irlan_set_broadcast_filter(self, FALSE);
-	}
X }
X 
X /*
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlan/irlan_filter.c linux/net/irda/irlan/irlan_filter.c
--- v2.3.5/linux/net/irda/irlan/irlan_filter.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlan/irlan_filter.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Fri Jan 29 11:16:38 1999
- * Modified at:   Sat May  8 15:25:23 1999
+ * Modified at:   Fri May 14 23:11:01 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -23,6 +23,7 @@
X  ********************************************************************/
X 
X #include <linux/skbuff.h>
+#include <linux/random.h>
X 
X #include <net/irda/irlan_common.h>
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlap.c linux/net/irda/irlap.c
--- v2.3.5/linux/net/irda/irlap.c	Sat Apr 24 17:50:06 1999
+++ linux/net/irda/irlap.c	Mon Jun  7 16:18:58 1999
@@ -1,26 +1,31 @@
X /*********************************************************************
X  *                
X  * Filename:      irlap.c
- * Version:       0.9
- * Description:   An IrDA LAP driver for Linux
- * Status:        Stable.
+ * Version:       1.0
+ * Description:   IrLAP implementation for Linux
+ * Status:        Stable
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Apr 23 10:12:29 1999
+ * Modified at:   Mon May 31 21:43:55 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
- *     Copyright (c) 1998 Dag Brattli <da...@cs.uit.no>, 
- *     All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
X  *     
- *     This program is free software; you can redistribute iyt and/or 
+ *     This program is free software; you can redistribute it and/or 
X  *     modify it under the terms of the GNU General Public License as 
X  *     published by the Free Software Foundation; either version 2 of 
X  *     the License, or (at your option) any later version.
- *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *
+ * 
+ *     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., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
+ *     
X  ********************************************************************/
X 
X #include <linux/config.h>
@@ -60,23 +65,23 @@
X };
X 
X #ifdef CONFIG_PROC_FS
-int irlap_proc_read( char *, char **, off_t, int, int);
+int irlap_proc_read(char *, char **, off_t, int, int);
X 
X #endif /* CONFIG_PROC_FS */
X 
-__initfunc(int irlap_init( void))
+__initfunc(int irlap_init(void))
X {
X 	/* Allocate master array */
-	irlap = hashbin_new( HB_LOCAL);
-	if ( irlap == NULL) {
-		printk( KERN_WARNING "IrLAP: Can't allocate irlap hashbin!\n");
+	irlap = hashbin_new(HB_LOCAL);
+	if (irlap == NULL) {
+		printk(KERN_WARNING "IrLAP: Can't allocate irlap hashbin!\n");
X 		return -ENOMEM;
X 	}
X 
X #ifdef CONFIG_IRDA_COMPRESSION
-	irlap_compressors = hashbin_new( HB_LOCAL);
-	if ( irlap_compressors == NULL) {
-		printk( KERN_WARNING "IrLAP: Can't allocate compressors hashbin!\n");
+	irlap_compressors = hashbin_new(HB_LOCAL);
+	if (irlap_compressors == NULL) {
+		printk(KERN_WARNING "IrLAP: Can't allocate compressors hashbin!\n");
X 		return -ENOMEM;
X 	}
X #endif
@@ -86,12 +91,12 @@
X 
X void irlap_cleanup(void)
X {
-	ASSERT( irlap != NULL, return;);
+	ASSERT(irlap != NULL, return;);
X 
-	hashbin_delete( irlap, (FREE_FUNC) __irlap_close);
+	hashbin_delete(irlap, (FREE_FUNC) __irlap_close);
X 
X #ifdef CONFIG_IRDA_COMPRESSION
-	hashbin_delete( irlap_compressors, (FREE_FUNC) kfree);
+	hashbin_delete(irlap_compressors, (FREE_FUNC) kfree);
X #endif
X }
X 
@@ -101,32 +106,32 @@
X  *    Initialize IrLAP layer
X  *
X  */
-struct irlap_cb *irlap_open( struct irda_device *irdev)
+struct irlap_cb *irlap_open(struct irda_device *irdev)
X {
X 	struct irlap_cb *self;
X 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 	
-	ASSERT( irdev != NULL, return NULL;);
-	ASSERT( irdev->magic == IRDA_DEVICE_MAGIC, return NULL;);
+	ASSERT(irdev != NULL, return NULL;);
+	ASSERT(irdev->magic == IRDA_DEVICE_MAGIC, return NULL;);
X 
X 	/* Initialize the irlap structure. */
-	self = kmalloc( sizeof( struct irlap_cb), GFP_KERNEL);
-	if ( self == NULL)
+	self = kmalloc(sizeof(struct irlap_cb), GFP_KERNEL);
+	if (self == NULL)
X 		return NULL;
X 	
-	memset( self, 0, sizeof(struct irlap_cb));
+	memset(self, 0, sizeof(struct irlap_cb));
X 	self->magic = LAP_MAGIC;
X 
X 	/* Make a binding between the layers */
X 	self->irdev = irdev;
X 	self->netdev = &irdev->netdev;
X 
-	irlap_next_state( self, LAP_OFFLINE);
+	irlap_next_state(self, LAP_OFFLINE);
X 
X 	/* Initialize transmitt queue */
-	skb_queue_head_init( &self->tx_list);
-	skb_queue_head_init( &self->wx_list);
+	skb_queue_head_init(&self->tx_list);
+	skb_queue_head_init(&self->wx_list);
X 
X 	/* My unique IrLAP device address! */
X 	get_random_bytes(&self->saddr, sizeof(self->saddr));
@@ -140,21 +145,21 @@
X 		self->caddr &= 0xfe;
X 	}
X 
-	init_timer( &self->slot_timer);
-	init_timer( &self->query_timer);
-	init_timer( &self->discovery_timer);
-	init_timer( &self->final_timer);		
-	init_timer( &self->poll_timer);
-	init_timer( &self->wd_timer);
-	init_timer( &self->backoff_timer);
+	init_timer(&self->slot_timer);
+	init_timer(&self->query_timer);
+	init_timer(&self->discovery_timer);
+	init_timer(&self->final_timer);		
+	init_timer(&self->poll_timer);
+	init_timer(&self->wd_timer);
+	init_timer(&self->backoff_timer);
X 
-	irlap_apply_default_connection_parameters( self);
+	irlap_apply_default_connection_parameters(self);
X 	
-	irlap_next_state( self, LAP_NDM);
+	irlap_next_state(self, LAP_NDM);
X 
-	hashbin_insert( irlap, (QUEUE *) self, self->saddr, NULL);
+	hashbin_insert(irlap, (QUEUE *) self, self->saddr, NULL);
X 
-	irlmp_register_link( self, self->saddr, &self->notify);
+	irlmp_register_link(self, self->saddr, &self->notify);
X 	
X 	return self;
X }
@@ -165,26 +170,26 @@
X  *    Remove IrLAP and all allocated memory. Stop any pending timers.
X  *
X  */
-static void __irlap_close( struct irlap_cb *self)
+static void __irlap_close(struct irlap_cb *self)
X {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
X 	/* Stop timers */
-	del_timer( &self->slot_timer);
-	del_timer( &self->query_timer);
-	del_timer( &self->discovery_timer);
-	del_timer( &self->final_timer);		
-	del_timer( &self->poll_timer);
-	del_timer( &self->wd_timer);
-	del_timer( &self->backoff_timer);
+	del_timer(&self->slot_timer);
+	del_timer(&self->query_timer);
+	del_timer(&self->discovery_timer);
+	del_timer(&self->final_timer);		
+	del_timer(&self->poll_timer);
+	del_timer(&self->wd_timer);
+	del_timer(&self->backoff_timer);
X 
-	irlap_flush_all_queues( self);
+	irlap_flush_all_queues(self);
X        
X 	self->irdev = NULL;
X 	self->magic = 0;
X 	
-	kfree( self);
+	kfree(self);
X }
X 
X /*
@@ -193,27 +198,27 @@
X  *    Remove IrLAP instance
X  *
X  */
-void irlap_close( struct irlap_cb *self) 
+void irlap_close(struct irlap_cb *self) 
X {
X 	struct irlap_cb *lap;
X 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
-	irlap_disconnect_indication( self, LAP_DISC_INDICATION);
+	irlap_disconnect_indication(self, LAP_DISC_INDICATION);
X 
X 	irlmp_unregister_link(self->saddr);
X 	self->notify.instance = NULL;
X 
X 	/* Be sure that we manage to remove ourself from the hash */
-	lap = hashbin_remove( irlap, self->saddr, NULL);
-	if ( !lap) {
-		DEBUG( 1, __FUNCTION__ "(), Didn't find myself!\n");
+	lap = hashbin_remove(irlap, self->saddr, NULL);
+	if (!lap) {
+		DEBUG(1, __FUNCTION__ "(), Didn't find myself!\n");
X 		return;
X 	}
-	__irlap_close( lap);
+	__irlap_close(lap);
X }
X 
X /*
@@ -243,7 +248,7 @@
X  */
X void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) 
X {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 	
X 	irlap_do_event(self, CONNECT_RESPONSE, skb, NULL);
X }
@@ -324,23 +329,23 @@
X  *    Received some data that was sent unreliable
X  *
X  */
-void irlap_unit_data_indication( struct irlap_cb *self, struct sk_buff *skb)
+void irlap_unit_data_indication(struct irlap_cb *self, struct sk_buff *skb)
X {
-	DEBUG( 1, __FUNCTION__ "()\n"); 
+	DEBUG(1, __FUNCTION__ "()\n"); 
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
X 
X 	/* Hide LAP header from IrLMP layer */
-	skb_pull( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+	skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
X 
X #ifdef CONFIG_IRDA_COMPRESSION
-	if ( self->qos_tx.compression.value) {
+	if (self->qos_tx.compression.value) {
X 		
-		skb = irlap_decompress_frame( self, skb);
-		if ( !skb) {
-			DEBUG( 1, __FUNCTION__ "(), Decompress error!\n");
+		skb = irlap_decompress_frame(self, skb);
+		if (!skb) {
+			DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
X 			return;
X 		}
X 	}
@@ -354,40 +359,35 @@
X  *    Queue data for transmission, must wait until XMIT state
X  *
X  */
-inline void irlap_data_request( struct irlap_cb *self, struct sk_buff *skb,
+inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
X 				int reliable)
X {
-	DEBUG( 4, __FUNCTION__ "()\n");
-       
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-
-	DEBUG( 4, __FUNCTION__ "(), tx_list=%d\n", 
-		   skb_queue_len( &self->tx_list));
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
X 
X #ifdef CONFIG_IRDA_COMPRESSION
-	if ( self->qos_tx.compression.value) {
-		skb = irlap_compress_frame( self, skb);
-		if ( !skb) {
-			DEBUG( 1, __FUNCTION__ "(), Compress error!\n");
+	if (self->qos_tx.compression.value) {
+		skb = irlap_compress_frame(self, skb);
+		if (!skb) {
+			DEBUG(1, __FUNCTION__ "(), Compress error!\n");
X 			return;
X 		}
X 	}
X #endif
X 	
-	ASSERT( skb_headroom( skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
-		return;);
-	skb_push( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+	ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), 
+	       return;);
+	skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
X 
X 	/*  
X 	 *  Must set frame format now so that the rest of the code knows 
X 	 *  if its dealing with an I or an UI frame
X 	 */
-	if ( reliable)
+	if (reliable)
X 		skb->data[1] = I_FRAME;
X 	else {
-		DEBUG( 4, __FUNCTION__ "(), queueing unreliable frame\n");
+		DEBUG(4, __FUNCTION__ "(), queueing unreliable frame\n");
X 		skb->data[1] = UI_FRAME;
X 	}
X 
@@ -395,20 +395,20 @@
X 	 *  Send event if this frame only if we are in the right state 
X 	 *  FIXME: udata should be sent first! (skb_queue_head?)
X 	 */
-  	if (( self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
+  	if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
X 		/*
X 		 *  Check if the transmit queue contains some unsent frames,
X 		 *  and if so, make sure they are sent first
X 		 */
-		if ( !skb_queue_empty( &self->tx_list)) {
-			skb_queue_tail( &self->tx_list, skb);
-			skb = skb_dequeue( &self->tx_list);
+		if (!skb_queue_empty(&self->tx_list)) {
+			skb_queue_tail(&self->tx_list, skb);
+			skb = skb_dequeue(&self->tx_list);
X 			
-			ASSERT( skb != NULL, return;);
+			ASSERT(skb != NULL, return;);
X 		}
-		irlap_do_event( self, SEND_I_CMD, skb, NULL);
+		irlap_do_event(self, SEND_I_CMD, skb, NULL);
X 	} else
-		skb_queue_tail( &self->tx_list, skb);	
+		skb_queue_tail(&self->tx_list, skb);	
X }
X 
X /*
@@ -444,33 +444,33 @@
X  *    Disconnect request from other device
X  *
X  */
-void irlap_disconnect_indication( struct irlap_cb *self, LAP_REASON reason) 
+void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) 
X {
-	DEBUG( 1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); 
+	DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); 
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
X #ifdef CONFIG_IRDA_COMPRESSION
-	irda_free_compression( self);
+	irda_free_compression(self);
X #endif
X 	/* Flush queues */
-	irlap_flush_all_queues( self);
+	irlap_flush_all_queues(self);
X 	
-	switch( reason) {
+	switch(reason) {
X 	case LAP_RESET_INDICATION:
-		DEBUG( 1, __FUNCTION__ "(), Sending reset request!\n");
-		irlap_do_event( self, RESET_REQUEST, NULL, NULL);
+		DEBUG(1, __FUNCTION__ "(), Sending reset request!\n");
+		irlap_do_event(self, RESET_REQUEST, NULL, NULL);
X 		break;
X 	case LAP_NO_RESPONSE:	   /* FALLTROUGH */	
X 	case LAP_DISC_INDICATION:  /* FALLTROUGH */
X 	case LAP_FOUND_NONE:       /* FALLTROUGH */
X 	case LAP_MEDIA_BUSY:
-		irlmp_link_disconnect_indication( self->notify.instance, 
+		irlmp_link_disconnect_indication(self->notify.instance, 
X 						  self, reason, NULL);
X 		break;
X 	default:
-		DEBUG( 1, __FUNCTION__ "(), Reason %d not implemented!\n", 
+		DEBUG(1, __FUNCTION__ "(), Reason %d not implemented!\n", 
X 		       reason);
X 	}
X }
@@ -485,22 +485,22 @@
X {
X 	struct irlap_info info;
X 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( discovery != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+	ASSERT(discovery != NULL, return;);
X 	
-	DEBUG( 4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
+	DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
X 
-	ASSERT(( discovery->nslots == 1) || ( discovery->nslots == 6) ||
-	       ( discovery->nslots == 8) || ( discovery->nslots == 16), 
+	ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
+	       (discovery->nslots == 8) || (discovery->nslots == 16), 
X 	       return;);
X 	
X   	/*
X 	 *  Discovery is only possible in NDM mode
X 	 */ 
-	if ( self->state == LAP_NDM) {
-		ASSERT( self->discovery_log == NULL, return;);
-		self->discovery_log= hashbin_new( HB_LOCAL);
+	if (self->state == LAP_NDM) {
+		ASSERT(self->discovery_log == NULL, return;);
+		self->discovery_log= hashbin_new(HB_LOCAL);
X 		
X 		info.S = discovery->nslots; /* Number of slots */
X 		info.s = 0; /* Current slot */
@@ -526,11 +526,11 @@
X 
X 		self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
X 		
-		irlap_do_event( self, DISCOVERY_REQUEST, NULL, &info);
+		irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
X 	} else { 
- 		DEBUG( 4, __FUNCTION__ 
+ 		DEBUG(4, __FUNCTION__ 
X 		       "(), discovery only possible in NDM mode\n");
-		irlap_discovery_confirm( self, NULL);
+		irlap_discovery_confirm(self, NULL);
X  	} 
X }
X 
@@ -540,12 +540,12 @@
X  *    A device has been discovered in front of this station, we
X  *    report directly to LMP.
X  */
-void irlap_discovery_confirm( struct irlap_cb *self, hashbin_t *discovery_log) 
+void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log) 
X {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 	
-	ASSERT( self->notify.instance != NULL, return;);
+	ASSERT(self->notify.instance != NULL, return;);
X 	
X 	/* 
X 	 * Check for successful discovery, since we are then allowed to clear 
@@ -556,7 +556,7 @@
X 		irda_device_set_media_busy(self->irdev, FALSE);
X 	
X 	/* Inform IrLMP */
-	irlmp_link_discovery_confirm( self->notify.instance, discovery_log);
+	irlmp_link_discovery_confirm(self->notify.instance, discovery_log);
X 	
X 	/* 
X 	 *  IrLMP has now the responsibilities for the discovery_log 
@@ -572,13 +572,13 @@
X  */
X void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) 
X {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( discovery != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+	ASSERT(discovery != NULL, return;);
X 
-	ASSERT( self->notify.instance != NULL, return;);
+	ASSERT(self->notify.instance != NULL, return;);
X 	
X 	irlmp_link_discovery_indication(self->notify.instance, discovery);
X }
@@ -591,12 +591,12 @@
X  */
X void irlap_status_indication(int quality_of_link) 
X {
-	switch( quality_of_link) {
+	switch(quality_of_link) {
X 	case STATUS_NO_ACTIVITY:
-		printk( KERN_INFO "IrLAP, no activity on link!\n");
+		printk(KERN_INFO "IrLAP, no activity on link!\n");
X 		break;
X 	case STATUS_NOISY:
-		printk( KERN_INFO "IrLAP, noisy link!\n");
+		printk(KERN_INFO "IrLAP, noisy link!\n");
X 		break;
X 	default:
X 		break;
@@ -610,17 +610,17 @@
X  *    
X  *
X  */
-void irlap_reset_indication( struct irlap_cb *self)
+void irlap_reset_indication(struct irlap_cb *self)
X {
-	DEBUG( 1, __FUNCTION__ "()\n");
+	DEBUG(1, __FUNCTION__ "()\n");
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 	
-	if ( self->state == LAP_RESET_WAIT)
-		irlap_do_event( self, RESET_REQUEST, NULL, NULL);
+	if (self->state == LAP_RESET_WAIT)
+		irlap_do_event(self, RESET_REQUEST, NULL, NULL);
X 	else
-		irlap_do_event( self, RESET_RESPONSE, NULL, NULL);
+		irlap_do_event(self, RESET_RESPONSE, NULL, NULL);
X }
X 
X /*
@@ -631,7 +631,7 @@
X  */
X void irlap_reset_confirm(void)
X {
- 	DEBUG( 1, __FUNCTION__ "()\n");
+ 	DEBUG(1, __FUNCTION__ "()\n");
X }
X 
X /*
@@ -641,15 +641,15 @@
X  *    S = Number of slots (0 -> S-1)
X  *    s = Current slot
X  */
-int irlap_generate_rand_time_slot( int S, int s) 
+int irlap_generate_rand_time_slot(int S, int s) 
X {
X 	int slot;
X 	
-	ASSERT(( S - s) > 0, return 0;);
+	ASSERT((S - s) > 0, return 0;);
X 
X 	slot = s + jiffies % (S-s);
X 	
-	ASSERT(( slot >= s) || ( slot < S), return 0;);
+	ASSERT((slot >= s) || (slot < S), return 0;);
X 	
X 	return slot;
X }
@@ -661,51 +661,51 @@
X  *    not intuitive and you should not try to change it. If you think it
X  *    contains bugs, please mail a patch to the author instead.
X  */
-void irlap_update_nr_received( struct irlap_cb *self, int nr) 
+void irlap_update_nr_received(struct irlap_cb *self, int nr) 
X {
X 	struct sk_buff *skb = NULL;
X 	int count = 0;
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
X 	/*
X          * Remove all the ack-ed frames from the window queue.
X          */
X 
-	DEBUG( 4, "--> wx_list=%d, va=%d, nr=%d\n", 
-	       skb_queue_len( &self->wx_list), self->va, nr);
+	DEBUG(4, "--> wx_list=%d, va=%d, nr=%d\n", 
+	       skb_queue_len(&self->wx_list), self->va, nr);
X 
X 	/* 
X 	 *  Optimize for the common case. It is most likely that the receiver
X 	 *  will acknowledge all the frames we have sent! So in that case we
X 	 *  delete all frames stored in window.
X 	 */
-	if ( nr == self->vs) {
-		while (( skb = skb_dequeue( &self->wx_list)) != NULL) {
+	if (nr == self->vs) {
+		while ((skb = skb_dequeue(&self->wx_list)) != NULL) {
X 		     dev_kfree_skb(skb);
X 		}
X 		/* The last acked frame is the next to send minus one */
X 		self->va = nr - 1;
X 	} else {
X 		/* Remove all acknowledged frames in current window */
-		while (( skb_peek( &self->wx_list) != NULL) && 
-		       ((( self->va+1) % 8) != nr)) 
+		while ((skb_peek(&self->wx_list) != NULL) && 
+		       (((self->va+1) % 8) != nr)) 
X 		{
-			skb = skb_dequeue( &self->wx_list);
+			skb = skb_dequeue(&self->wx_list);
X 			dev_kfree_skb(skb);
X 			
X 			self->va = (self->va + 1) % 8;
X 			count++;
X 		}
X 		
-		DEBUG( 4, "irlap_update_nr_received(), removed %d\n", count);
-		DEBUG( 4, "wx_list=%d, va=%d, nr=%d -->\n", 
-		       skb_queue_len( &self->wx_list), self->va, nr);
+		DEBUG(4, "irlap_update_nr_received(), removed %d\n", count);
+		DEBUG(4, "wx_list=%d, va=%d, nr=%d -->\n", 
+		       skb_queue_len(&self->wx_list), self->va, nr);
X 	}
X 	
X 	/* Advance window */
-	self->window = self->window_size - skb_queue_len( &self->wx_list);
+	self->window = self->window_size - skb_queue_len(&self->wx_list);
X }
X 
X /*
@@ -713,14 +713,14 @@
X  *
X  *    Validate the next to send (ns) field from received frame.
X  */
-int irlap_validate_ns_received( struct irlap_cb *self, int ns) 
+int irlap_validate_ns_received(struct irlap_cb *self, int ns) 
X {
-	ASSERT( self != NULL, return -ENODEV;);
-	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+	ASSERT(self != NULL, return -ENODEV;);
+	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
X 
X 	/*  ns as expected?  */
-	if ( ns == self->vr) {
-		DEBUG( 4, __FUNCTION__ "(), expected!\n");
+	if (ns == self->vr) {
+		DEBUG(4, __FUNCTION__ "(), expected!\n");
X 		return NS_EXPECTED;
X 	}
X 	/*
@@ -737,14 +737,14 @@
X  *    Validate the next to receive (nr) field from received frame.
X  *
X  */
-int irlap_validate_nr_received( struct irlap_cb *self, int nr) 
+int irlap_validate_nr_received(struct irlap_cb *self, int nr) 
X {
-	ASSERT( self != NULL, return -ENODEV;);
-	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+	ASSERT(self != NULL, return -ENODEV;);
+	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
X 
X 	/*  nr as expected?  */
-	if ( nr == self->vs) {
-		DEBUG( 4, __FUNCTION__ "(), expected!\n");
+	if (nr == self->vs) {
+		DEBUG(4, __FUNCTION__ "(), expected!\n");
X 		return NR_EXPECTED;
X 	}
X 
@@ -752,11 +752,11 @@
X 	 *  unexpected nr? (but within current window), first we check if the 
X 	 *  ns numbers of the frames in the current window wrap.
X 	 */
-	if ( self->va < self->vs) {
-		if (( nr >= self->va) && ( nr <= self->vs))
+	if (self->va < self->vs) {
+		if ((nr >= self->va) && (nr <= self->vs))
X 			return NR_UNEXPECTED;
X 	} else {
-		if (( nr >= self->va) || ( nr <= self->vs)) 
+		if ((nr >= self->va) || (nr <= self->vs)) 
X 			return NR_UNEXPECTED;
X 	}
X 	
@@ -770,12 +770,12 @@
X  *    Initialize the connection state parameters
X  *
X  */
-void irlap_initiate_connection_state( struct irlap_cb *self) 
+void irlap_initiate_connection_state(struct irlap_cb *self) 
X {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
X 	/* Next to send and next to receive */
X 	self->vs = self->vr = 0;
@@ -829,24 +829,24 @@
X  *    Flush all queues
X  *
X  */
-void irlap_flush_all_queues( struct irlap_cb *self) 
+void irlap_flush_all_queues(struct irlap_cb *self) 
X {
X 	struct sk_buff* skb;
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
X 	/* Free transmission queue */
-	while (( skb = skb_dequeue( &self->tx_list)) != NULL)
-		dev_kfree_skb( skb);
+	while ((skb = skb_dequeue(&self->tx_list)) != NULL)
+		dev_kfree_skb(skb);
X 	
X 	/* Free sliding window buffered packets */
-	while (( skb = skb_dequeue( &self->wx_list)) != NULL)
-		dev_kfree_skb( skb);
+	while ((skb = skb_dequeue(&self->wx_list)) != NULL)
+		dev_kfree_skb(skb);
X 
X #ifdef CONFIG_IRDA_RECYCLE_RR
-	if ( self->recycle_rr_skb) { 
- 		dev_kfree_skb( self->recycle_rr_skb);
+	if (self->recycle_rr_skb) { 
+ 		dev_kfree_skb(self->recycle_rr_skb);
X  		self->recycle_rr_skb = NULL;
X  	}
X #endif
@@ -866,7 +866,7 @@
X 	ASSERT(self->magic == LAP_MAGIC, return;);
X 
X 	if (!self->irdev) {
-		DEBUG( 1, __FUNCTION__ "(), driver missing!\n");
+		DEBUG(1, __FUNCTION__ "(), driver missing!\n");
X 		return;
X 	}
X 
@@ -883,8 +883,8 @@
X 	__u8 mask; /* Current bit tested */
X 	int i;
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
X 	/* 
X 	 *  Find out which compressors we support. We do this be checking that
@@ -892,24 +892,24 @@
X 	 *  actually been loaded. Ths is sort of hairy code but that is what 
X 	 *  you get when you do a little bit flicking :-)
X 	 */
-	DEBUG( 4, __FUNCTION__ "(), comp bits 0x%02x\n", 
+	DEBUG(4, __FUNCTION__ "(), comp bits 0x%02x\n", 
X 	       self->qos_rx.compression.bits); 
X 	mask = 0x80; /* Start with testing MSB */
-	for ( i=0;i<8;i++) {
-		DEBUG( 4, __FUNCTION__ "(), testing bit %d\n", 8-i);
-		if ( self->qos_rx.compression.bits & mask) {
-			DEBUG( 4, __FUNCTION__ "(), bit %d is set by defalt\n",
+	for (i=0;i<8;i++) {
+		DEBUG(4, __FUNCTION__ "(), testing bit %d\n", 8-i);
+		if (self->qos_rx.compression.bits & mask) {
+			DEBUG(4, __FUNCTION__ "(), bit %d is set by defalt\n",
X 			       8-i);
-			comp = hashbin_find( irlap_compressors, 
+			comp = hashbin_find(irlap_compressors, 
X 					     compression[ msb_index(mask)], 
X 					     NULL);
-			if ( !comp) {
+			if (!comp) {
X 				/* Protocol not supported, so clear the bit */
-				DEBUG( 4, __FUNCTION__ "(), Compression "
+				DEBUG(4, __FUNCTION__ "(), Compression "
X 				       "protocol %d has not been loaded!\n", 
X 				       compression[msb_index(mask)]);
X 				self->qos_rx.compression.bits &= ~mask;
-				DEBUG( 4, __FUNCTION__ 
+				DEBUG(4, __FUNCTION__ 
X 				       "(), comp bits 0x%02x\n", 
X 				       self->qos_rx.compression.bits); 
X 			}
@@ -931,20 +931,20 @@
X void irlap_init_qos_capabilities(struct irlap_cb *self,
X 				 struct qos_info *qos_user)
X {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( self->irdev != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
+	ASSERT(self->irdev != NULL, return;);
X 
X 	/* Start out with the maximum QoS support possible */
-	irda_init_max_qos_capabilies( &self->qos_rx);
+	irda_init_max_qos_capabilies(&self->qos_rx);
X 
X #ifdef CONFIG_IRDA_COMPRESSION
-	irlap_init_comp_qos_capabilities( self);
+	irlap_init_comp_qos_capabilities(self);
X #endif
X 
X 	/* Apply drivers QoS capabilities */
-	irda_qos_compute_intersection( &self->qos_rx, 
-				       irda_device_get_qos( self->irdev));
+	irda_qos_compute_intersection(&self->qos_rx, 
+				      irda_device_get_qos(self->irdev));
X 
X 	/*
X 	 *  Check for user supplied QoS parameters. The service user is only 
@@ -952,17 +952,17 @@
X 	 *  user may not have set all of them.
X 	 */
X 	if (qos_user) {
-		DEBUG( 1, __FUNCTION__ "(), Found user specified QoS!\n");
+		DEBUG(1, __FUNCTION__ "(), Found user specified QoS!\n");
X 
-		if ( qos_user->baud_rate.bits)
+		if (qos_user->baud_rate.bits)
X 			self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
X 
-		if ( qos_user->max_turn_time.bits)
+		if (qos_user->max_turn_time.bits)
X 			self->qos_rx.max_turn_time.bits &= qos_user->max_turn_time.bits;
-		if ( qos_user->data_size.bits)
+		if (qos_user->data_size.bits)
X 			self->qos_rx.data_size.bits &= qos_user->data_size.bits;
X 
-		if ( qos_user->link_disc_time.bits)
+		if (qos_user->link_disc_time.bits)
X 			self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits;
X #ifdef CONFIG_IRDA_COMPRESSION
X 		self->qos_rx.compression.bits &= qos_user->compression.bits;
@@ -984,7 +984,7 @@
X 	/* Set disconnect time */
X 	self->qos_rx.link_disc_time.bits &= 0x07;
X 
-	irda_qos_bits_to_value( &self->qos_rx);
+	irda_qos_bits_to_value(&self->qos_rx);
X }
X 
X /*
@@ -993,14 +993,14 @@
X  *    Use the default connection and transmission parameters
X  * 
X  */
-void irlap_apply_default_connection_parameters( struct irlap_cb *self)
+void irlap_apply_default_connection_parameters(struct irlap_cb *self)
X {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
-	irlap_change_speed( self, 9600);
+	irlap_change_speed(self, 9600);
X 
X 	/* Default value in NDM */
X 	self->bofs_count = 11;
@@ -1028,12 +1028,12 @@
X void irlap_apply_connection_parameters(struct irlap_cb *self, 
X 				       struct qos_info *qos) 
X {
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
X 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
X 
-	irlap_change_speed( self, qos->baud_rate.value);
+	irlap_change_speed(self, qos->baud_rate.value);
X 
X 	self->window_size = qos->window_size.value;
X 	self->window      = qos->window_size.value;
@@ -1045,7 +1045,7 @@
X 	 */
X 	self->window_bytes = qos->baud_rate.value 
X 		* qos->max_turn_time.value / 10000;
-	DEBUG( 4, "Setting window_bytes = %d\n", self->window_bytes);
+	DEBUG(4, "Setting window_bytes = %d\n", self->window_bytes);
X 
X 	/*
X 	 *  Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to 
@@ -1058,10 +1058,10 @@
X 	else
X 		self->N1 = 3000 / qos->max_turn_time.value;
X 	
-	DEBUG( 4, "Setting N1 = %d\n", self->N1);
+	DEBUG(4, "Setting N1 = %d\n", self->N1);
X 	
X 	self->N2 = qos->link_disc_time.value * 1000 / qos->max_turn_time.value;
-	DEBUG( 4, "Setting N2 = %d\n", self->N2);
+	DEBUG(4, "Setting N2 = %d\n", self->N2);
X 
X 	/* 
X 	 *  Initialize timeout values, some of the rules are listed on 
@@ -1072,11 +1072,11 @@
X 	self->wd_timeout = self->poll_timeout * 2;
X 
X #ifdef CONFIG_IRDA_COMPRESSION
-	if ( qos->compression.value) {
-		DEBUG( 1, __FUNCTION__ "(), Initializing compression\n");
-		irda_set_compression( self, qos->compression.value);
+	if (qos->compression.value) {
+		DEBUG(1, __FUNCTION__ "(), Initializing compression\n");
+		irda_set_compression(self, qos->compression.value);
X 
-		irlap_compressor_init( self, 0);
+		irlap_compressor_init(self, 0);
X 	}
X #endif
X }
@@ -1088,7 +1088,7 @@
X  *    Give some info to the /proc file system
X  *
X  */
-int irlap_proc_read( char *buf, char **start, off_t offset, int len, 
+int irlap_proc_read(char *buf, char **start, off_t offset, int len, 
X 		     int unused)
X {
X 	struct irlap_cb *self;
@@ -1100,81 +1100,81 @@
X 
X 	len = 0;
X 
-	self = (struct irlap_cb *) hashbin_get_first( irlap);
-	while ( self != NULL) {
-		ASSERT( self != NULL, return -ENODEV;);
-		ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+	self = (struct irlap_cb *) hashbin_get_first(irlap);
+	while (self != NULL) {
+		ASSERT(self != NULL, return -ENODEV;);
+		ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
X 
-		len += sprintf( buf+len, "irlap%d <-> %s ",
+		len += sprintf(buf+len, "irlap%d <-> %s ",
X 				i++, self->irdev->name);
-		len += sprintf( buf+len, "state: %s\n", 
+		len += sprintf(buf+len, "state: %s\n", 
X 				irlap_state[ self->state]);
X 		
-		len += sprintf( buf+len, "  caddr: %#02x, ", self->caddr);
-		len += sprintf( buf+len, "saddr: %#08x, ", self->saddr);
-		len += sprintf( buf+len, "daddr: %#08x\n", self->daddr);
+		len += sprintf(buf+len, "  caddr: %#02x, ", self->caddr);
+		len += sprintf(buf+len, "saddr: %#08x, ", self->saddr);
+		len += sprintf(buf+len, "daddr: %#08x\n", self->daddr);
X 		
-		len += sprintf( buf+len, "  win size: %d, ", 
+		len += sprintf(buf+len, "  win size: %d, ", 
X 				self->window_size);
-		len += sprintf( buf+len, "win: %d, ", self->window);
-		len += sprintf( buf+len, "win bytes: %d, ", self->window_bytes);
-		len += sprintf( buf+len, "bytes left: %d\n", self->bytes_left);
-
-		len += sprintf( buf+len, "  tx queue len: %d ", 
-				skb_queue_len( &self->tx_list));
-		len += sprintf( buf+len, "win queue len: %d ", 
-				skb_queue_len( &self->wx_list));
-		len += sprintf( buf+len, "rbusy: %s\n", self->remote_busy ? 
+		len += sprintf(buf+len, "win: %d, ", self->window);
+		len += sprintf(buf+len, "win bytes: %d, ", self->window_bytes);
+		len += sprintf(buf+len, "bytes left: %d\n", self->bytes_left);
+
+		len += sprintf(buf+len, "  tx queue len: %d ", 
+				skb_queue_len(&self->tx_list));
+		len += sprintf(buf+len, "win queue len: %d ", 
+				skb_queue_len(&self->wx_list));
+		len += sprintf(buf+len, "rbusy: %s\n", self->remote_busy ? 
X 				"TRUE" : "FALSE");
X 		
-		len += sprintf( buf+len, "  retrans: %d ", self->retry_count);
-		len += sprintf( buf+len, "vs: %d ", self->vs);
-		len += sprintf( buf+len, "vr: %d ", self->vr);
-		len += sprintf( buf+len, "va: %d\n", self->va);
+		len += sprintf(buf+len, "  retrans: %d ", self->retry_count);
+		len += sprintf(buf+len, "vs: %d ", self->vs);
+		len += sprintf(buf+len, "vr: %d ", self->vr);
+		len += sprintf(buf+len, "va: %d\n", self->va);
X 		
-		len += sprintf( buf+len, "  qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
+		len += sprintf(buf+len, "  qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
X 		
-		len += sprintf( buf+len, "  tx\t%d\t", 
+		len += sprintf(buf+len, "  tx\t%d\t", 
X 				self->qos_tx.baud_rate.value);
-		len += sprintf( buf+len, "%d\t", 
+		len += sprintf(buf+len, "%d\t", 
X 				self->qos_tx.max_turn_time.value);
-		len += sprintf( buf+len, "%d\t",
+		len += sprintf(buf+len, "%d\t",
X 				self->qos_tx.data_size.value);
-		len += sprintf( buf+len, "%d\t",
+		len += sprintf(buf+len, "%d\t",
X 				self->qos_tx.window_size.value);
-		len += sprintf( buf+len, "%d\t",
+		len += sprintf(buf+len, "%d\t",
X 				self->qos_tx.additional_bofs.value);
-		len += sprintf( buf+len, "%d\t", 
+		len += sprintf(buf+len, "%d\t", 
X 				self->qos_tx.min_turn_time.value);
-		len += sprintf( buf+len, "%d\t", 
+		len += sprintf(buf+len, "%d\t", 
X 				self->qos_tx.link_disc_time.value);
X #ifdef CONFIG_IRDA_COMPRESSION
-		len += sprintf( buf+len, "%d",
+		len += sprintf(buf+len, "%d",
X 				self->qos_tx.compression.value);
X #endif
-		len += sprintf( buf+len, "\n");
+		len += sprintf(buf+len, "\n");
X 
-		len += sprintf( buf+len, "  rx\t%d\t", 
+		len += sprintf(buf+len, "  rx\t%d\t", 
X 				self->qos_rx.baud_rate.value);
-		len += sprintf( buf+len, "%d\t", 
+		len += sprintf(buf+len, "%d\t", 
X 				self->qos_rx.max_turn_time.value);
-		len += sprintf( buf+len, "%d\t",
+		len += sprintf(buf+len, "%d\t",
X 				self->qos_rx.data_size.value);
-		len += sprintf( buf+len, "%d\t",
+		len += sprintf(buf+len, "%d\t",
X 				self->qos_rx.window_size.value);
-		len += sprintf( buf+len, "%d\t",
+		len += sprintf(buf+len, "%d\t",
X 				self->qos_rx.additional_bofs.value);
-		len += sprintf( buf+len, "%d\t", 
+		len += sprintf(buf+len, "%d\t", 
X 				self->qos_rx.min_turn_time.value);
-		len += sprintf( buf+len, "%d\t", 
+		len += sprintf(buf+len, "%d\t", 
X 				self->qos_rx.link_disc_time.value);
X #ifdef CONFIG_IRDA_COMPRESSION
-		len += sprintf( buf+len, "%d",
+		len += sprintf(buf+len, "%d",
X 				self->qos_rx.compression.value);
X #endif
-		len += sprintf( buf+len, "\n");
+		len += sprintf(buf+len, "\n");
X 		
-		self = (struct irlap_cb *) hashbin_get_next( irlap);
+		self = (struct irlap_cb *) hashbin_get_next(irlap);
X 	}
X 	restore_flags(flags);
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- v2.3.5/linux/net/irda/irlap_event.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlap_event.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Sun May  9 22:44:32 1999
+ * Modified at:   Mon May 31 21:55:42 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>,
@@ -209,8 +209,8 @@
X  *    Rushes through the state machine without any delay. If state == XMIT
X  *    then send queued data frames. 
X  */
-void irlap_do_event( struct irlap_cb *self, IRLAP_EVENT event, 
-		     struct sk_buff *skb, struct irlap_info *info) 
+void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, 
+		    struct sk_buff *skb, struct irlap_info *info) 
X {
X 	int ret;
X 	
@@ -218,7 +218,7 @@
X 		return;
X 	
X   	DEBUG(4, __FUNCTION__ "(), event = %s, state = %s\n", 
-	      irlap_event[ event], irlap_state[ self->state]); 
+	      irlap_event[event], irlap_state[self->state]); 
X 	
X 	ret = (*state[ self->state]) (self, event, skb, info);
X 	
@@ -236,13 +236,12 @@
X 		if (skb_queue_len(&self->tx_list)) {
X 			/* Try to send away all queued data frames */
X 			while ((skb = skb_dequeue(&self->tx_list)) != NULL) {
-				ret = (*state[ self->state])(self, SEND_I_CMD,
-							     skb, NULL);
+				ret = (*state[self->state])(self, SEND_I_CMD,
+							    skb, NULL);
X 				if ( ret == -EPROTO)
X 					break; /* Try again later! */
X 			}
X 		} else if (self->disconnect_pending) {
-			DEBUG(0, __FUNCTION__ "(), disconnecting!\n");
X 			self->disconnect_pending = FALSE;
X 			
X 			ret = (*state[self->state])(self, DISCONNECT_REQUEST,
@@ -761,36 +760,30 @@
X  *    stations.
X  * 
X  */
-static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event, 
-			       struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, 
+			      struct sk_buff *skb, struct irlap_info *info) 
X {
X 	int ret = 0;
X 	
-	ASSERT( self != NULL, return -ENODEV;);
-	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
-
-	DEBUG( 4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", 
-	       irlap_event[ event], self->vs, self->vr); 
+	DEBUG(4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", 
+	      irlap_event[event], self->vs, self->vr);
X 		
X 	switch (event) {
X 	case SEND_I_CMD:
-		ASSERT( skb != NULL, return -1;);
-		DEBUG( 4, __FUNCTION__ "(), Window=%d\n", self->window);
-		
X 		/*
X 		 *  Only send frame if send-window > 0.
X 		 */ 
-		if (( self->window > 0) && ( !self->remote_busy)) {
+		if ((self->window > 0) && (!self->remote_busy)) {
X 
X 			/*
X 			 *  Test if we have transmitted more bytes over the 
X 			 *  link than its possible to do with the current 
X 			 *  speed and turn-around-time.
X 			 */
-			if (( skb->len+self->bofs_count) > self->bytes_left) {
-				DEBUG( 4, __FUNCTION__ "(), Not allowed to "
-				       "transmit more bytes!\n");
-				skb_queue_head( &self->tx_list, skb);
+			if ((skb->len+self->bofs_count) > self->bytes_left) {
+				DEBUG(4, __FUNCTION__ "(), Not allowed to "
+				      "transmit more bytes!\n");
+				skb_queue_head(&self->tx_list, skb);
X 
X 				/*
X 				 *  We should switch state to LAP_NRM_P, but
@@ -802,7 +795,7 @@
X 				 */
X 				return -EPROTO;
X 			}
-			self->bytes_left -= ( skb->len + self->bofs_count);
+			self->bytes_left -= (skb->len + self->bofs_count);
X 
X 			/*
X 			 *  Send data with poll bit cleared only if window > 1
@@ -811,11 +804,9 @@
X 			if (( self->window > 1) && 
X 			    skb_queue_len( &self->tx_list) > 0) 
X 			{   
-				DEBUG( 4, __FUNCTION__ "(), window > 1\n");
X 				irlap_send_data_primary( self, skb);
X 				irlap_next_state( self, LAP_XMIT_P);
X 			} else {
-				DEBUG( 4, __FUNCTION__ "(), window <= 1\n");
X 				irlap_send_data_primary_poll( self, skb);
X 				irlap_next_state( self, LAP_NRM_P);
X 				
@@ -933,9 +924,6 @@
X 	int ns_status;
X 	int nr_status;
X 
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == LAP_MAGIC, return -1;);
-
X 	switch (event) {
X 	case RECV_I_RSP: /* Optimize for the common case */
X 		/* FIXME: must check for remote_busy below */
@@ -947,7 +935,6 @@
X 		 */
X 		self->fast_RR = FALSE;
X #endif
-
X 		ASSERT( info != NULL, return -1;);
X 
X 		ns_status = irlap_validate_ns_received(self, info->ns);
@@ -1141,13 +1128,6 @@
X 		}
X 		break;
X 	case RECV_RR_RSP:
-		DEBUG(4, __FUNCTION__ "(), RECV_RR_FRAME: "
-		      "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
-		      self->retry_count, info->nr, self->va, self->vs, 
-		      self->vr);
-
-		ASSERT(info != NULL, return -1;);
-
X 		/*  
X 		 *  If you get a RR, the remote isn't busy anymore, 
X 		 *  no matter what the NR 
@@ -1194,14 +1174,6 @@
X 			/* Resend rejected frames */
X 			irlap_resend_rejected_frames( self, CMD_FRAME);
X 			
-			/*
-			 *  Start only if not running, DB
-			 *  TODO: Should this one be here?
-			 */
-			/* if ( !self->final_timer.prev) */
-/* 				irda_start_timer( FINAL_TIMER, self->final_timeout);  */
-
-			/* Keep state */
X 			irlap_next_state( self, LAP_NRM_P);
X 		} else if (ret == NR_INVALID) {
X 			DEBUG(1, "irlap_state_nrm_p: received RR with "
@@ -1210,8 +1182,7 @@
X 
X 			irlap_next_state( self, LAP_RESET_WAIT);
X 
-			irlap_disconnect_indication( self, 
-						     LAP_RESET_INDICATION);
+			irlap_disconnect_indication(self, LAP_RESET_INDICATION);
X 			self->xmitflag = TRUE;
X 		}
X 		if (skb)
@@ -1479,13 +1450,13 @@
X 		/*
X 		 *  Send frame only if send window > 1
X 		 */ 
-		if (( self->window > 0) && ( !self->remote_busy)) {
+		if ((self->window > 0) && ( !self->remote_busy)) {
X 			/*
X 			 *  Test if we have transmitted more bytes over the 
X 			 *  link than its possible to do with the current 
X 			 *  speed and turn-around-time.
X 			 */
-			if (( skb->len+self->bofs_count) > self->bytes_left) {
+			if ((skb->len+self->bofs_count) > self->bytes_left) {
X 				DEBUG( 4, "IrDA: Not allowed to transmit more bytes!\n");
X 				skb_queue_head( &self->tx_list, skb);
X 				/*
@@ -1507,11 +1478,9 @@
X 			if (( self->window > 1) && 
X 			    skb_queue_len( &self->tx_list) > 0) 
X 			{   
-				DEBUG( 4, __FUNCTION__ "(), window > 1\n");
X 				irlap_send_data_secondary( self, skb);
X 				irlap_next_state( self, LAP_XMIT_S);
X 			} else {
-				DEBUG( 4, "(), window <= 1\n");
X 				irlap_send_data_secondary_final( self, skb);
X 				irlap_next_state( self, LAP_NRM_S);
X 
@@ -1635,8 +1604,7 @@
X 		/*
X 		 *  Check for Unexpected next to send (Ns)
X 		 */
-		if (( ns_status == NS_UNEXPECTED) && 
-		    ( nr_status == NR_EXPECTED)) 
+		if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
X 		{
X 			/* Unexpected next to send, with final bit cleared */
X 			if ( !info->pf) {
@@ -1659,8 +1627,7 @@
X 		/* 
X 		 *  Unexpected Next to Receive(NR) ?
X 		 */
-		if (( ns_status == NS_EXPECTED) && 
-		    ( nr_status == NR_UNEXPECTED))
+		if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
X 		{
X 			if ( info->pf) {
X 				DEBUG( 4, "RECV_I_RSP: frame(s) lost\n");
@@ -1756,20 +1723,20 @@
X 				irlap_update_nr_received( self, info->nr);
X 				del_timer( &self->wd_timer);
X 				
-				irlap_wait_min_turn_around( self, &self->qos_tx);
+				irlap_wait_min_turn_around(self, &self->qos_tx);
X 				irlap_next_state( self, LAP_XMIT_S);
X 			} else {			
X 				self->remote_busy = FALSE;
X 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
-				irlap_wait_min_turn_around( self, &self->qos_tx);
+				irlap_update_nr_received(self, info->nr);
+				irlap_wait_min_turn_around(self, &self->qos_tx);
X 				
-				irlap_send_rr_frame( self, RSP_FRAME);
+				irlap_send_rr_frame(self, RSP_FRAME);
X 				
-				irlap_start_wd_timer( self, self->wd_timeout);
-				irlap_next_state( self, LAP_NRM_S);
+				irlap_start_wd_timer(self, self->wd_timeout);
+				irlap_next_state(self, LAP_NRM_S);
X 			}
-		} else if ( nr_status == NR_UNEXPECTED) {
+		} else if (nr_status == NR_UNEXPECTED) {
X 			self->remote_busy = FALSE;
X 			irlap_update_nr_received( self, info->nr);
X 			irlap_resend_rejected_frames( self, RSP_FRAME);
@@ -1781,8 +1748,8 @@
X 		} else {
X 			DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
X 		} 
-		if ( skb)
-			dev_kfree_skb( skb);
+		if (skb)
+			dev_kfree_skb(skb);
X 
X 		break;
X 	case RECV_SNRM_CMD:
@@ -1894,7 +1861,7 @@
X 	ASSERT( self != NULL, return -ENODEV;);
X 	ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
X 	
-	switch( event) {
+	switch(event) {
X 	case RESET_RESPONSE:
X 		irlap_send_ua_response_frame( self, &self->qos_rx);
X 		irlap_initiate_connection_state( self);
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c
--- v2.3.5/linux/net/irda/irlap_frame.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlap_frame.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Sun May  9 22:55:11 1999
+ * Modified at:   Mon May 31 09:29:13 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>, All Rights Resrved.
@@ -1001,10 +1001,6 @@
X {
X 	__u8  *frame;
X 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-
X 	frame = skb->data;
X 	
X 	/* Insert connection address */
@@ -1014,15 +1010,6 @@
X 	/* Insert next to receive (Vr) */
X 	frame[1] |= (self->vr << 5);  /* insert nr */
X 
-#if 0
-	{
-		int ns;
-		ns = (frame[1] >> 1) & 0x07; /* Next to send */
-
-		DEBUG(0, __FUNCTION__ "(), ns=%d\n", ns);
-	}
-#endif
-
X 	irlap_queue_xmit(self, skb);
X }
X 
@@ -1240,7 +1227,7 @@
X 	 *  Optimize for the common case and check if the frame is an
X 	 *  I(nformation) frame. Only I-frames have bit 0 set to 0
X 	 */
-	if(~control & 0x01) {
+	if (~control & 0x01) {
X 		irlap_recv_i_frame(self, skb, &info, command);
X 		self->stats.rx_packets++;
X 		return 0;
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlmp.c linux/net/irda/irlmp.c
--- v2.3.5/linux/net/irda/irlmp.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlmp.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Stable.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Sun May  9 22:45:06 1999
+ * Modified at:   Mon May 31 21:49:41 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>, 
@@ -451,17 +451,16 @@
X 	ASSERT(skb != NULL, return;);
X 	ASSERT(self->lap != NULL, return;);
X 
-	DEBUG(0, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+	DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
X 	      self->slsap_sel, self->dlsap_sel);
X 
X 	self->qos = *self->lap->qos;
X 
-	lap_header_size = irlap_get_header_size(self->lap->irlap);
-
-	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
-		lap_header_size;
+	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
X 	DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
X 	
+	lap_header_size = irlap_get_header_size(self->lap->irlap);
+
X 	max_header_size = LMP_HEADER + lap_header_size;
X 
X 	DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", max_header_size);
@@ -519,11 +518,10 @@
X 	ASSERT(self->lap != NULL, return;);
X 	self->qos = *self->lap->qos;
X 
-	lap_header_size = irlap_get_header_size(self->lap->irlap);
-
-	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
-		lap_header_size;
+	max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
X 	DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
+
+	lap_header_size = irlap_get_header_size(self->lap->irlap);
X 	
X 	max_header_size = LMP_HEADER + lap_header_size;
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c
--- v2.3.5/linux/net/irda/irlmp_frame.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irlmp_frame.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Sun May  9 21:00:05 1999
+ * Modified at:   Mon May 31 09:53:16 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>
@@ -134,17 +134,17 @@
X 				       self->lsaps);
X 	
X 	if (lsap == NULL) {
-		DEBUG(0, "IrLMP, Sorry, no LSAP for received frame!\n");
-		DEBUG(0, __FUNCTION__ 
+		DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
+		DEBUG(2, __FUNCTION__ 
X 		      "(), slsap_sel = %02x, dlsap_sel = %02x\n", slsap_sel, 
X 		      dlsap_sel);
X 		if (fp[0] & CONTROL_BIT) {
-			DEBUG(0, __FUNCTION__ 
+			DEBUG(2, __FUNCTION__ 
X 			      "(), received control frame %02x\n", fp[2]);
X 		} else {
-			DEBUG(0, __FUNCTION__ "(), received data frame\n");
+			DEBUG(2, __FUNCTION__ "(), received data frame\n");
X 		}
-		dev_kfree_skb( skb);
+		dev_kfree_skb(skb);
X 		return;
X 	}
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/irmod.c linux/net/irda/irmod.c
--- v2.3.5/linux/net/irda/irmod.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irmod.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Mon May 10 15:28:49 1999
+ * Modified at:   Fri May 14 13:46:02 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
@@ -45,7 +45,7 @@
X #include <net/irda/wrapper.h>
X #include <net/irda/timer.h>
X 
-extern struct proc_dir_entry proc_irda;
+extern struct proc_dir_entry *proc_irda;
X 
X struct irda_cb irda; /* One global instance */
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/irttp.c linux/net/irda/irttp.c
--- v2.3.5/linux/net/irda/irttp.c	Mon May 31 22:28:07 1999
+++ linux/net/irda/irttp.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Mon May 10 17:12:53 1999
+ * Modified at:   Mon May 31 10:29:56 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * 
X  *     Copyright (c) 1998-1999 Dag Brattli <da...@cs.uit.no>, 
@@ -35,7 +35,7 @@
X #include <net/irda/irlmp.h>
X #include <net/irda/irttp.h>
X 
-struct irttp_cb *irttp = NULL;
+static struct irttp_cb *irttp = NULL;
X 
X static void __irttp_close_tsap(struct tsap_cb *self);
X 
@@ -44,8 +44,7 @@
X static int irttp_udata_indication(void *instance, void *sap, 
X 				  struct sk_buff *skb);
X static void irttp_disconnect_indication(void *instance, void *sap,  
-					LM_REASON reason,
-					struct sk_buff *);
+					LM_REASON reason, struct sk_buff *);
X static void irttp_connect_indication(void *instance, void *sap, 
X 				     struct qos_info *qos, __u32 max_sdu_size,
X 				     __u8 header_size, struct sk_buff *skb);
@@ -57,8 +56,8 @@
X 
X static void irttp_flush_queues(struct tsap_cb *self);
X static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
X static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
+static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
X 
X /*
X  * Function irttp_init (void)
@@ -298,7 +297,7 @@
X 
X 	/* Check that nothing bad happens */
X 	if ((skb->len == 0) || (!self->connected)) {
-		DEBUG(4, __FUNCTION__ "(), No data, or not connected\n");
+		ERROR(__FUNCTION__ "(), No data, or not connected\n");
X 		return -ENOTCONN;
X 	}
X 
@@ -307,8 +306,8 @@
X 	 *  inside an IrLAP frame
X 	 */
X 	if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
-		DEBUG(1, __FUNCTION__ 
-		       "(), SAR disabled, and data is to large for IrLAP!\n");
+		ERROR(__FUNCTION__ 
+		      "(), SAR disabled, and data is to large for IrLAP!\n");
X 		return -EMSGSIZE;
X 	}
X 
@@ -320,8 +319,8 @@
X 	    (self->tx_max_sdu_size != SAR_UNBOUND) && 
X 	    (skb->len > self->tx_max_sdu_size))
X 	{
-		DEBUG(1, __FUNCTION__ "(), SAR enabled, "
-		       "but data is larger than TxMaxSduSize!\n");
+		ERROR(__FUNCTION__ "(), SAR enabled, "
+		      "but data is larger than TxMaxSduSize!\n");
X 		return -EMSGSIZE;
X 	}
X 	/* 
@@ -343,7 +342,6 @@
X 		frame = skb_push(skb, TTP_HEADER);
X 		frame[0] = 0x00; /* Clear more bit */
X 		
-		DEBUG(4, __FUNCTION__ "(), queueing original skb\n");
X 		skb_queue_tail(&self->tx_queue, skb);
X 	} else {
X 		/*
@@ -384,12 +382,8 @@
X {
X 	struct sk_buff *skb = NULL;
X 	unsigned long flags;
-	__u8 *frame;
X 	int n;
X 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	
X 	if (irda_lock(&self->tx_queue_lock) == FALSE)
X 		return;
X 
@@ -424,12 +418,7 @@
X 		 *  More bit must be set by the data_request() or fragment() 
X 		 *  functions
X 		 */
-		frame = skb->data;
-
-		DEBUG(4, __FUNCTION__ "(), More=%s\n", frame[0] & 0x80 ? 
-		       "TRUE" : "FALSE" );
-
-		frame[0] |= (__u8) (n & 0x7f);
+		skb->data[0] |= (n & 0x7f);
X 		
X 		irlmp_data_request(self->lsap, skb);
X 		self->stats.tx_packets++;
@@ -437,12 +426,12 @@
X 		/* Check if we can accept more frames from client */
X 		if ((self->tx_sdu_busy) && 
X 		    (skb_queue_len(&self->tx_queue) < LOW_THRESHOLD)) 
-		{ 
+		{
X 			self->tx_sdu_busy = FALSE;
X 			
X 			if (self->notify.flow_indication)
X 				self->notify.flow_indication(
-					self->notify.instance, self, 
+					self->notify.instance, self,
X 					FLOW_START);
X 		}
X 	}
@@ -541,23 +530,14 @@
X 				 struct sk_buff *skb)
X {
X 	struct tsap_cb *self;
-	int more;
X 	int n;
-	__u8 *frame;
-	
+
X 	self = (struct tsap_cb *) instance;
X 
X 	ASSERT(self != NULL, return -1;);
X 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-	ASSERT(skb != NULL, return -1;);
X 
-	frame = skb->data;
-	
-	n = frame[0] & 0x7f;     /* Extract the credits */
-	more = frame[0] & 0x80;
-
- 	DEBUG(3, __FUNCTION__"(), got %d credits, TSAP sel=%02x\n", 
-	      n, self->stsap_sel);
+	n = skb->data[0] & 0x7f;     /* Extract the credits */
X 
X 	self->stats.rx_packets++;
X 
@@ -565,10 +545,9 @@
X 	 *  Data or dataless frame? Dataless frames only contain the 
X 	 *  TTP_HEADER
X 	 */
-	if (skb->len == 1) {
-		/* Dataless flowdata TTP-PDU */
-		self->send_credit += n;
-	} else {
+	if (skb->len == 1)
+		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
+	else {
X 		/* Deal with inbound credit */
X 		self->send_credit += n;
X 		self->remote_credit--;
@@ -768,6 +747,10 @@
X 	self->connected = TRUE;
X 
X 	parameters = frame[0] & 0x80;	
+
+	ASSERT(skb->len >= TTP_HEADER, return;);
+	skb_pull(skb, TTP_HEADER);
+		
X 	if (parameters) {
X 		plen = frame[1];
X 		pi   = frame[2];
@@ -793,13 +776,15 @@
X 
X 		DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", 
X 		      self->tx_max_sdu_size);
+		
+		/* Remove parameters */
+		ASSERT(skb->len >= (plen+1), return;);
+		skb_pull(skb, plen+1);
X 	}
X 	
X 	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
X 	      self->send_credit, self->avail_credit, self->remote_credit);
X 
-	skb_pull(skb, TTP_HEADER);
-
X 	if (self->notify.connect_confirm) {
X 		self->notify.connect_confirm(self->notify.instance, self, qos,
X 					     self->tx_max_sdu_size, 
@@ -814,7 +799,7 @@
X  *
X  */
X void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __u32 max_seg_size,  __u8 max_header_size, 
+			      __u32 max_seg_size, __u8 max_header_size, 
X 			      struct sk_buff *skb) 
X {
X 	struct tsap_cb *self;
@@ -847,7 +832,11 @@
X 	self->send_credit = n;
X 	self->tx_max_sdu_size = 0;
X 	
-	parameters = frame[0] & 0x80;	
+	parameters = frame[0] & 0x80;
+
+	ASSERT(skb->len >= TTP_HEADER, return;);
+	skb_pull(skb, TTP_HEADER);
+		
X 	if (parameters) {
X 		DEBUG(3, __FUNCTION__ "(), Contains parameters!\n");
X 		plen = frame[1];
@@ -871,7 +860,10 @@
X 			       "() illegal value length for max_sdu_size!\n");
X 			self->tx_max_sdu_size = 0;
X 		};
-
+		
+		/* Remove parameters */
+		ASSERT(skb->len >= (plen+1), return;);
+		skb_pull(skb, plen+1);
X 
X 		DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", 
X 		      self->tx_max_sdu_size);
@@ -879,8 +871,6 @@
X 
X 	DEBUG(4, __FUNCTION__ "(), initial send_credit=%d\n", n);
X 
-	skb_pull(skb, 1); /* Remove TTP header */
-
X 	if (self->notify.connect_indication) {
X 		self->notify.connect_indication(self->notify.instance, self, 
X 						qos, self->rx_max_sdu_size, 
@@ -1403,11 +1393,9 @@
X 	irttp_run_tx_queue(self);
X 
X 	/*  Give avay some credits to peer?  */
-	if ((skb_queue_empty(&self->tx_queue)) && 
-	    (self->remote_credit < LOW_THRESHOLD) && 
-	    (self->avail_credit > 0)) 
+	if ((self->remote_credit < LOW_THRESHOLD) && 
+	    (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
X 	{
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 25'
echo 'File patch-2.3.6 is continued in part 26'
echo 26 > _shar_seq_.tmp
#!/bin/sh
# this is part 26 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 26; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
-		DEBUG(4, __FUNCTION__ "(), sending credit!\n");
X 		irttp_give_credit(self);
X 	}
X 
diff -u --recursive --new-file v2.3.5/linux/net/irda/wrapper.c linux/net/irda/wrapper.c
--- v2.3.5/linux/net/irda/wrapper.c	Wed Jun  2 14:44:39 1999
+++ linux/net/irda/wrapper.c	Mon Jun  7 16:18:58 1999
@@ -6,7 +6,7 @@
X  * Status:        Experimental.
X  * Author:        Dag Brattli <da...@cs.uit.no>
X  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Sun May  2 21:58:00 1999
+ * Modified at:   Fri May 28 20:30:24 1999
X  * Modified by:   Dag Brattli <da...@cs.uit.no>
X  * Modified at:   Fri May 28  3:11 CST 1999
X  * Modified by:   Horst von Brand <vonb...@sleipnir.valparaiso.cl>
@@ -219,7 +219,7 @@
X /*
X  * Function state_begin_frame (idev, byte)
X  *
- *    
+ *    Begin of frame detected
X  *
X  */
X static void state_begin_frame(struct irda_device *idev, __u8 byte)
@@ -231,6 +231,10 @@
X 	case CE:
X 		/* Stuffed byte */
X 		idev->rx_buff.state = LINK_ESCAPE;
+
+		/* Time to initialize receive buffer */
+		idev->rx_buff.data = idev->rx_buff.head;
+		idev->rx_buff.len = 0;
X 		break;
X 	case EOF:
X 		/* Abort frame */
@@ -239,11 +243,11 @@
X 		idev->stats.rx_errors++;
X 		idev->stats.rx_frame_errors++;
X 		break;
-	default:
-		/* Got first byte of frame */
+	default:	
+		/* Time to initialize receive buffer */
X 		idev->rx_buff.data = idev->rx_buff.head;
X 		idev->rx_buff.len = 0;
-		
+
X 		idev->rx_buff.data[idev->rx_buff.len++] = byte;
X 		
X 		idev->rx_buff.fcs = irda_fcs(INIT_FCS, byte);
@@ -293,7 +297,7 @@
X /*
X  * Function state_inside_frame (idev, byte)
X  *
- *    
+ *    Handle bytes received within a frame
X  *
X  */
X static void state_inside_frame(struct irda_device *idev, __u8 byte)
diff -u --recursive --new-file v2.3.5/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c
--- v2.3.5/linux/net/netrom/nr_route.c	Mon May 31 22:28:07 1999
+++ linux/net/netrom/nr_route.c	Wed Jun  9 14:45:37 1999
@@ -564,13 +564,13 @@
X {
X 	struct device *dev, *first = NULL;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
X 			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
X 				first = dev;
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	return first;
X }
@@ -582,13 +582,13 @@
X {
X 	struct device *dev;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
X 			goto out;
X 	}
X out:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	return dev;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.5/linux/net/netsyms.c	Mon May 31 22:28:07 1999
+++ linux/net/netsyms.c	Wed Jun  9 14:45:37 1999
@@ -170,7 +170,6 @@
X 
X EXPORT_SYMBOL(neigh_table_init);
X EXPORT_SYMBOL(neigh_table_clear);
-EXPORT_SYMBOL(__neigh_lookup);
X EXPORT_SYMBOL(neigh_resolve_output);
X EXPORT_SYMBOL(neigh_connected_output);
X EXPORT_SYMBOL(neigh_update);
@@ -388,8 +387,7 @@
X EXPORT_SYMBOL(dev_set_allmulti);
X EXPORT_SYMBOL(dev_set_promiscuity);
X EXPORT_SYMBOL(sklist_remove_socket);
-EXPORT_SYMBOL(rtnl_wait);
-EXPORT_SYMBOL(rtnl_rlockct);
+EXPORT_SYMBOL(rtnl_sem);
X EXPORT_SYMBOL(rtnl_lock);
X EXPORT_SYMBOL(rtnl_unlock);
X 
diff -u --recursive --new-file v2.3.5/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.3.5/linux/net/packet/af_packet.c	Sun Mar 21 07:22:00 1999
+++ linux/net/packet/af_packet.c	Wed Jun  9 14:45:37 1999
@@ -5,7 +5,7 @@
X  *
X  *		PACKET - implements raw packet sockets.
X  *
- * Version:	$Id: af_packet.c,v 1.19 1999/03/21 05:23:03 davem Exp $
+ * Version:	$Id: af_packet.c,v 1.20 1999/06/09 10:11:32 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -286,26 +286,27 @@
X 	else
X 		return(-ENOTCONN);	/* SOCK_PACKET must be sent giving an address */
X 
+	dev_lock_list();
+
X 	/*
X 	 *	Find the device first to size check it 
X 	 */
X 
X 	saddr->spkt_device[13] = 0;
X 	dev = dev_get(saddr->spkt_device);
-	if (dev == NULL) 
-	{
-		return(-ENODEV);
-  	}
+	err = -ENODEV;
+	if (dev == NULL)
+		goto out_unlock;
X 	
X 	/*
X 	 *	You may not queue a frame bigger than the mtu. This is the lowest level
X 	 *	raw protocol and you must do your own fragmentation at this level.
X 	 */
X 	 
-	if(len>dev->mtu+dev->hard_header_len)
-  		return -EMSGSIZE;
+	err = -EMSGSIZE;
+ 	if(len>dev->mtu+dev->hard_header_len)
+		goto out_unlock;
X 
-	dev_lock_list();
X 	err = -ENOBUFS;
X 	skb = sock_wmalloc(sk, len+dev->hard_header_len+15, 0, GFP_KERNEL);
X 
@@ -351,8 +352,8 @@
X 	 *	Now send it
X 	 */
X 
-	dev_unlock_list();
X 	dev_queue_xmit(skb);
+	dev_unlock_list();
X 	return(len);
X 
X out_free:
@@ -455,16 +456,18 @@
X 		addr	= saddr->sll_addr;
X 	}
X 
+	dev_lock_list();
X 	dev = dev_get_by_index(ifindex);
+	err = -ENXIO;
X 	if (dev == NULL)
-		return -ENXIO;
+		goto out_unlock;
X 	if (sock->type == SOCK_RAW)
X 		reserve = dev->hard_header_len;
X 
+	err = -EMSGSIZE;
X 	if (len > dev->mtu+reserve)
-  		return -EMSGSIZE;
+		goto out_unlock;
X 
-	dev_lock_list();
X 
X 	skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 
X 				msg->msg_flags & MSG_DONTWAIT, &err);
@@ -501,8 +504,8 @@
X 	 *	Now send it
X 	 */
X 
-	dev_unlock_list();
X 	dev_queue_xmit(skb);
+	dev_unlock_list();
X 	return(len);
X 
X out_free:
diff -u --recursive --new-file v2.3.5/linux/net/rose/rose_route.c linux/net/rose/rose_route.c
--- v2.3.5/linux/net/rose/rose_route.c	Mon May 31 22:28:07 1999
+++ linux/net/rose/rose_route.c	Wed Jun  9 14:45:37 1999
@@ -543,13 +543,13 @@
X {
X 	struct device *dev, *first = NULL;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
X 			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
X 				first = dev;
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	return first;
X }
@@ -561,13 +561,13 @@
X {
X 	struct device *dev;
X 
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
X 			goto out;
X 	}
X out:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 	return dev;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/sched/cls_api.c linux/net/sched/cls_api.c
--- v2.3.5/linux/net/sched/cls_api.c	Thu Mar 25 09:23:34 1999
+++ linux/net/sched/cls_api.c	Wed Jun  9 14:45:37 1999
@@ -39,20 +39,24 @@
X 
X static struct tcf_proto_ops *tcf_proto_base;
X 
+/* Protects list of registered TC modules. It is pure SMP lock. */
+static rwlock_t cls_mod_lock = RW_LOCK_UNLOCKED;
X 
X /* Find classifier type by string name */
X 
X struct tcf_proto_ops * tcf_proto_lookup_ops(struct rtattr *kind)
X {
-	struct tcf_proto_ops *t;
+	struct tcf_proto_ops *t = NULL;
X 
X 	if (kind) {
+		read_lock(&cls_mod_lock);
X 		for (t = tcf_proto_base; t; t = t->next) {
X 			if (rtattr_strcmp(kind, t->kind) == 0)
-				return t;
+				break;
X 		}
+		read_unlock(&cls_mod_lock);
X 	}
-	return NULL;
+	return t;
X }
X 
X /* Register(unregister) new classifier type */
@@ -61,12 +65,17 @@
X {
X 	struct tcf_proto_ops *t, **tp;
X 
-	for (tp = &tcf_proto_base; (t=*tp) != NULL; tp = &t->next)
-		if (strcmp(ops->kind, t->kind) == 0)
+	write_lock(&cls_mod_lock);
+	for (tp = &tcf_proto_base; (t=*tp) != NULL; tp = &t->next) {
+		if (strcmp(ops->kind, t->kind) == 0) {
+			write_unlock(&cls_mod_lock);
X 			return -EEXIST;
+		}
+	}
X 
X 	ops->next = NULL;
X 	*tp = ops;
+	write_unlock(&cls_mod_lock);
X 	return 0;
X }
X 
@@ -74,13 +83,17 @@
X {
X 	struct tcf_proto_ops *t, **tp;
X 
+	write_lock(&cls_mod_lock);
X 	for (tp = &tcf_proto_base; (t=*tp) != NULL; tp = &t->next)
X 		if (t == ops)
X 			break;
X 
-	if (!t)
+	if (!t) {
+		write_unlock(&cls_mod_lock);
X 		return -ENOENT;
+	}
X 	*tp = t->next;
+	write_unlock(&cls_mod_lock);
X 	return 0;
X }
X 
@@ -217,8 +230,12 @@
X 			kfree(tp);
X 			goto errout;
X 		}
+		write_lock(&qdisc_tree_lock);
+		spin_lock_bh(&dev->queue_lock);
X 		tp->next = *back;
X 		*back = tp;
+		spin_unlock_bh(&dev->queue_lock);
+		write_unlock(&qdisc_tree_lock);
X 	} else if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], tp->ops->kind))
X 		goto errout;
X 
@@ -226,8 +243,11 @@
X 
X 	if (fh == 0) {
X 		if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
+			write_lock(&qdisc_tree_lock);
+			spin_lock_bh(&dev->queue_lock);
X 			*back = tp->next;
-			synchronize_bh();
+			spin_unlock_bh(&dev->queue_lock);
+			write_unlock(&qdisc_tree_lock);
X 
X 			tp->ops->destroy(tp);
X 			kfree(tp);
@@ -344,12 +364,16 @@
X 		return skb->len;
X 	if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
X 		return skb->len;
+
+	read_lock(&qdisc_tree_lock);
X 	if (!tcm->tcm_parent)
X 		q = dev->qdisc_sleeping;
X 	else
X 		q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
-	if (q == NULL)
+	if (q == NULL) {
+		read_unlock(&qdisc_tree_lock);
X 		return skb->len;
+	}
X 	if ((cops = q->ops->cl_ops) == NULL)
X 		goto errout;
X 	if (TC_H_MIN(tcm->tcm_parent)) {
@@ -400,6 +424,7 @@
X 	if (cl)
X 		cops->put(q, cl);
X 
+	read_unlock(&qdisc_tree_lock);
X 	return skb->len;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/sched/cls_fw.c linux/net/sched/cls_fw.c
--- v2.3.5/linux/net/sched/cls_fw.c	Thu Apr 22 19:45:20 1999
+++ linux/net/sched/cls_fw.c	Wed Jun  9 14:45:37 1999
@@ -136,7 +136,7 @@
X 			unsigned long cl;
X 			head->ht[h] = f->next;
X 
-			if ((cl = cls_set_class(&f->res.class, 0)) != 0)
+			if ((cl = __cls_set_class(&f->res.class, 0)) != 0)
X 				tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X #ifdef CONFIG_NET_CLS_POLICE
X 			tcf_police_release(f->police);
@@ -161,10 +161,11 @@
X 		if (*fp == f) {
X 			unsigned long cl;
X 
+			tcf_tree_lock(tp);
X 			*fp = f->next;
-			synchronize_bh();
+			tcf_tree_unlock(tp);
X 
-			if ((cl = cls_set_class(&f->res.class, 0)) != 0)
+			if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0)
X 				tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X #ifdef CONFIG_NET_CLS_POLICE
X 			tcf_police_release(f->police);
@@ -203,7 +204,7 @@
X 
X 			f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
X 			cl = tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid);
-			cl = cls_set_class(&f->res.class, cl);
+			cl = cls_set_class(tp, &f->res.class, cl);
X 			if (cl)
X 				tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X 		}
@@ -211,8 +212,9 @@
X 		if (tb[TCA_FW_POLICE-1]) {
X 			struct tcf_police *police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]);
X 
+			tcf_tree_lock(tp);
X 			police = xchg(&f->police, police);
-			synchronize_bh();
+			tcf_tree_unlock(tp);
X 
X 			tcf_police_release(police);
X 		}
@@ -229,8 +231,9 @@
X 			return -ENOBUFS;
X 		memset(head, 0, sizeof(*head));
X 
+		tcf_tree_lock(tp);
X 		tp->root = head;
-		synchronize_bh();
+		tcf_tree_unlock(tp);
X 	}
X 
X 	f = kmalloc(sizeof(struct fw_filter), GFP_KERNEL);
@@ -245,7 +248,7 @@
X 		if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != 4)
X 			goto errout;
X 		f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
-		cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
+		cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
X 	}
X 
X #ifdef CONFIG_NET_CLS_POLICE
@@ -254,8 +257,9 @@
X #endif
X 
X 	f->next = head->ht[fw_hash(handle)];
-	wmb();
+	tcf_tree_lock(tp);
X 	head->ht[fw_hash(handle)] = f;
+	tcf_tree_unlock(tp);
X 
X 	*arg = (unsigned long)f;
X 	return 0;
@@ -335,7 +339,8 @@
X 	rta->rta_len = skb->tail - b;
X #ifdef CONFIG_NET_CLS_POLICE
X 	if (f->police) {
-		RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &f->police->stats);
+		if (qdisc_copy_stats(skb, &f->police->stats))
+			goto rtattr_failure;
X 	}
X #endif
X 	return skb->len;
diff -u --recursive --new-file v2.3.5/linux/net/sched/cls_route.c linux/net/sched/cls_route.c
--- v2.3.5/linux/net/sched/cls_route.c	Thu Mar 25 09:23:34 1999
+++ linux/net/sched/cls_route.c	Wed Jun  9 14:45:37 1999
@@ -83,11 +83,11 @@
X 	return id&0xF;
X }
X 
-static void route4_reset_fastmap(struct route4_head *head, u32 id)
+static void route4_reset_fastmap(struct device *dev, struct route4_head *head, u32 id)
X {
-	start_bh_atomic();
+	spin_lock_bh(&dev->queue_lock);
X 	memset(head->fastmap, 0, sizeof(head->fastmap));
-	end_bh_atomic();
+	spin_unlock_bh(&dev->queue_lock);
X }
X 
X static void __inline__
@@ -297,7 +297,7 @@
X 					unsigned long cl;
X 
X 					b->ht[h2] = f->next;
-					if ((cl = cls_set_class(&f->res.class, 0)) != 0)
+					if ((cl = __cls_set_class(&f->res.class, 0)) != 0)
X 						tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X #ifdef CONFIG_NET_CLS_POLICE
X 					tcf_police_release(f->police);
@@ -329,12 +329,13 @@
X 		if (*fp == f) {
X 			unsigned long cl;
X 
+			tcf_tree_lock(tp);
X 			*fp = f->next;
-			synchronize_bh();
+			tcf_tree_unlock(tp);
X 
-			route4_reset_fastmap(head, f->id);
+			route4_reset_fastmap(tp->q->dev, head, f->id);
X 
-			if ((cl = cls_set_class(&f->res.class, 0)) != 0)
+			if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0)
X 				tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X 
X #ifdef CONFIG_NET_CLS_POLICE
@@ -349,8 +350,9 @@
X 					return 0;
X 
X 			/* OK, session has no flows */
+			tcf_tree_lock(tp);
X 			head->table[to_hash(h)] = NULL;
-			synchronize_bh();
+			tcf_tree_unlock(tp);
X 
X 			kfree(b);
X 			return 0;
@@ -387,7 +389,7 @@
X 			unsigned long cl;
X 
X 			f->res.classid = *(u32*)RTA_DATA(tb[TCA_ROUTE4_CLASSID-1]);
-			cl = cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
+			cl = cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
X 			if (cl)
X 				tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X 		}
@@ -395,8 +397,9 @@
X 		if (tb[TCA_ROUTE4_POLICE-1]) {
X 			struct tcf_police *police = tcf_police_locate(tb[TCA_ROUTE4_POLICE-1], tca[TCA_RATE-1]);
X 
+			tcf_tree_lock(tp);
X 			police = xchg(&f->police, police);
-			synchronize_bh();
+			tcf_tree_unlock(tp);
X 
X 			tcf_police_release(police);
X 		}
@@ -412,8 +415,9 @@
X 			return -ENOBUFS;
X 		memset(head, 0, sizeof(struct route4_head));
X 
+		tcf_tree_lock(tp);
X 		tp->root = head;
-		synchronize_bh();
+		tcf_tree_unlock(tp);
X 	}
X 
X 	f = kmalloc(sizeof(struct route4_filter), GFP_KERNEL);
@@ -475,8 +479,9 @@
X 			goto errout;
X 		memset(b, 0, sizeof(*b));
X 
+		tcf_tree_lock(tp);
X 		head->table[h1] = b;
-		synchronize_bh();
+		tcf_tree_unlock(tp);
X 	}
X 	f->bkt = b;
X 
@@ -489,17 +494,18 @@
X 			goto errout;
X 	}
X 
-	cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
+	cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
X #ifdef CONFIG_NET_CLS_POLICE
X 	if (tb[TCA_ROUTE4_POLICE-1])
X 		f->police = tcf_police_locate(tb[TCA_ROUTE4_POLICE-1], tca[TCA_RATE-1]);
X #endif
X 
X 	f->next = f1;
-	wmb();
+	tcf_tree_lock(tp);
X 	*ins_f = f;
+	tcf_tree_unlock(tp);
X 
-	route4_reset_fastmap(head, f->id);
+	route4_reset_fastmap(tp->q->dev, head, f->id);
X 	*arg = (unsigned long)f;
X 	return 0;
X 
@@ -589,7 +595,8 @@
X 	rta->rta_len = skb->tail - b;
X #ifdef CONFIG_NET_CLS_POLICE
X 	if (f->police) {
-		RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &f->police->stats);
+		if (qdisc_copy_stats(skb, &f->police->stats))
+			goto rtattr_failure;
X 	}
X #endif
X 	return skb->len;
diff -u --recursive --new-file v2.3.5/linux/net/sched/cls_rsvp.h linux/net/sched/cls_rsvp.h
--- v2.3.5/linux/net/sched/cls_rsvp.h	Thu Apr 22 19:45:20 1999
+++ linux/net/sched/cls_rsvp.h	Wed Jun  9 14:45:37 1999
@@ -282,7 +282,7 @@
X 					unsigned long cl;
X 
X 					s->ht[h2] = f->next;
-					if ((cl = cls_set_class(&f->res.class, 0)) != 0)
+					if ((cl = __cls_set_class(&f->res.class, 0)) != 0)
X 						tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X #ifdef CONFIG_NET_CLS_POLICE
X 					tcf_police_release(f->police);
@@ -310,10 +310,11 @@
X 			unsigned long cl;
X 
X 
+			tcf_tree_lock(tp);
X 			*fp = f->next;
-			synchronize_bh();
+			tcf_tree_unlock(tp);
X 
-			if ((cl = cls_set_class(&f->res.class, 0)) != 0)
+			if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0)
X 				tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X 
X #ifdef CONFIG_NET_CLS_POLICE
@@ -332,8 +333,9 @@
X 			for (sp = &((struct rsvp_head*)tp->root)->ht[h&0xFF];
X 			     *sp; sp = &(*sp)->next) {
X 				if (*sp == s) {
+					tcf_tree_lock(tp);
X 					*sp = s->next;
-					synchronize_bh();
+					tcf_tree_unlock(tp);
X 
X 					kfree(s);
X 					return 0;
@@ -446,7 +448,7 @@
X 			unsigned long cl;
X 
X 			f->res.classid = *(u32*)RTA_DATA(tb[TCA_RSVP_CLASSID-1]);
-			cl = cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
+			cl = cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
X 			if (cl)
X 				tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X 		}
@@ -454,8 +456,9 @@
X 		if (tb[TCA_RSVP_POLICE-1]) {
X 			struct tcf_police *police = tcf_police_locate(tb[TCA_RSVP_POLICE-1], tca[TCA_RATE-1]);
X 
+			tcf_tree_lock(tp);
X 			police = xchg(&f->police, police);
-			synchronize_bh();
+			tcf_tree_unlock(tp);
X 
X 			tcf_police_release(police);
X 		}
@@ -536,7 +539,7 @@
X 
X 			f->sess = s;
X 			if (f->tunnelhdr == 0)
-				cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
+				cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
X #ifdef CONFIG_NET_CLS_POLICE
X 			if (tb[TCA_RSVP_POLICE-1])
X 				f->police = tcf_police_locate(tb[TCA_RSVP_POLICE-1], tca[TCA_RATE-1]);
@@ -659,7 +662,8 @@
X 	rta->rta_len = skb->tail - b;
X #ifdef CONFIG_NET_CLS_POLICE
X 	if (f->police) {
-		RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &f->police->stats);
+		if (qdisc_copy_stats(skb, &f->police->stats))
+			goto rtattr_failure;
X 	}
X #endif
X 	return skb->len;
diff -u --recursive --new-file v2.3.5/linux/net/sched/cls_u32.c linux/net/sched/cls_u32.c
--- v2.3.5/linux/net/sched/cls_u32.c	Thu Mar 25 09:23:34 1999
+++ linux/net/sched/cls_u32.c	Wed Jun  9 14:45:37 1999
@@ -307,7 +307,7 @@
X {
X 	unsigned long cl;
X 
-	if ((cl = cls_set_class(&n->res.class, 0)) != 0)
+	if ((cl = __cls_set_class(&n->res.class, 0)) != 0)
X 		tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
X #ifdef CONFIG_NET_CLS_POLICE
X 	tcf_police_release(n->police);
@@ -326,8 +326,9 @@
X 	if (ht) {
X 		for (kp = &ht->ht[TC_U32_HASH(key->handle)]; *kp; kp = &(*kp)->next) {
X 			if (*kp == key) {
+				tcf_tree_lock(tp);
X 				*kp = key->next;
-				synchronize_bh();
+				tcf_tree_unlock(tp);
X 
X 				u32_destroy_key(tp, key);
X 				return 0;
@@ -346,7 +347,6 @@
X 	for (h=0; h<=ht->divisor; h++) {
X 		while ((n = ht->ht[h]) != NULL) {
X 			ht->ht[h] = n->next;
-			synchronize_bh();
X 
X 			u32_destroy_key(tp, n);
X 		}
@@ -465,8 +465,9 @@
X 			ht_down->refcnt++;
X 		}
X 
+		sch_tree_lock(q);
X 		ht_down = xchg(&n->ht_down, ht_down);
-		synchronize_bh();
+		sch_tree_unlock(q);
X 
X 		if (ht_down)
X 			ht_down->refcnt--;
@@ -475,7 +476,9 @@
X 		unsigned long cl;
X 
X 		n->res.classid = *(u32*)RTA_DATA(tb[TCA_U32_CLASSID-1]);
-		cl = cls_set_class(&n->res.class, q->ops->cl_ops->bind_tcf(q, base, n->res.classid));
+		sch_tree_lock(q);
+		cl = __cls_set_class(&n->res.class, q->ops->cl_ops->bind_tcf(q, base, n->res.classid));
+		sch_tree_unlock(q);
X 		if (cl)
X 			q->ops->cl_ops->unbind_tcf(q, cl);
X 	}
@@ -483,8 +486,9 @@
X 	if (tb[TCA_U32_POLICE-1]) {
X 		struct tcf_police *police = tcf_police_locate(tb[TCA_U32_POLICE-1], est);
X 
+		sch_tree_lock(q);
X 		police = xchg(&n->police, police);
-		synchronize_bh();
+		sch_tree_lock(q);
X 
X 		tcf_police_release(police);
X 	}
@@ -682,7 +686,8 @@
X 	rta->rta_len = skb->tail - b;
X #ifdef CONFIG_NET_CLS_POLICE
X 	if (TC_U32_KEY(n->handle) && n->police) {
-		RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &n->police->stats);
+		if (qdisc_copy_stats(skb, &n->police->stats))
+			goto rtattr_failure;
X 	}
X #endif
X 	return skb->len;
diff -u --recursive --new-file v2.3.5/linux/net/sched/estimator.c linux/net/sched/estimator.c
--- v2.3.5/linux/net/sched/estimator.c	Thu Mar 25 09:23:34 1999
+++ linux/net/sched/estimator.c	Wed Jun  9 14:45:37 1999
@@ -97,29 +97,38 @@
X 
X static struct qdisc_estimator_head elist[EST_MAX_INTERVAL+1];
X 
+/* Estimator array lock */
+static rwlock_t est_lock = RW_LOCK_UNLOCKED;
+
X static void est_timer(unsigned long arg)
X {
X 	int idx = (int)arg;
X 	struct qdisc_estimator *e;
X 
+	read_lock(&est_lock);
X 	for (e = elist[idx].list; e; e = e->next) {
-		u64 nbytes = e->stats->bytes;
-		u32 npackets = e->stats->packets;
+		struct tc_stats *st = e->stats;
+		u64 nbytes;
+		u32 npackets;
X 		u32 rate;
-		
+
+		spin_lock(st->lock);
+		nbytes = st->bytes;
+		npackets = st->packets;
X 		rate = (nbytes - e->last_bytes)<<(7 - idx);
X 		e->last_bytes = nbytes;
X 		e->avbps += ((long)rate - (long)e->avbps) >> e->ewma_log;
-		e->stats->bps = (e->avbps+0xF)>>5;
+		st->bps = (e->avbps+0xF)>>5;
X 
X 		rate = (npackets - e->last_packets)<<(12 - idx);
X 		e->last_packets = npackets;
X 		e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
X 		e->stats->pps = (e->avpps+0x1FF)>>10;
+		spin_unlock(st->lock);
X 	}
X 
-	elist[idx].timer.expires = jiffies + ((HZ/4)<<idx);
-	add_timer(&elist[idx].timer);
+	mod_timer(&elist[idx].timer, jiffies + ((HZ/4)<<idx));
+	read_unlock(&est_lock);
X }
X 
X int qdisc_new_estimator(struct tc_stats *stats, struct rtattr *opt)
@@ -154,7 +163,9 @@
X 		elist[est->interval].timer.function = est_timer;
X 		add_timer(&elist[est->interval].timer);
X 	}
+	write_lock_bh(&est_lock);
X 	elist[est->interval].list = est;
+	write_unlock_bh(&est_lock);
X 	return 0;
X }
X 
@@ -172,8 +183,9 @@
X 				continue;
X 			}
X 
+			write_lock_bh(&est_lock);
X 			*pest = est->next;
-			synchronize_bh();
+			write_unlock_bh(&est_lock);
X 
X 			kfree(est);
X 			killed++;
diff -u --recursive --new-file v2.3.5/linux/net/sched/police.c linux/net/sched/police.c
--- v2.3.5/linux/net/sched/police.c	Sun Mar 21 07:22:00 1999
+++ linux/net/sched/police.c	Wed Jun  9 14:45:37 1999
@@ -38,6 +38,10 @@
X 
X static u32 idx_gen;
X static struct tcf_police *tcf_police_ht[16];
+/* Policer hash table lock */
+static rwlock_t police_lock = RW_LOCK_UNLOCKED;
+
+/* Each policer is serialized by its individual spinlock */
X 
X static __inline__ unsigned tcf_police_hash(u32 index)
X {
@@ -48,11 +52,13 @@
X {
X 	struct tcf_police *p;
X 
+	read_lock(&police_lock);
X 	for (p = tcf_police_ht[tcf_police_hash(index)]; p; p = p->next) {
X 		if (p->index == index)
-			return p;
+			break;
X 	}
-	return NULL;
+	read_unlock(&police_lock);
+	return p;
X }
X 
X static __inline__ u32 tcf_police_new_index(void)
@@ -73,7 +79,9 @@
X 	
X 	for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->next) {
X 		if (*p1p == p) {
+			write_lock_bh(&police_lock);
X 			*p1p = p->next;
+			write_unlock_bh(&police_lock);
X #ifdef CONFIG_NET_ESTIMATOR
X 			qdisc_kill_estimator(&p->stats);
X #endif
@@ -114,6 +122,8 @@
X 
X 	memset(p, 0, sizeof(*p));
X 	p->refcnt = 1;
+	spin_lock_init(&p->lock);
+	p->stats.lock = &p->lock;
X 	if (parm->rate.rate) {
X 		if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL)
X 			goto failure;
@@ -144,8 +154,10 @@
X 		qdisc_new_estimator(&p->stats, est);
X #endif
X 	h = tcf_police_hash(p->index);
+	write_lock_bh(&police_lock);
X 	p->next = tcf_police_ht[h];
X 	tcf_police_ht[h] = p;
+	write_unlock_bh(&police_lock);
X 	return p;
X 
X failure:
@@ -161,19 +173,24 @@
X 	long toks;
X 	long ptoks = 0;
X 
+	spin_lock(&p->lock);
+
X 	p->stats.bytes += skb->len;
X 	p->stats.packets++;
X 
X #ifdef CONFIG_NET_ESTIMATOR
X 	if (p->ewma_rate && p->stats.bps >= p->ewma_rate) {
X 		p->stats.overlimits++;
+		spin_unlock(&p->lock);
X 		return p->action;
X 	}
X #endif
X 
X 	if (skb->len <= p->mtu) {
-		if (p->R_tab == NULL)
+		if (p->R_tab == NULL) {
+			spin_unlock(&p->lock);
X 			return p->result;
+		}
X 
X 		PSCHED_GET_TIME(now);
X 
@@ -194,11 +211,13 @@
X 			p->t_c = now;
X 			p->toks = toks;
X 			p->ptoks = ptoks;
+			spin_unlock(&p->lock);
X 			return p->result;
X 		}
X 	}
X 
X 	p->stats.overlimits++;
+	spin_unlock(&p->lock);
X 	return p->action;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_api.c linux/net/sched/sch_api.c
--- v2.3.5/linux/net/sched/sch_api.c	Mon May 31 22:28:07 1999
+++ linux/net/sched/sch_api.c	Wed Jun  9 14:45:37 1999
@@ -124,6 +124,10 @@
X    changes qdisc parameters.
X  */
X 
+/* Protects list of registered TC modules. It is pure SMP lock. */
+static rwlock_t qdisc_mod_lock = RW_LOCK_UNLOCKED;
+
+
X /************************************************
X  *	Queueing disciplines manipulation.	*
X  ************************************************/
@@ -139,9 +143,13 @@
X {
X 	struct Qdisc_ops *q, **qp;
X 
-	for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next)
-		if (strcmp(qops->id, q->id) == 0)
+	write_lock(&qdisc_mod_lock);
+	for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next) {
+		if (strcmp(qops->id, q->id) == 0) {
+			write_unlock(&qdisc_mod_lock);
X 			return -EEXIST;
+		}
+	}
X 
X 	if (qops->enqueue == NULL)
X 		qops->enqueue = noop_qdisc_ops.enqueue;
@@ -152,20 +160,26 @@
X 
X 	qops->next = NULL;
X 	*qp = qops;
+	write_unlock(&qdisc_mod_lock);
X 	return 0;
X }
X 
X int unregister_qdisc(struct Qdisc_ops *qops)
X {
X 	struct Qdisc_ops *q, **qp;
+	int err = -ENOENT;
+
+	write_lock(&qdisc_mod_lock);
X 	for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next)
X 		if (q == qops)
X 			break;
-	if (!q)
-		return -ENOENT;
-	*qp = q->next;
-	q->next = NULL;
-	return 0;
+	if (q) {
+		*qp = q->next;
+		q->next = NULL;
+		err = 0;
+	}
+ write_unlock(&qdisc_mod_lock);
+	return err;
X }
X 
X /* We know handle. Find qdisc among all qdisc's attached to device
@@ -203,15 +217,17 @@
X 
X struct Qdisc_ops *qdisc_lookup_ops(struct rtattr *kind)
X {
-	struct Qdisc_ops *q;
+	struct Qdisc_ops *q = NULL;
X 
X 	if (kind) {
+		read_lock(&qdisc_mod_lock);
X 		for (q = qdisc_base; q; q = q->next) {
X 			if (rtattr_strcmp(kind, q->id) == 0)
-				return q;
+				break;
X 		}
+		read_unlock(&qdisc_mod_lock);
X 	}
-	return NULL;
+	return q;
X }
X 
X static struct qdisc_rate_table *qdisc_rtab_list;
@@ -284,7 +300,8 @@
X 	if (dev->flags & IFF_UP)
X 		dev_deactivate(dev);
X 
-	start_bh_atomic();
+	write_lock(&qdisc_tree_lock);
+	spin_lock_bh(&dev->queue_lock);
X 	oqdisc = dev->qdisc_sleeping;
X 
X 	/* Prune old scheduler */
@@ -296,7 +313,8 @@
X 		qdisc = &noop_qdisc;
X 	dev->qdisc_sleeping = qdisc;
X 	dev->qdisc = &noop_qdisc;
-	end_bh_atomic();
+	spin_unlock_bh(&dev->queue_lock);
+	write_unlock(&qdisc_tree_lock);
X 
X 	if (dev->flags & IFF_UP)
X 		dev_activate(dev);
@@ -376,7 +394,7 @@
X 		goto err_out;
X 
X 	/* Grrr... Resolve race condition with module unload */
-	
+
X 	err = -EINVAL;
X 	if (ops != qdisc_lookup_ops(kind))
X 		goto err_out;
@@ -389,6 +407,7 @@
X 	sch->dequeue = ops->dequeue;
X 	sch->dev = dev;
X 	atomic_set(&sch->refcnt, 1);
+	sch->stats.lock = &dev->queue_lock;
X 	if (handle == 0) {
X 		handle = qdisc_alloc_handle(dev);
X 		err = -ENOMEM;
@@ -398,8 +417,10 @@
X 	sch->handle = handle;
X 
X 	if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) {
+		write_lock(&qdisc_tree_lock);
X 		sch->next = dev->qdisc_list;
X 		dev->qdisc_list = sch;
+		write_unlock(&qdisc_tree_lock);
X #ifdef CONFIG_NET_ESTIMATOR
X 		if (tca[TCA_RATE-1])
X 			qdisc_new_estimator(&sch->stats, tca[TCA_RATE-1]);
@@ -521,7 +542,9 @@
X 			return err;
X 		if (q) {
X 			qdisc_notify(skb, n, clid, q, NULL);
+			spin_lock_bh(&dev->queue_lock);
X 			qdisc_destroy(q);
+			spin_unlock_bh(&dev->queue_lock);
X 		}
X 	} else {
X 		qdisc_notify(skb, n, clid, NULL, q);
@@ -637,17 +660,36 @@
X 		struct Qdisc *old_q = NULL;
X 		err = qdisc_graft(dev, p, clid, q, &old_q);
X 		if (err) {
-			if (q)
+			if (q) {
+				spin_lock_bh(&dev->queue_lock);
X 				qdisc_destroy(q);
+				spin_unlock_bh(&dev->queue_lock);
+			}
X 			return err;
X 		}
X 		qdisc_notify(skb, n, clid, old_q, q);
-		if (old_q)
+		if (old_q) {
+			spin_lock_bh(&dev->queue_lock);
X 			qdisc_destroy(old_q);
+			spin_unlock_bh(&dev->queue_lock);
+		}
X 	}
X 	return 0;
X }
X 
+int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st)
+{
+	spin_lock_bh(st->lock);
+	RTA_PUT(skb, TCA_STATS, (char*)&st->lock - (char*)st, st);
+	spin_unlock_bh(st->lock);
+	return 0;
+
+rtattr_failure:
+	spin_unlock_bh(st->lock);
+	return -1;
+}
+
+
X static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
X 			 u32 pid, u32 seq, unsigned flags, int event)
X {
@@ -667,7 +709,8 @@
X 	if (q->ops->dump && q->ops->dump(q, skb) < 0)
X 		goto rtattr_failure;
X 	q->stats.qlen = q->q.qlen;
-	RTA_PUT(skb, TCA_STATS, sizeof(q->stats), &q->stats);
+	if (qdisc_copy_stats(skb, &q->stats))
+		goto rtattr_failure;
X 	nlh->nlmsg_len = skb->tail - b;
X 	return skb->len;
X 
@@ -713,24 +756,28 @@
X 
X 	s_idx = cb->args[0];
X 	s_q_idx = q_idx = cb->args[1];
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
X 		if (idx < s_idx)
X 			continue;
X 		if (idx > s_idx)
X 			s_q_idx = 0;
+		read_lock(&qdisc_tree_lock);
X 		for (q = dev->qdisc_list, q_idx = 0; q;
X 		     q = q->next, q_idx++) {
X 			if (q_idx < s_q_idx)
X 				continue;
X 			if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid,
-					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
+					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
+				read_unlock(&qdisc_tree_lock);
X 				goto done;
+			}
X 		}
+		read_unlock(&qdisc_tree_lock);
X 	}
X 
X done:
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	cb->args[0] = idx;
X 	cb->args[1] = q_idx;
@@ -936,6 +983,7 @@
X 
X 	s_t = cb->args[0];
X 
+	read_lock(&qdisc_tree_lock);
X 	for (q=dev->qdisc_list, t=0; q; q = q->next, t++) {
X 		if (t < s_t) continue;
X 		if (!q->ops->cl_ops) continue;
@@ -954,6 +1002,7 @@
X 		if (arg.w.stop)
X 			break;
X 	}
+	read_unlock(&qdisc_tree_lock);
X 
X 	cb->args[0] = t;
X 
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- v2.3.5/linux/net/sched/sch_cbq.c	Sat Apr 24 17:51:48 1999
+++ linux/net/sched/sch_cbq.c	Wed Jun  9 14:45:37 1999
@@ -1417,6 +1417,7 @@
X 	q->link.ewma_log = TC_CBQ_DEF_EWMA;
X 	q->link.avpkt = q->link.allot/2;
X 	q->link.minidle = -0x7FFFFFFF;
+	q->link.stats.lock = &sch->dev->queue_lock;
X 
X 	init_timer(&q->wd_timer);
X 	q->wd_timer.data = (unsigned long)sch;
@@ -1558,6 +1559,16 @@
X 	return 0;
X }
X 
+int cbq_copy_xstats(struct sk_buff *skb, struct tc_cbq_xstats *st)
+{
+	RTA_PUT(skb, TCA_STATS, sizeof(*st), st);
+	return 0;
+
+rtattr_failure:
+	return -1;
+}
+
+
X static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
X {
X 	struct cbq_sched_data *q = (struct cbq_sched_data*)sch->data;
@@ -1569,8 +1580,13 @@
X 	if (cbq_dump_attr(skb, &q->link) < 0)
X 		goto rtattr_failure;
X 	rta->rta_len = skb->tail - b;
+	spin_lock_bh(&sch->dev->queue_lock);
X 	q->link.xstats.avgidle = q->link.avgidle;
-	RTA_PUT(skb, TCA_XSTATS, sizeof(q->link.xstats), &q->link.xstats);
+	if (cbq_copy_xstats(skb, &q->link.xstats)) {
+		spin_unlock_bh(&sch->dev->queue_lock);
+		goto rtattr_failure;
+	}
+	spin_unlock_bh(&sch->dev->queue_lock);
X 	return skb->len;
X 
X rtattr_failure:
@@ -1600,12 +1616,19 @@
X 		goto rtattr_failure;
X 	rta->rta_len = skb->tail - b;
X 	cl->stats.qlen = cl->q->q.qlen;
-	RTA_PUT(skb, TCA_STATS, sizeof(cl->stats), &cl->stats);
+	if (qdisc_copy_stats(skb, &cl->stats))
+		goto rtattr_failure;
+	spin_lock_bh(&sch->dev->queue_lock);
X 	cl->xstats.avgidle = cl->avgidle;
X 	cl->xstats.undertime = 0;
X 	if (!PSCHED_IS_PASTPERFECT(cl->undertime))
X 		cl->xstats.undertime = PSCHED_TDIFF(cl->undertime, q->now);
-	RTA_PUT(skb, TCA_XSTATS, sizeof(cl->xstats), &cl->xstats);
+	q->link.xstats.avgidle = q->link.avgidle;
+	if (cbq_copy_xstats(skb, &cl->xstats)) {
+		spin_unlock_bh(&sch->dev->queue_lock);
+		goto rtattr_failure;
+	}
+	spin_unlock_bh(&sch->dev->queue_lock);
X 
X 	return skb->len;
X 
@@ -1631,8 +1654,11 @@
X 				new->reshape_fail = cbq_reshape_fail;
X #endif
X 		}
-		if ((*old = xchg(&cl->q, new)) != NULL)
-			qdisc_reset(*old);
+		sch_tree_lock(sch);
+		*old = cl->q;
+		cl->q = new;
+		qdisc_reset(*old);
+		sch_tree_unlock(sch);
X 
X 		return 0;
X 	}
@@ -1710,16 +1736,16 @@
X 	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;
X 	struct cbq_class *cl = (struct cbq_class*)arg;
X 
-	start_bh_atomic();
X 	if (--cl->refcnt == 0) {
X #ifdef CONFIG_NET_CLS_POLICE
+		spin_lock_bh(&sch->dev->queue_lock);
X 		if (q->rx_class == cl)
X 			q->rx_class = NULL;
+		spin_unlock_bh(&sch->dev->queue_lock);
X #endif
+
X 		cbq_destroy_class(cl);
X 	}
-	end_bh_atomic();
-	return;
X }
X 
X static int
@@ -1780,7 +1806,7 @@
X 		}
X 
X 		/* Change class parameters */
-		start_bh_atomic();
+		sch_tree_lock(sch);
X 
X 		if (cl->next_alive != NULL)
X 			cbq_deactivate_class(cl);
@@ -1812,7 +1838,7 @@
X 		if (cl->q->q.qlen)
X 			cbq_activate_class(cl);
X 
-		end_bh_atomic();
+		sch_tree_lock(sch);
X 
X #ifdef CONFIG_NET_ESTIMATOR
X 		if (tca[TCA_RATE-1]) {
@@ -1878,8 +1904,9 @@
X 	cl->allot = parent->allot;
X 	cl->quantum = cl->allot;
X 	cl->weight = cl->R_tab->rate.rate;
+	cl->stats.lock = &sch->dev->queue_lock;
X 
-	start_bh_atomic();
+	sch_tree_lock(sch);
X 	cbq_link_class(cl);
X 	cl->borrow = cl->tparent;
X 	if (cl->tparent != &q->link)
@@ -1903,7 +1930,7 @@
X #endif
X 	if (tb[TCA_CBQ_FOPT-1])
X 		cbq_set_fopt(cl, RTA_DATA(tb[TCA_CBQ_FOPT-1]));
-	end_bh_atomic();
+	sch_tree_unlock(sch);
X 
X #ifdef CONFIG_NET_ESTIMATOR
X 	if (tca[TCA_RATE-1])
@@ -1926,7 +1953,7 @@
X 	if (cl->filters || cl->children || cl == &q->link)
X 		return -EBUSY;
X 
-	start_bh_atomic();
+	sch_tree_lock(sch);
X 
X 	if (cl->next_alive)
X 		cbq_deactivate_class(cl);
@@ -1948,11 +1975,10 @@
X 	cbq_sync_defmap(cl);
X 
X 	cbq_rmprio(q, cl);
+	sch_tree_unlock(sch);
X 
X 	if (--cl->refcnt == 0)
X 		cbq_destroy_class(cl);
-
-	end_bh_atomic();
X 
X 	return 0;
X }
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_csz.c linux/net/sched/sch_csz.c
--- v2.3.5/linux/net/sched/sch_csz.c	Sun Mar 21 07:22:00 1999
+++ linux/net/sched/sch_csz.c	Wed Jun  9 14:45:37 1999
@@ -885,7 +885,7 @@
X 
X 		a = &q->flow[cl];
X 
-		start_bh_atomic();	
+		spin_lock_bh(&sch->dev->queue_lock);
X #if 0
X 		a->rate_log = copt->rate_log;
X #endif
@@ -899,7 +899,7 @@
X 		if (tb[TCA_CSZ_RTAB-1])
X 			memcpy(a->L_tab, RTA_DATA(tb[TCA_CSZ_RTAB-1]), 1024);
X 
-		end_bh_atomic();
+		spin_unlock_bh(&sch->dev->queue_lock);
X 		return 0;
X 	}
X 	/* NI */
@@ -920,14 +920,14 @@
X 
X 	a = &q->flow[cl];
X 
-	start_bh_atomic();
+	spin_lock_bh(&sch->dev->queue_lock);
X 	a->fprev->fnext = a->fnext;
X 	a->fnext->fprev = a->fprev;
X 	a->sprev->snext = a->snext;
X 	a->snext->sprev = a->sprev;
X 	a->start = a->finish = 0;
X 	kfree(xchg(&q->flow[cl].L_tab, NULL));
-	end_bh_atomic();
+	spin_unlock_bh(&sch->dev->queue_lock);
X 
X 	return 0;
X }
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c
--- v2.3.5/linux/net/sched/sch_generic.c	Mon May 31 22:28:07 1999
+++ linux/net/sched/sch_generic.c	Wed Jun  9 14:45:37 1999
@@ -34,7 +34,45 @@
X 
X /* Main transmission queue. */
X 
-struct Qdisc_head qdisc_head = { &qdisc_head };
+struct Qdisc_head qdisc_head = { &qdisc_head, &qdisc_head };
+spinlock_t qdisc_runqueue_lock = SPIN_LOCK_UNLOCKED;
+
+/* Main qdisc structure lock. 
+
+   However, modifications
+   to data, participating in scheduling must be additionally
+   protected with dev->queue_lock spinlock.
+
+   The idea is the following:
+   - enqueue, dequeue are serialized via top level device
+     spinlock dev->queue_lock.
+   - tree walking is protected by read_lock(qdisc_tree_lock)
+     and this lock is used only in process context.
+   - updates to tree are made only under rtnl semaphore,
+     hence this lock may be made without local bh disabling.
+
+   qdisc_tree_lock must be grabbed BEFORE dev->queue_lock!
+ */
+rwlock_t qdisc_tree_lock = RW_LOCK_UNLOCKED;
+
+/* Anti deadlock rules:
+
+   qdisc_runqueue_lock protects main transmission list qdisc_head.
+   Run list is accessed only under this spinlock.
+
+   dev->queue_lock serializes queue accesses for this device
+   AND dev->qdisc pointer itself.
+
+   dev->xmit_lock serializes accesses to device driver.
+
+   dev->queue_lock and dev->xmit_lock are mutually exclusive,
+   if one is grabbed, another must be free.
+
+   qdisc_runqueue_lock may be requested under dev->queue_lock,
+   but neither dev->queue_lock nor dev->xmit_lock may be requested
+   under qdisc_runqueue_lock.
+ */
+
X 
X /* Kick device.
X    Note, that this procedure can be called by a watchdog timer, so that
@@ -44,7 +82,7 @@
X             >0  - queue is not empty, but throttled.
X 	    <0  - queue is not empty. Device is throttled, if dev->tbusy != 0.
X 
-   NOTE: Called only from NET BH
+   NOTE: Called under dev->queue_lock with locally disabled BH.
X */
X 
X int qdisc_restart(struct device *dev)
@@ -53,27 +91,97 @@
X 	struct sk_buff *skb;
X 
X 	if ((skb = q->dequeue(q)) != NULL) {
+		/* Dequeue packet and release queue */
+		spin_unlock(&dev->queue_lock);
+
X 		if (netdev_nit)
X 			dev_queue_xmit_nit(skb, dev);
X 
-		if (dev->hard_start_xmit(skb, dev) == 0) {
-			q->tx_last = jiffies;
-			return -1;
+		if (spin_trylock(&dev->xmit_lock)) {
+			/* Remember that the driver is grabbed by us. */
+			dev->xmit_lock_owner = smp_processor_id();
+			if (dev->hard_start_xmit(skb, dev) == 0) {
+				dev->xmit_lock_owner = -1;
+				spin_unlock(&dev->xmit_lock);
+
+				spin_lock(&dev->queue_lock);
+				dev->qdisc->tx_last = jiffies;
+				return -1;
+			}
+			/* Release the driver */
+			dev->xmit_lock_owner = -1;
+			spin_unlock(&dev->xmit_lock);
+		} else {
+			/* So, someone grabbed the driver. */
+
+			/* It may be transient configuration error,
+			   when hard_start_xmit() recurses. We detect
+			   it by checking xmit owner and drop the
+			   packet when deadloop is detected.
+			 */
+			if (dev->xmit_lock_owner == smp_processor_id()) {
+				kfree_skb(skb);
+				if (net_ratelimit())
+					printk(KERN_DEBUG "Dead loop on virtual %s, fix it urgently!\n", dev->name);
+				spin_lock(&dev->queue_lock);
+				return -1;
+			}
+
+			/* Otherwise, packet is requeued
+			   and will be sent by the next net_bh run.
+			 */
+			mark_bh(NET_BH);
X 		}
X 
X 		/* Device kicked us out :(
X 		   This is possible in three cases:
X 
+		   0. driver is locked
X 		   1. fastroute is enabled
X 		   2. device cannot determine busy state
X 		      before start of transmission (f.e. dialout)
X 		   3. device is buggy (ppp)
X 		 */
X 
+		spin_lock(&dev->queue_lock);
+		q = dev->qdisc;
X 		q->ops->requeue(skb, q);
X 		return -1;
X 	}
-	return q->q.qlen;
+	return dev->qdisc->q.qlen;
+}
+
+static __inline__ void
+qdisc_stop_run(struct Qdisc *q)
+{
+	q->h.forw->back = q->h.back;
+	q->h.back->forw = q->h.forw;
+	q->h.forw = NULL;
+}
+
+extern __inline__ void
+qdisc_continue_run(struct Qdisc *q)
+{
+	if (!qdisc_on_runqueue(q) && q->dev) {
+		q->h.forw = &qdisc_head;
+		q->h.back = qdisc_head.back;
+		qdisc_head.back->forw = &q->h;
+		qdisc_head.back = &q->h;
+	}
+}
+
+static __inline__ int
+qdisc_init_run(struct Qdisc_head *lh)
+{
+	if (qdisc_head.forw != &qdisc_head) {
+		*lh = qdisc_head;
+		lh->forw->back = lh;
+		lh->back->forw = lh;
+		qdisc_head.forw = &qdisc_head;
+		qdisc_head.back = &qdisc_head;
+		return 1;
+	}
+	return 0;
X }
X 
X /* Scan transmission queue and kick devices.
@@ -84,63 +192,90 @@
X    I have no idea how to solve it using only "anonymous" Linux mark_bh().
X 
X    To change queue from device interrupt? Ough... only not this...
+
+   This function is called only from net_bh.
X  */
X 
X void qdisc_run_queues(void)
X {
-	struct Qdisc_head **hp, *h;
+	struct Qdisc_head lh, *h;
X 
-	hp = &qdisc_head.forw;
-	while ((h = *hp) != &qdisc_head) {
-		int res = -1;
+	spin_lock(&qdisc_runqueue_lock);
+	if (!qdisc_init_run(&lh))
+		goto out;
+
+	while ((h = lh.forw) != &lh) {
+		int res;
+		struct device *dev;
X 		struct Qdisc *q = (struct Qdisc*)h;
-		struct device *dev = q->dev;
X 
-		spin_lock_bh(&dev->xmit_lock);
-		while (!dev->tbusy && (res = qdisc_restart(dev)) < 0)
-			/* NOTHING */;
-		spin_unlock_bh(&dev->xmit_lock);
-
-		/* An explanation is necessary here.
-		   qdisc_restart called dev->hard_start_xmit,
-		   if device is virtual, it could trigger one more
-		   dev_queue_xmit and a new device could appear
-		   in the active chain. In this case we cannot unlink
-		   the empty queue, because we lost the back pointer.
-		   No problem, we will unlink it during the next round.
-		 */
+		qdisc_stop_run(q);
+
+		dev = q->dev;
+		spin_unlock(&qdisc_runqueue_lock);
X 
-		if (res == 0 && *hp == h) {
-			*hp = h->forw;
-			h->forw = NULL;
-			continue;
+		res = -1;
+		if (spin_trylock(&dev->queue_lock)) {
+			while (!dev->tbusy && (res = qdisc_restart(dev)) < 0)
+				/* NOTHING */;
+			spin_unlock(&dev->queue_lock);
X 		}
-		hp = &h->forw;
+
+		spin_lock(&qdisc_runqueue_lock);
+		/* If qdisc is not empty add it to the tail of list */
+		if (res)
+			qdisc_continue_run(q);
X 	}
+out:
+	spin_unlock(&qdisc_runqueue_lock);
X }
X 
-/* Periodic watchdoc timer to recover from hard/soft device bugs. */
+/* Periodic watchdog timer to recover from hard/soft device bugs. */
X 
X static void dev_do_watchdog(unsigned long dummy);
X 
X static struct timer_list dev_watchdog =
X 	{ NULL, NULL, 0L, 0L, &dev_do_watchdog };
X 
+/*   This function is called only from timer */
+
X static void dev_do_watchdog(unsigned long dummy)
X {
-	struct Qdisc_head *h;
+	struct Qdisc_head lh, *h;
+
+	if (!spin_trylock(&qdisc_runqueue_lock)) {
+		/* No hurry with watchdog. */
+		mod_timer(&dev_watchdog, jiffies + HZ/10);
+		return;
+	}
+
+	if (!qdisc_init_run(&lh))
+		goto out;
X 
-	for (h = qdisc_head.forw; h != &qdisc_head; h = h->forw) {
+	while ((h = lh.forw) != &lh) {
+		struct device *dev;
X 		struct Qdisc *q = (struct Qdisc*)h;
-		struct device *dev = q->dev;
X 
-		spin_lock_bh(&dev->xmit_lock);
-		if (dev->tbusy && jiffies - q->tx_last > q->tx_timeo)
-			qdisc_restart(dev);
-		spin_unlock_bh(&dev->xmit_lock);
+		qdisc_stop_run(q);
+
+		dev = q->dev;
+		spin_unlock(&qdisc_runqueue_lock);
+
+		if (spin_trylock(&dev->queue_lock)) {
+			q = dev->qdisc;
+			if (dev->tbusy && jiffies - q->tx_last > q->tx_timeo)
+				qdisc_restart(dev);
+			spin_unlock(&dev->queue_lock);
+		}
+
+		spin_lock(&qdisc_runqueue_lock);
+
+		qdisc_continue_run(dev->qdisc);
X 	}
-	dev_watchdog.expires = jiffies + 5*HZ;
-	add_timer(&dev_watchdog);
+
+out:
+	mod_timer(&dev_watchdog, jiffies + 5*HZ);
+	spin_unlock(&qdisc_runqueue_lock);
X }
X 
X 
@@ -211,7 +346,7 @@
X {
X         { NULL }, 
X 	NULL,
-	NULL,
+	noop_dequeue,
X 	TCQ_F_BUILTIN,
X 	&noqueue_qdisc_ops,
X };
@@ -327,6 +462,7 @@
X 	sch->enqueue = ops->enqueue;
X 	sch->dequeue = ops->dequeue;
X 	sch->dev = dev;
+	sch->stats.lock = &dev->queue_lock;
X 	atomic_set(&sch->refcnt, 1);
X 	if (!ops->init || ops->init(sch, NULL) == 0)
X 		return sch;
@@ -335,42 +471,45 @@
X 	return NULL;
X }
X 
+/* Under dev->queue_lock and BH! */
+
X void qdisc_reset(struct Qdisc *qdisc)
X {
X 	struct Qdisc_ops *ops = qdisc->ops;
-	start_bh_atomic();
X 	if (ops->reset)
X 		ops->reset(qdisc);
-	end_bh_atomic();
X }
X 
+/* Under dev->queue_lock and BH! */
+
X void qdisc_destroy(struct Qdisc *qdisc)
X {
X 	struct Qdisc_ops *ops = qdisc->ops;
+	struct device *dev;
X 
X 	if (!atomic_dec_and_test(&qdisc->refcnt))
X 		return;
X 
+	dev = qdisc->dev;
+
X #ifdef CONFIG_NET_SCHED
-	if (qdisc->dev) {
+	if (dev) {
X 		struct Qdisc *q, **qp;
-		for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next)
+		for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next) {
X 			if (q == qdisc) {
X 				*qp = q->next;
-				q->next = NULL;
X 				break;
X 			}
+		}
X 	}
X #ifdef CONFIG_NET_ESTIMATOR
X 	qdisc_kill_estimator(&qdisc->stats);
X #endif
X #endif
-	start_bh_atomic();
X 	if (ops->reset)
X 		ops->reset(qdisc);
X 	if (ops->destroy)
X 		ops->destroy(qdisc);
-	end_bh_atomic();
X 	if (!(qdisc->flags&TCQ_F_BUILTIN))
X 		kfree(qdisc);
X }
@@ -385,19 +524,23 @@
X 	 */
X 
X 	if (dev->qdisc_sleeping == &noop_qdisc) {
+		struct Qdisc *qdisc;
X 		if (dev->tx_queue_len) {
-			struct Qdisc *qdisc;
X 			qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops);
X 			if (qdisc == NULL) {
X 				printk(KERN_INFO "%s: activation failed\n", dev->name);
X 				return;
X 			}
-			dev->qdisc_sleeping = qdisc;
-		} else
-			dev->qdisc_sleeping = &noqueue_qdisc;
+		} else {
+			qdisc =  &noqueue_qdisc;
+		}
+		write_lock(&qdisc_tree_lock);
+		dev->qdisc_sleeping = qdisc;
+		write_unlock(&qdisc_tree_lock);
X 	}
X 
-	start_bh_atomic();
+	spin_lock_bh(&dev->queue_lock);
+	spin_lock(&qdisc_runqueue_lock);
X 	if ((dev->qdisc = dev->qdisc_sleeping) != &noqueue_qdisc) {
X 		dev->qdisc->tx_timeo = 5*HZ;
X 		dev->qdisc->tx_last = jiffies - dev->qdisc->tx_timeo;
@@ -405,51 +548,50 @@
X 			dev_watchdog.expires = jiffies + 5*HZ;
X 		add_timer(&dev_watchdog);
X 	}
-	end_bh_atomic();
+	spin_unlock(&qdisc_runqueue_lock);
+	spin_unlock_bh(&dev->queue_lock);
X }
X 
X void dev_deactivate(struct device *dev)
X {
X 	struct Qdisc *qdisc;
X 
-	start_bh_atomic();
-
-	qdisc = xchg(&dev->qdisc, &noop_qdisc);
+	spin_lock_bh(&dev->queue_lock);
+	qdisc = dev->qdisc;
+	dev->qdisc = &noop_qdisc;
X 
X 	qdisc_reset(qdisc);
X 
-	if (qdisc->h.forw) {
-		struct Qdisc_head **hp, *h;
-
-		for (hp = &qdisc_head.forw; (h = *hp) != &qdisc_head; hp = &h->forw) {
-			if (h == &qdisc->h) {
-				*hp = h->forw;
-				break;
-			}
-		}
-	}
-
-	end_bh_atomic();
+	spin_lock(&qdisc_runqueue_lock);
+	if (qdisc_on_runqueue(qdisc))
+		qdisc_stop_run(qdisc);
+	spin_unlock(&qdisc_runqueue_lock);
+	spin_unlock_bh(&dev->queue_lock);
X }
X 
X void dev_init_scheduler(struct device *dev)
X {
+	write_lock(&qdisc_tree_lock);
+	spin_lock_bh(&dev->queue_lock);
X 	dev->qdisc = &noop_qdisc;
+	spin_unlock_bh(&dev->queue_lock);
X 	dev->qdisc_sleeping = &noop_qdisc;
X 	dev->qdisc_list = NULL;
+	write_unlock(&qdisc_tree_lock);
X }
X 
X void dev_shutdown(struct device *dev)
X {
X 	struct Qdisc *qdisc;
X 
-	start_bh_atomic();
+	write_lock(&qdisc_tree_lock);
+	spin_lock_bh(&dev->queue_lock);
X 	qdisc = dev->qdisc_sleeping;
X 	dev->qdisc = &noop_qdisc;
X 	dev->qdisc_sleeping = &noop_qdisc;
X 	qdisc_destroy(qdisc);
X 	BUG_TRAP(dev->qdisc_list == NULL);
X 	dev->qdisc_list = NULL;
-	end_bh_atomic();
+	spin_unlock_bh(&dev->queue_lock);
+	write_unlock(&qdisc_tree_lock);
X }
-
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_prio.c linux/net/sched/sch_prio.c
--- v2.3.5/linux/net/sched/sch_prio.c	Thu Mar 25 09:23:34 1999
+++ linux/net/sched/sch_prio.c	Wed Jun  9 14:45:37 1999
@@ -178,7 +178,7 @@
X 			return -EINVAL;
X 	}
X 
-	start_bh_atomic();
+	sch_tree_lock(sch);
X 	q->bands = qopt->bands;
X 	memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
X 
@@ -187,7 +187,7 @@
X 		if (child != &noop_qdisc)
X 			qdisc_destroy(child);
X 	}
-	end_bh_atomic();
+	sch_tree_unlock(sch);
X 
X 	for (i=0; i<=TC_PRIO_MAX; i++) {
X 		int band = q->prio2band[i];
@@ -195,11 +195,12 @@
X 			struct Qdisc *child;
X 			child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
X 			if (child) {
+				sch_tree_lock(sch);
X 				child = xchg(&q->queues[band], child);
-				synchronize_bh();
X 
X 				if (child != &noop_qdisc)
X 					qdisc_destroy(child);
+				sch_tree_unlock(sch);
X 			}
X 		}
X 	}
@@ -265,7 +266,11 @@
X 	if (new == NULL)
X 		new = &noop_qdisc;
X 
-	*old = xchg(&q->queues[band], new);
+	sch_tree_lock(sch);
+	*old = q->queues[band];
+	q->queues[band] = new;
+	qdisc_reset(*old);
+	sch_tree_unlock(sch);
X 
X 	return 0;
X }
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c
--- v2.3.5/linux/net/sched/sch_sfq.c	Sat Apr 24 17:51:48 1999
+++ linux/net/sched/sch_sfq.c	Wed Jun  9 14:45:37 1999
@@ -387,7 +387,7 @@
X 	if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
X 		return -EINVAL;
X 
-	start_bh_atomic();
+	sch_tree_lock(sch);
X 	q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
X 	q->perturb_period = ctl->perturb_period*HZ;
X 
@@ -396,7 +396,7 @@
X 		q->perturb_timer.expires = jiffies + q->perturb_period;
X 		add_timer(&q->perturb_timer);
X 	}
-	end_bh_atomic();
+	sch_tree_unlock(sch);
X 	return 0;
X }
X 
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c
--- v2.3.5/linux/net/sched/sch_tbf.c	Sun Mar 21 07:22:00 1999
+++ linux/net/sched/sch_tbf.c	Wed Jun  9 14:45:37 1999
@@ -308,7 +308,7 @@
X 	if (rtab->data[max_size>>qopt->rate.cell_log] > qopt->buffer)
X 		goto done;
X 
-	start_bh_atomic();
+	sch_tree_lock(sch);
X 	q->limit = qopt->limit;
X 	q->mtu = qopt->mtu;
X 	q->max_size = max_size;
@@ -317,7 +317,7 @@
X 	q->ptokens = q->mtu;
X 	rtab = xchg(&q->R_tab, rtab);
X 	ptab = xchg(&q->P_tab, ptab);
-	end_bh_atomic();
+	sch_tree_unlock(sch);
X 	err = 0;
X done:
X 	if (rtab)
diff -u --recursive --new-file v2.3.5/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c
--- v2.3.5/linux/net/sched/sch_teql.c	Sun Mar 21 07:22:00 1999
+++ linux/net/sched/sch_teql.c	Wed Jun  9 14:45:37 1999
@@ -125,9 +125,11 @@
X 	if (skb == NULL) {
X 		struct device *m = dat->m->dev.qdisc->dev;
X 		if (m) {
-			m->tbusy = 0;
X 			dat->m->slaves = sch;
+			spin_lock(&m->queue_lock);
+			m->tbusy = 0;
X 			qdisc_restart(m);
+			spin_unlock(&m->queue_lock);
X 		}
X 	}
X 	sch->q.qlen = dat->q.qlen + dat->m->dev.qdisc->q.qlen;
@@ -167,7 +169,9 @@
X 					master->slaves = NEXT_SLAVE(q);
X 					if (q == master->slaves) {
X 						master->slaves = NULL;
+						spin_lock_bh(&master->dev.queue_lock);
X 						qdisc_reset(master->dev.qdisc);
+						spin_unlock_bh(&master->dev.queue_lock);
X 					}
X 				}
X 				skb_queue_purge(&dat->q);
@@ -190,6 +194,9 @@
X 	if (dev->hard_header_len > m->dev.hard_header_len)
X 		return -EINVAL;
X 
+	if (&m->dev == dev)
+		return -ELOOP;
+
X 	q->m = m;
X 
X 	skb_queue_head_init(&q->q);
@@ -244,7 +251,11 @@
X 			return -ENOBUFS;
X 	}
X 	if (neigh_event_send(n, skb_res) == 0) {
-		if (dev->hard_header(skb, dev, ntohs(skb->protocol), n->ha, NULL, skb->len) < 0) {
+		int err;
+		read_lock(&n->lock);
+		err = dev->hard_header(skb, dev, ntohs(skb->protocol), n->ha, NULL, skb->len);
+		read_unlock(&n->lock);
+		if (err < 0) {
X 			neigh_release(n);
X 			return -EINVAL;
X 		}
@@ -295,19 +306,24 @@
X 			continue;
X 		}
X 
-		if (q->h.forw == NULL) {
-			q->h.forw = qdisc_head.forw;
-			qdisc_head.forw = &q->h;
-		}
+		if (!qdisc_on_runqueue(q))
+			qdisc_run(q);
X 
X 		switch (teql_resolve(skb, skb_res, slave)) {
X 		case 0:
-			if (slave->hard_start_xmit(skb, slave) == 0) {
-				master->slaves = NEXT_SLAVE(q);
-				dev->tbusy = 0;
-				master->stats.tx_packets++;
-				master->stats.tx_bytes += len;
+			if (spin_trylock(&slave->xmit_lock)) {
+				slave->xmit_lock_owner = smp_processor_id();
+				if (slave->hard_start_xmit(skb, slave) == 0) {
+					slave->xmit_lock_owner = -1;
+					spin_unlock(&slave->xmit_lock);
+					master->slaves = NEXT_SLAVE(q);
+					dev->tbusy = 0;
+					master->stats.tx_packets++;
+					master->stats.tx_bytes += len;
X 					return 0;
+				}
+				slave->xmit_lock_owner = -1;
+				spin_unlock(&slave->xmit_lock);
X 			}
X 			if (dev->tbusy)
X 				busy = 1;
diff -u --recursive --new-file v2.3.5/linux/net/socket.c linux/net/socket.c
--- v2.3.5/linux/net/socket.c	Mon May 31 22:28:07 1999
+++ linux/net/socket.c	Tue Jun  8 10:47:58 1999
@@ -204,7 +204,7 @@
X 			return -ENFILE;
X 		}
X 
-		file->f_dentry = d_alloc_root(inode, NULL);
+		file->f_dentry = d_alloc_root(inode);
X 		if (!file->f_dentry) {
X 			put_filp(file);
X 			put_unused_fd(fd);
diff -u --recursive --new-file v2.3.5/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.3.5/linux/net/sunrpc/xprt.c	Tue May  4 10:29:07 1999
+++ linux/net/sunrpc/xprt.c	Tue Jun  8 17:58:03 1999
@@ -42,6 +42,7 @@
X #define __KERNEL_SYSCALLS__
X 
X #include <linux/version.h>
+#include <linux/config.h>
X #include <linux/types.h>
X #include <linux/malloc.h>
X #include <linux/sched.h>
@@ -56,6 +57,8 @@
X #include <linux/file.h>
X 
X #include <net/sock.h>
+#include <net/checksum.h>
+#include <net/udp.h>
X 
X #include <asm/uaccess.h>
X 
@@ -356,6 +359,7 @@
X 	sk->user_data    = NULL;
X #endif
X 	sk->data_ready   = xprt->old_data_ready;
+	sk->no_check 	 = 0;
X 	sk->state_change = xprt->old_state_change;
X 	sk->write_space  = xprt->old_write_space;
X 
@@ -563,18 +567,61 @@
X 	return;
X }
X 
-/*
- * Input handler for RPC replies. Called from a bottom half and hence
+/* We have set things up such that we perform the checksum of the UDP
+ * packet in parallel with the copies into the RPC client iovec.  -DaveM
+ */
+static int csum_partial_copy_to_page_cache(struct iovec *iov,
+					   struct sk_buff *skb,
+					   int copied)
+{
+	__u8 *pkt_data = skb->data + sizeof(struct udphdr);
+	__u8 *cur_ptr = iov->iov_base;
+	__kernel_size_t cur_len = iov->iov_len;
+	unsigned int csum = skb->csum;
+	int need_csum = (skb->ip_summed != CHECKSUM_UNNECESSARY);
+	int slack = skb->len - copied - sizeof(struct udphdr);
+
+	if (need_csum)
+		csum = csum_partial(skb->h.raw, sizeof(struct udphdr), csum);
+	while (copied > 0) {
+		if (cur_len) {
+			int to_move = cur_len;
+			if (to_move > copied)
+				to_move = copied;
+			if (need_csum)
+				csum = csum_partial_copy_nocheck(pkt_data, cur_ptr,
+								 to_move, csum);
+			else
+				memcpy(cur_ptr, pkt_data, to_move);
+			pkt_data += to_move;
+			copied -= to_move;
+			cur_ptr += to_move;
+			cur_len -= to_move;
+		}
+		if (cur_len <= 0) {
+			iov++;
+			cur_len = iov->iov_len;
+			cur_ptr = iov->iov_base;
+		}
+	}
+	if (need_csum) {
+		if (slack > 0)
+			csum = csum_partial(pkt_data, slack, csum);
+		if ((unsigned short)csum_fold(csum))
+			return -1;
+	}
+	return 0;
+}
+
+/* Input handler for RPC replies. Called from a bottom half and hence
X  * atomic.
X  */
X static inline void
X udp_data_ready(struct sock *sk, int len)
X {
-	struct rpc_task	*task;
X 	struct rpc_xprt	*xprt;
X 	struct rpc_rqst *rovr;
X 	struct sk_buff	*skb;
-	struct iovec	iov[MAX_IOVEC];
X 	int		err, repsize, copied;
X 
X 	dprintk("RPC:      udp_data_ready...\n");
@@ -584,28 +631,31 @@
X 
X 	if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL)
X 		return;
-	repsize = skb->len - 8;	/* don't account for UDP header */
X 
+	repsize = skb->len - sizeof(struct udphdr);
X 	if (repsize < 4) {
X 		printk("RPC: impossible RPC reply size %d!\n", repsize);
X 		goto dropit;
X 	}
X 
X 	/* Look up the request corresponding to the given XID */
-	if (!(rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + 8))))
+	if (!(rovr = xprt_lookup_rqst(xprt,
+				      *(u32 *) (skb->h.raw + sizeof(struct udphdr)))))
X 		goto dropit;
-	task = rovr->rq_task;
X 
-	dprintk("RPC: %4d received reply\n", task->tk_pid);
-	xprt_pktdump("packet data:", (u32 *) (skb->h.raw+8), repsize);
+	dprintk("RPC: %4d received reply\n", rovr->rq_task->tk_pid);
+	xprt_pktdump("packet data:",
+		     (u32 *) (skb->h.raw + sizeof(struct udphdr)), repsize);
X 
X 	if ((copied = rovr->rq_rlen) > repsize)
X 		copied = repsize;
X 
-	/* Okay, we have it. Copy datagram... */
-	memcpy(iov, rovr->rq_rvec, rovr->rq_rnr * sizeof(iov[0]));
-	/* This needs to stay tied with the usermode skb_copy_dagram... */
-	memcpy_tokerneliovec(iov, skb->data+8, copied);
+	/* Suck it into the iovec, verify checksum if not done by hw. */
+	if (csum_partial_copy_to_page_cache(rovr->rq_rvec, skb, copied))
+		goto dropit;
+
+	/* Something worked... */
+	dst_confirm(skb->dst);
X 
X 	xprt_complete_rqst(xprt, rovr, copied);
X 
@@ -1341,6 +1391,7 @@
X 	xprt->old_write_space = inet->write_space;
X 	if (proto == IPPROTO_UDP) {
X 		inet->data_ready = udp_data_ready;
+		inet->no_check = UDP_CSUM_NORCV;
X 	} else {
X 		inet->data_ready = tcp_data_ready;
X 		inet->state_change = tcp_state_change;
diff -u --recursive --new-file v2.3.5/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.3.5/linux/net/wanrouter/wanmain.c	Wed Dec 30 15:07:00 1998
+++ linux/net/wanrouter/wanmain.c	Wed Jun  2 14:40:22 1999
@@ -30,6 +30,7 @@
X * Dec 22, 1998  Arnaldo Melo    vmalloc/vfree used in device_setup to allocate
X *                               kernel memory and copy configuration data to
X *                               kernel space (for big firmwares)
+* May 19, 1999  Arnaldo Melo    __initfunc in wanrouter_init
X *****************************************************************************/
X 
X #include <linux/config.h>
@@ -104,17 +105,18 @@
X #endif
X 
X #ifndef MODULE
-
-int wanrouter_init(void)
+__initfunc(int wanrouter_init(void))
X {
X 	int err;
-	extern void wanpipe_init(void);
+	extern int wanpipe_init(void),
+		   cyclomx_init(void);
X 
X 	printk(KERN_INFO "%s v%u.%u %s\n",
X 		fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
X 	err = wanrouter_proc_init();
X 	if (err)
-		printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname);		
+		printk(KERN_ERR "%s: can't create entry in proc filesystem!\n",
+				modname);		
X 
X 	/*
X 	 *	Initialise compiled in boards
@@ -123,6 +125,9 @@
X #ifdef CONFIG_VENDOR_SANGOMA
X 	wanpipe_init();
X #endif	
+#ifdef CONFIG_CYCLADES_SYNC
+	cyclomx_init();
+#endif
X 	return err;
X }
X 
@@ -187,7 +192,6 @@
X  *	Context:	process
X  */
X 
-
X int register_wan_device(wan_device_t* wandev)
X {
X 	int err, namelen;
@@ -207,7 +211,6 @@
X 	printk(KERN_INFO "%s: registering WAN device %s\n",
X 		modname, wandev->name);
X #endif
-
X 	/*
X 	 *	Register /proc directory entry 
X 	 */
diff -u --recursive --new-file v2.3.5/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.3.5/linux/net/x25/af_x25.c	Wed Jun  2 14:44:39 1999
+++ linux/net/x25/af_x25.c	Wed Jun  9 14:45:37 1999
@@ -1336,7 +1336,7 @@
X 	/*
X 	 *	Register any pre existing devices.
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
fi
echo 'End of  part 26'
echo 'File patch-2.3.6 is continued in part 27'
echo 27 > _shar_seq_.tmp
#!/bin/sh
# this is part 27 of a 27 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.6 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 27; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.6'
else
echo 'x - continuing with patch-2.3.6'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.6' &&
X */
-	read_lock_bh(&dev_base_lock);
+	read_lock(&dev_base_lock);
X 	for (dev = dev_base; dev != NULL; dev = dev->next) {
X 		if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25
X #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
@@ -1345,7 +1345,7 @@
X 			))
X 			x25_link_device_up(dev);
X 	}
-	read_unlock_bh(&dev_base_lock);
+	read_unlock(&dev_base_lock);
X 
X 	return 0;
X }
SHAR_EOF
true || echo 'restore of patch-2.3.6 failed'
echo 'File patch-2.3.6 is complete' &&
chmod 644 patch-2.3.6 ||
echo 'restore of patch-2.3.6 failed'
Cksum="`cksum < 'patch-2.3.6'`"
if ! test "593112112 1494642" = "$Cksum"
then
	echo 'patch-2.3.6: original Checksum 593112112 1494642, current one' "$Cksum" 
	rm -f _shar_wnt_.tmp
	rm -f _shar_seq_.tmp
	exit 1
fi
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo 'You have unpacked the last part.'