summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-27 23:54:12 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-27 23:54:12 +0000
commitd3e71cb08747743fce908122bab08b479eb403a5 (patch)
treecbec6948fdbdee9af81cf3ecfb504070d2745d7b
parentfe7ff1706e323d0e5ed83972960a1ecc1ee538b3 (diff)
Merge with Linux 2.3.99-pre3.
-rw-r--r--CREDITS44
-rw-r--r--Documentation/Changes7
-rw-r--r--Documentation/Configure.help324
-rw-r--r--Documentation/DocBook/Makefile5
-rw-r--r--Documentation/DocBook/kernel-api.tmpl13
-rw-r--r--Documentation/devices.tex2209
-rw-r--r--Documentation/devices.txt160
-rw-r--r--Documentation/isapnp.txt53
-rw-r--r--Documentation/isdn/README.eicon6
-rw-r--r--Documentation/networking/tlan.txt4
-rw-r--r--Documentation/networking/tulip.txt21
-rw-r--r--Documentation/video4linux/bttv/README7
-rw-r--r--MAINTAINERS16
-rw-r--r--Makefile16
-rw-r--r--Rules.make2
-rw-r--r--arch/alpha/config.in20
-rw-r--r--arch/alpha/defconfig45
-rw-r--r--arch/alpha/kernel/core_apecs.c6
-rw-r--r--arch/alpha/kernel/core_cia.c13
-rw-r--r--arch/alpha/kernel/core_irongate.c14
-rw-r--r--arch/alpha/kernel/core_lca.c6
-rw-r--r--arch/alpha/kernel/core_mcpcia.c10
-rw-r--r--arch/alpha/kernel/core_polaris.c8
-rw-r--r--arch/alpha/kernel/core_t2.c8
-rw-r--r--arch/alpha/kernel/core_tsunami.c15
-rw-r--r--arch/alpha/kernel/entry.S3
-rw-r--r--arch/alpha/kernel/osf_sys.c33
-rw-r--r--arch/alpha/kernel/pci.c36
-rw-r--r--arch/alpha/kernel/process.c7
-rw-r--r--arch/alpha/kernel/ptrace.c17
-rw-r--r--arch/alpha/kernel/sys_jensen.c17
-rw-r--r--arch/alpha/math-emu/math.c62
-rw-r--r--arch/arm/config.in4
-rw-r--r--arch/arm/defconfig204
-rw-r--r--arch/i386/Makefile22
-rw-r--r--arch/i386/boot/compressed/misc.c14
-rw-r--r--arch/i386/config.in24
-rw-r--r--arch/i386/defconfig2
-rw-r--r--arch/i386/kernel/entry.S12
-rw-r--r--arch/i386/kernel/i8259.c4
-rw-r--r--arch/i386/kernel/io_apic.c134
-rw-r--r--arch/i386/kernel/signal.c4
-rw-r--r--arch/i386/lib/checksum.S13
-rw-r--r--arch/ia64/config.in53
-rw-r--r--arch/ia64/defconfig200
-rw-r--r--arch/m68k/Makefile4
-rw-r--r--arch/m68k/config.in1
-rw-r--r--arch/m68k/defconfig234
-rw-r--r--arch/mips/config.in17
-rw-r--r--arch/mips/defconfig15
-rw-r--r--arch/mips/defconfig-decstation2
-rw-r--r--arch/mips/defconfig-ip2215
-rw-r--r--arch/mips/kernel/irixelf.c130
-rw-r--r--arch/mips/mm/loadmmu.c3
-rw-r--r--arch/mips/mm/r2300.c3
-rw-r--r--arch/mips64/config.in17
-rw-r--r--arch/mips64/defconfig11
-rw-r--r--arch/mips64/defconfig-ip222
-rw-r--r--arch/mips64/defconfig-ip2711
-rw-r--r--arch/ppc/config.in28
-rw-r--r--arch/ppc/configs/common_defconfig144
-rw-r--r--arch/ppc/defconfig109
-rw-r--r--arch/sh/config.in2
-rw-r--r--arch/sh/defconfig32
-rw-r--r--arch/sparc/Makefile2
-rw-r--r--arch/sparc/config.in2
-rw-r--r--arch/sparc64/Makefile4
-rw-r--r--arch/sparc64/config.in4
-rw-r--r--arch/sparc64/defconfig4
-rw-r--r--arch/sparc64/kernel/Makefile4
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c42
-rw-r--r--arch/sparc64/kernel/ioctl32.c43
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c40
-rw-r--r--arch/sparc64/lib/memcmp.S41
-rw-r--r--drivers/acorn/block/Makefile3
-rw-r--r--drivers/acorn/scsi/Makefile3
-rw-r--r--drivers/atm/Makefile28
-rw-r--r--drivers/atm/ambassador.c551
-rw-r--r--drivers/atm/ambassador.h22
-rw-r--r--drivers/atm/atmdev_init.c2
-rw-r--r--drivers/atm/atmtcp.c61
-rw-r--r--drivers/atm/eni.c271
-rw-r--r--drivers/atm/eni.h3
-rw-r--r--drivers/atm/fore200e.c174
-rw-r--r--drivers/atm/fore200e.h33
-rw-r--r--drivers/atm/horizon.c124
-rw-r--r--drivers/atm/horizon.h2
-rw-r--r--drivers/atm/idt77105.c64
-rw-r--r--drivers/atm/iphase.c161
-rw-r--r--drivers/atm/nicstar.c141
-rw-r--r--drivers/atm/nicstar.h2
-rw-r--r--drivers/atm/suni.c169
-rw-r--r--drivers/atm/suni.h4
-rw-r--r--drivers/atm/uPD98402.c123
-rw-r--r--drivers/atm/zatm.c26
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/lvm.c9
-rw-r--r--drivers/block/md.c4
-rw-r--r--drivers/block/paride/paride.c4
-rw-r--r--drivers/cdrom/cm206.c2
-rw-r--r--drivers/char/acquirewdt.c10
-rw-r--r--drivers/char/amigamouse.c6
-rw-r--r--drivers/char/amiserial.c2
-rw-r--r--drivers/char/applicom.c1167
-rw-r--r--drivers/char/atixlmouse.c22
-rw-r--r--drivers/char/bttv.c206
-rw-r--r--drivers/char/bttv.h11
-rw-r--r--drivers/char/busmouse.c126
-rw-r--r--drivers/char/busmouse.h2
-rw-r--r--drivers/char/misc.c34
-rw-r--r--drivers/char/rtc.c10
-rw-r--r--drivers/char/serial.c290
-rw-r--r--drivers/char/sysrq.c36
-rw-r--r--drivers/char/tty_io.c3
-rw-r--r--drivers/char/wdt.c6
-rw-r--r--drivers/i2c/i2c-algo-pcf.c2
-rw-r--r--drivers/ide/Config.in9
-rw-r--r--drivers/ide/aec6210.c16
-rw-r--r--drivers/ide/ali14xx.c2
-rw-r--r--drivers/ide/alim15x3.c54
-rw-r--r--drivers/ide/amd7409.c109
-rw-r--r--drivers/ide/buddha.c2
-rw-r--r--drivers/ide/cmd640.c2
-rw-r--r--drivers/ide/cmd64x.c203
-rw-r--r--drivers/ide/cs5530.c21
-rw-r--r--drivers/ide/cy82c693.c15
-rw-r--r--drivers/ide/dtc2278.c2
-rw-r--r--drivers/ide/falconide.c2
-rw-r--r--drivers/ide/gayle.c2
-rw-r--r--drivers/ide/hd.c2
-rw-r--r--drivers/ide/hpt34x.c123
-rw-r--r--drivers/ide/hpt366.c125
-rw-r--r--drivers/ide/ht6560b.c2
-rw-r--r--drivers/ide/icside.c2
-rw-r--r--drivers/ide/ide-cd.c23
-rw-r--r--drivers/ide/ide-cd.h2
-rw-r--r--drivers/ide/ide-disk.c21
-rw-r--r--drivers/ide/ide-dma.c28
-rw-r--r--drivers/ide/ide-features.c2
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/ide-geometry.c6
-rw-r--r--drivers/ide/ide-pci.c4
-rw-r--r--drivers/ide/ide-pmac.c4
-rw-r--r--drivers/ide/ide-pnp.c2
-rw-r--r--drivers/ide/ide-probe.c2
-rw-r--r--drivers/ide/ide-proc.c2
-rw-r--r--drivers/ide/ide-tape.c2
-rw-r--r--drivers/ide/ide.c33
-rw-r--r--drivers/ide/ide_modes.h2
-rw-r--r--drivers/ide/ns87415.c15
-rw-r--r--drivers/ide/opti621.c2
-rw-r--r--drivers/ide/pdc202xx.c311
-rw-r--r--drivers/ide/piix.c45
-rw-r--r--drivers/ide/q40ide.c2
-rw-r--r--drivers/ide/qd6580.c2
-rw-r--r--drivers/ide/rapide.c2
-rw-r--r--drivers/ide/rz1000.c2
-rw-r--r--drivers/ide/sis5513.c240
-rw-r--r--drivers/ide/sl82c105.c2
-rw-r--r--drivers/ide/trm290.c9
-rw-r--r--drivers/ide/umc8672.c2
-rw-r--r--drivers/ide/via82cxxx.c186
-rw-r--r--drivers/ieee1394/Config.in3
-rw-r--r--drivers/ieee1394/csr.c168
-rw-r--r--drivers/ieee1394/csr.h1
-rw-r--r--drivers/ieee1394/highlevel.c61
-rw-r--r--drivers/ieee1394/highlevel.h41
-rw-r--r--drivers/ieee1394/ieee1394.h99
-rw-r--r--drivers/ieee1394/ieee1394_core.c161
-rw-r--r--drivers/ieee1394/ieee1394_core.h17
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c37
-rw-r--r--drivers/ieee1394/ieee1394_types.h3
-rw-r--r--drivers/ieee1394/ohci1394.c195
-rw-r--r--drivers/ieee1394/ohci1394.h35
-rw-r--r--drivers/ieee1394/pcilynx.c78
-rw-r--r--drivers/ieee1394/pcilynx.h118
-rw-r--r--drivers/ieee1394/raw1394.c161
-rw-r--r--drivers/ieee1394/raw1394.h7
-rw-r--r--drivers/isdn/Config.in10
-rw-r--r--drivers/isdn/Makefile4
-rw-r--r--drivers/isdn/avmb1/Makefile133
-rw-r--r--drivers/isdn/avmb1/avm_cs.c528
-rw-r--r--drivers/isdn/avmb1/b1dma.c2
-rw-r--r--drivers/isdn/avmb1/b1pcmcia.c9
-rw-r--r--drivers/isdn/avmb1/c4.c110
-rw-r--r--drivers/isdn/avmb1/capi.c1777
-rw-r--r--drivers/isdn/avmb1/capicmd.h17
-rw-r--r--drivers/isdn/avmb1/capidev.h35
-rw-r--r--drivers/isdn/avmb1/capidrv.c100
-rw-r--r--drivers/isdn/avmb1/capifs.c595
-rw-r--r--drivers/isdn/avmb1/capifs.h25
-rw-r--r--drivers/isdn/avmb1/capiutil.c23
-rw-r--r--drivers/isdn/avmb1/capiutil.h72
-rw-r--r--drivers/isdn/avmb1/kcapi.c274
-rw-r--r--drivers/isdn/divert/divert_procfs.c26
-rw-r--r--drivers/isdn/eicon/eicon_idi.c32
-rw-r--r--drivers/isdn/hisax/callc.c18
-rw-r--r--drivers/isdn/hisax/l3dss1.c131
-rw-r--r--drivers/isdn/hisax/md5sums.asc14
-rw-r--r--drivers/isdn/hisax/q931.c28
-rw-r--r--drivers/isdn/hisax/w6692.c21
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c23
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c28
-rw-r--r--drivers/isdn/isdn_audio.c29
-rw-r--r--drivers/isdn/isdn_common.c8
-rw-r--r--drivers/isdn/isdn_concap.c20
-rw-r--r--drivers/isdn/isdn_net.c420
-rw-r--r--drivers/isdn/isdn_net.h106
-rw-r--r--drivers/isdn/isdn_ppp.c210
-rw-r--r--drivers/isdn/isdn_v110.c167
-rw-r--r--drivers/isdn/isdn_v110.h22
-rw-r--r--drivers/net/3c509.c4
-rw-r--r--drivers/net/3c515.c4
-rw-r--r--drivers/net/3c59x.c5
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/8390.c87
-rw-r--r--drivers/net/Config.in14
-rw-r--r--drivers/net/defxx.c2
-rw-r--r--drivers/net/epic100.c14
-rw-r--r--drivers/net/irda/irport.c8
-rw-r--r--drivers/net/irda/irtty.c12
-rw-r--r--drivers/net/irda/nsc-ircc.c4
-rw-r--r--drivers/net/irda/toshoboe.c4
-rw-r--r--drivers/net/irda/w83977af_ir.c4
-rw-r--r--drivers/net/ne2k-pci.c294
-rw-r--r--drivers/net/net_init.c28
-rw-r--r--drivers/net/pcmcia/3c575_cb.c724
-rw-r--r--drivers/net/pcmcia/Config.in1
-rw-r--r--drivers/net/pcmcia/Makefile3
-rw-r--r--drivers/net/pcmcia/xircom_tulip_cb.c3153
-rw-r--r--drivers/net/plip.c3
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/sgiseeq.c3
-rw-r--r--drivers/net/shaper.c4
-rw-r--r--drivers/net/starfire.c351
-rw-r--r--drivers/net/tlan.c15
-rw-r--r--drivers/net/tokenring/lanstreamer.c344
-rw-r--r--drivers/net/tokenring/lanstreamer.h11
-rw-r--r--drivers/net/tulip/21142.c1
-rw-r--r--drivers/net/tulip/eeprom.c43
-rw-r--r--drivers/net/tulip/interrupt.c6
-rw-r--r--drivers/net/tulip/media.c1
-rw-r--r--drivers/net/tulip/pnic.c1
-rw-r--r--drivers/net/tulip/timer.c7
-rw-r--r--drivers/net/tulip/tulip.h29
-rw-r--r--drivers/net/tulip/tulip_core.c109
-rw-r--r--drivers/net/via-rhine.c421
-rw-r--r--drivers/net/wan/Config.in6
-rw-r--r--drivers/parport/ChangeLog9
-rw-r--r--drivers/parport/init.c6
-rw-r--r--drivers/parport/parport_pc.c7
-rw-r--r--drivers/pci/pci.c52
-rw-r--r--drivers/pcmcia/ti113x.h26
-rw-r--r--drivers/pcmcia/yenta.c19
-rw-r--r--drivers/pnp/isapnp.c47
-rw-r--r--drivers/sbus/char/envctrl.c13
-rw-r--r--drivers/sbus/char/sunmouse.c15
-rw-r--r--drivers/sbus/char/sunserial.c4
-rw-r--r--drivers/scsi/Makefile8
-rw-r--r--drivers/scsi/advansys.c26
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/qlogicisp.c10
-rw-r--r--drivers/scsi/scsi.c8
-rw-r--r--drivers/scsi/st.c20
-rw-r--r--drivers/scsi/u14-34f.c2
-rw-r--r--drivers/sound/ac97_codec.c2
-rw-r--r--drivers/sound/awe_hw.h4
-rw-r--r--drivers/sound/awe_wave.c1692
-rw-r--r--drivers/sound/awe_wave.h18
-rw-r--r--drivers/sound/sb.h1
-rw-r--r--drivers/sound/sb_card.c237
-rw-r--r--drivers/sound/sb_common.c5
-rw-r--r--drivers/sound/sb_mixer.c6
-rw-r--r--drivers/usb/Config.in1
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/hid-debug.h1
-rw-r--r--drivers/usb/hid.c54
-rw-r--r--drivers/usb/hid.h8
-rw-r--r--drivers/usb/keybdev.c21
-rw-r--r--drivers/usb/mdc800.c931
-rw-r--r--drivers/usb/mousedev.c4
-rw-r--r--drivers/usb/pegasus.c42
-rw-r--r--drivers/usb/serial/Makefile-keyspan_pda_fw2
-rw-r--r--drivers/usb/serial/keyspan_pda.S1124
-rw-r--r--drivers/usb/serial/usb-serial.c857
-rw-r--r--drivers/usb/serial/usb-serial.h116
-rw-r--r--drivers/usb/uhci.c21
-rw-r--r--drivers/usb/usb-ohci.c97
-rw-r--r--drivers/usb/usb-ohci.h137
-rw-r--r--drivers/usb/usb-storage.c324
-rw-r--r--drivers/usb/usb-uhci.c32
-rw-r--r--drivers/usb/usb.c49
-rw-r--r--drivers/usb/wacom.c485
-rw-r--r--drivers/video/Makefile8
-rw-r--r--drivers/video/amifb.c26
-rw-r--r--drivers/video/cgthreefb.c10
-rw-r--r--drivers/video/macmodes.c121
-rw-r--r--drivers/video/modedb.c15
-rw-r--r--drivers/video/offb.c109
-rw-r--r--drivers/video/riva/fbdev.c2
-rw-r--r--fs/adfs/inode.c2
-rw-r--r--fs/affs/file.c2
-rw-r--r--fs/bfs/file.c2
-rw-r--r--fs/binfmt_aout.c55
-rw-r--r--fs/binfmt_elf.c106
-rw-r--r--fs/binfmt_em86.c23
-rw-r--r--fs/binfmt_misc.c15
-rw-r--r--fs/binfmt_script.c19
-rw-r--r--fs/buffer.c2
-rw-r--r--fs/coda/dir.c2
-rw-r--r--fs/cramfs/inode.c7
-rw-r--r--fs/dcache.c71
-rw-r--r--fs/devfs/Makefile2
-rw-r--r--fs/exec.c183
-rw-r--r--fs/ext2/balloc.c30
-rw-r--r--fs/ext2/ialloc.c7
-rw-r--r--fs/ext2/inode.c2
-rw-r--r--fs/ext2/super.c34
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/fifo.c81
-rw-r--r--fs/hfs/inode.c2
-rw-r--r--fs/hpfs/file.c2
-rw-r--r--fs/lockd/clntproc.c8
-rw-r--r--fs/lockd/mon.c2
-rw-r--r--fs/minix/inode.c2
-rw-r--r--fs/nfs/Makefile2
-rw-r--r--fs/nfs/dir.c62
-rw-r--r--fs/nfs/file.c4
-rw-r--r--fs/nfs/flushd.c304
-rw-r--r--fs/nfs/inode.c57
-rw-r--r--fs/nfs/nfs2xdr.c49
-rw-r--r--fs/nfs/nfsroot.c5
-rw-r--r--fs/nfs/proc.c8
-rw-r--r--fs/nfs/read.c10
-rw-r--r--fs/nfs/write.c1667
-rw-r--r--fs/nfsd/export.c5
-rw-r--r--fs/nfsd/nfs3xdr.c1
-rw-r--r--fs/nfsd/nfsctl.c42
-rw-r--r--fs/nfsd/nfsproc.c5
-rw-r--r--fs/nfsd/nfssvc.c26
-rw-r--r--fs/nfsd/stats.c45
-rw-r--r--fs/nfsd/vfs.c9
-rw-r--r--fs/ntfs/fs.c2
-rw-r--r--fs/ntfs/inode.c4
-rw-r--r--fs/open.c42
-rw-r--r--fs/openpromfs/inode.c7
-rw-r--r--fs/partitions/msdos.c15
-rw-r--r--fs/pipe.c126
-rw-r--r--fs/proc/array.c3
-rw-r--r--fs/qnx4/inode.c2
-rw-r--r--fs/romfs/inode.c9
-rw-r--r--fs/smbfs/file.c2
-rw-r--r--fs/super.c1
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/udf/balloc.c102
-rw-r--r--fs/udf/file.c6
-rw-r--r--fs/udf/inode.c23
-rw-r--r--fs/udf/lowlevel.c22
-rw-r--r--fs/udf/misc.c8
-rw-r--r--fs/udf/namei.c4
-rw-r--r--fs/udf/super.c84
-rw-r--r--fs/udf/udf_sb.h6
-rw-r--r--fs/udf/udfdecl.h4
-rw-r--r--fs/udf/unicode.c3
-rw-r--r--fs/ufs/inode.c2
-rw-r--r--include/asm-alpha/fpu.h57
-rw-r--r--include/asm-alpha/pci.h23
-rw-r--r--include/asm-alpha/pgtable.h10
-rw-r--r--include/asm-alpha/sfp-machine.h4
-rw-r--r--include/asm-alpha/smplock.h2
-rw-r--r--include/asm-alpha/unistd.h1
-rw-r--r--include/asm-arm/smplock.h2
-rw-r--r--include/asm-generic/smplock.h2
-rw-r--r--include/asm-i386/cache.h8
-rw-r--r--include/asm-i386/smplock.h2
-rw-r--r--include/asm-i386/string.h7
-rw-r--r--include/asm-i386/system.h3
-rw-r--r--include/asm-i386/uaccess.h2
-rw-r--r--include/asm-ia64/smplock.h2
-rw-r--r--include/asm-m68k/smplock.h2
-rw-r--r--include/asm-mips/smplock.h4
-rw-r--r--include/asm-mips64/smplock.h8
-rw-r--r--include/asm-ppc/elf.h2
-rw-r--r--include/asm-ppc/mman.h12
-rw-r--r--include/asm-ppc/smplock.h2
-rw-r--r--include/asm-ppc/types.h10
-rw-r--r--include/asm-sparc/asm_offsets.h60
-rw-r--r--include/asm-sparc/pgtable.h11
-rw-r--r--include/asm-sparc/smplock.h2
-rw-r--r--include/asm-sparc64/page.h5
-rw-r--r--include/asm-sparc64/smplock.h2
-rw-r--r--include/linux/atm_idt77105.h14
-rw-r--r--include/linux/atm_suni.h11
-rw-r--r--include/linux/atmdev.h143
-rw-r--r--include/linux/awe_voice.h5
-rw-r--r--include/linux/binfmts.h7
-rw-r--r--include/linux/capi.h34
-rw-r--r--include/linux/circ_buf.h32
-rw-r--r--include/linux/dcache.h3
-rw-r--r--include/linux/ext2_fs.h5
-rw-r--r--include/linux/fb.h29
-rw-r--r--include/linux/fs.h9
-rw-r--r--include/linux/hdreg.h14
-rw-r--r--include/linux/ide.h2
-rw-r--r--include/linux/input.h7
-rw-r--r--include/linux/isapnp.h26
-rw-r--r--include/linux/isdn.h51
-rw-r--r--include/linux/isdn_ppp.h3
-rw-r--r--include/linux/kernelcapi.h29
-rw-r--r--include/linux/linkage.h12
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/linux/nfs.h26
-rw-r--r--include/linux/nfs_flushd.h64
-rw-r--r--include/linux/nfs_fs.h129
-rw-r--r--include/linux/nfs_fs_i.h18
-rw-r--r--include/linux/nfs_fs_sb.h1
-rw-r--r--include/linux/nfsd/stats.h13
-rw-r--r--include/linux/nfsd/syscall.h7
-rw-r--r--include/linux/pci.h3
-rw-r--r--include/linux/pci_ids.h6
-rw-r--r--include/linux/pipe_fs_i.h9
-rw-r--r--include/linux/serial.h6
-rw-r--r--include/linux/serialP.h27
-rw-r--r--include/linux/smp_lock.h1
-rw-r--r--include/linux/sonet.h45
-rw-r--r--include/linux/sunrpc/auth.h14
-rw-r--r--include/linux/sunrpc/clnt.h24
-rw-r--r--include/linux/sunrpc/sched.h34
-rw-r--r--include/linux/sunrpc/xprt.h57
-rw-r--r--include/linux/udf_fs.h1
-rw-r--r--include/linux/udf_fs_sb.h12
-rw-r--r--include/linux/usb.h1
-rw-r--r--include/net/irda/irda_device.h19
-rw-r--r--include/net/irda/parameters.h12
-rw-r--r--ipc/shm.c56
-rw-r--r--kernel/Makefile5
-rw-r--r--kernel/ksyms.c21
-rw-r--r--kernel/ptrace.c4
-rw-r--r--kernel/sched.c7
-rw-r--r--kernel/signal.c94
-rw-r--r--kernel/sysctl.c69
-rw-r--r--mm/filemap.c2
-rw-r--r--mm/highmem.c13
-rw-r--r--mm/memory.c30
-rw-r--r--mm/mmap.c10
-rw-r--r--mm/page_alloc.c38
-rw-r--r--mm/vmalloc.c5
-rw-r--r--mm/vmscan.c4
-rw-r--r--net/802/tr.c10
-rw-r--r--net/atm/Makefile9
-rw-r--r--net/atm/addr.c54
-rw-r--r--net/atm/addr.h3
-rw-r--r--net/atm/atm_misc.c28
-rw-r--r--net/atm/clip.c13
-rw-r--r--net/atm/common.c181
-rw-r--r--net/atm/ipcommon.c26
-rw-r--r--net/atm/ipcommon.h6
-rw-r--r--net/atm/lane_mpoa_init.c12
-rw-r--r--net/atm/lec.c80
-rw-r--r--net/atm/lec.h9
-rw-r--r--net/atm/mpc.c8
-rw-r--r--net/atm/proc.c15
-rw-r--r--net/atm/pvc.c9
-rw-r--r--net/atm/raw.c22
-rw-r--r--net/atm/resources.c14
-rw-r--r--net/atm/signaling.c42
-rw-r--r--net/atm/signaling.h1
-rw-r--r--net/atm/svc.c170
-rw-r--r--net/bridge/br.c19
-rw-r--r--net/bridge/br_input.c8
-rw-r--r--net/bridge/br_private.h4
-rw-r--r--net/core/dev.c2
-rw-r--r--net/ipv4/ipip.c2
-rw-r--r--net/ipv4/netfilter/Makefile6
-rw-r--r--net/ipv4/netfilter/ip_conntrack_ftp.c3
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c3
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c3
-rw-r--r--net/ipv4/netfilter/ip_queue.c2
-rw-r--r--net/ipv4/route.c8
-rw-r--r--net/ipv4/tcp.c15
-rw-r--r--net/ipv4/tcp_input.c11
-rw-r--r--net/ipv4/tcp_ipv4.c4
-rw-r--r--net/ipv6/sit.c2
-rw-r--r--net/irda/ircomm/ircomm_param.c66
-rw-r--r--net/irda/irda_device.c7
-rw-r--r--net/irda/irlan/irlan_eth.c7
-rw-r--r--net/irda/irttp.c6
-rw-r--r--net/irda/parameters.c20
-rw-r--r--net/irda/qos.c41
-rw-r--r--net/khttpd/main.c3
-rw-r--r--net/khttpd/security.c3
-rw-r--r--net/sched/sch_atm.c25
-rw-r--r--net/sunrpc/auth.c121
-rw-r--r--net/sunrpc/auth_null.c10
-rw-r--r--net/sunrpc/auth_unix.c21
-rw-r--r--net/sunrpc/clnt.c359
-rw-r--r--net/sunrpc/pmap_clnt.c3
-rw-r--r--net/sunrpc/sched.c396
-rw-r--r--net/sunrpc/sunrpc_syms.c6
-rw-r--r--net/sunrpc/xprt.c943
-rw-r--r--scripts/mkdep.c29
501 files changed, 23794 insertions, 13285 deletions
diff --git a/CREDITS b/CREDITS
index e20a1f141..b5436e948 100644
--- a/CREDITS
+++ b/CREDITS
@@ -891,6 +891,10 @@ S: Fichtenweg 3/511
S: 72076 Tübingen
S: Germany
+N: Justin Guyett
+E: jguyett@andrew.cmu.edu
+D: via-rhine net driver hacking
+
N: Danny ter Haar
E: dth@cistron.nl
D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;)
@@ -1143,6 +1147,7 @@ E: nkbj@image.dk
W: http://www.image.dk/~nkbj
D: 4.4BSD and NeXTstep filesystem support in the old ufs.
D: Openstep filesystem and NeXTstep CDROM support in the new ufs.
+D: Replace CPU==[3-6]86 and __i386__ submodel flags by configuration options.
D: Danish HOWTO, Linux+FreeBSD mini-HOWTO.
S: Dr. Holsts Vej 34, lejl. 164
S: DK-8230 Åbyhøj
@@ -1327,6 +1332,13 @@ N: Andreas S. Krebs
E: akrebs@altavista.net
D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards
+N: Greg Kroah-Hartman
+E: greg@kroah.com
+W: http://www.kroah.com/linux-usb/
+D: USB Serial Converter driver framework, USB Handspring Visor driver
+D: ConnectTech WHITEHeat USB driver, Generic USB Serial driver
+D: bits and pieces of USB core code.
+
N: Russell Kroll
E: rkroll@exploits.org
W: http://www.exploits.org/
@@ -1360,10 +1372,13 @@ S: D-91080 Uttenreuth
S: Germany
N: Jaroslav Kysela
-E: perex@jcu.cz
-W: http://www.pf.jcu.cz/~perex
+E: perex@suse.cz
+W: http://www.perex.cz
D: Original Author and Maintainer for HP 10/100 Mbit Network Adapters
-S: Unix Centre of Pedagogical Faculty, University of South Bohemia
+D: ISA PnP
+S: Sindlovy Dvory 117
+S: 370 01 Ceske Budejovice
+S: Czech Republic
N: Bas Laarhoven
E: bas@vimec.nl
@@ -1947,6 +1962,16 @@ S: Lazarettstrasse 8
S: 91054 Erlangen
S: Germany
+N: Giuliano Procida
+E: myxie@debian.org,gprocida@madge.com
+D: Madge Ambassador driver (Collage 155 Server ATM adapter)
+D: Madge Horizon driver (Collage 25 and 155 Client ATM adapters)
+P: 1024/93898735 D3 9E F4 F7 6D 8D 2F 3A 38 BA 06 7C 2B 33 43 7D
+S: Madge Networks
+S: Framewood Road
+S: Wexham SL3 6PJ
+S: United Kingdom
+
N: Daniel Quinlan
E: quinlan@pathname.com
W: http://www.pathname.com/~quinlan/
@@ -2037,6 +2062,14 @@ S: Gaildorfer Str. 27
S: 7000 Stuttgart 50
S: Germany
+N: Christoph Rohland
+E: hans-christoph.rohland@sap.com
+E: ch.rohland@gmx.net
+D: shm fs, SYSV semaphores, af_unix
+S: Neue Heimat Str. 8
+S: D-68789 St.Leon-Rot
+S: Germany
+
N: Stephen Rothwell
E: sfr@linuxcare.com
W: http://linuxcare.com.au/sfr
@@ -2455,6 +2488,7 @@ D: Amiga Zorro maintainer
D: Amiga Buddha and Catweasel chipset IDE
D: Atari Falcon chipset IDE
D: Amiga Gayle chipset IDE
+D: mipsel NEC DDB Vrc-5074
S: C. Huysmansstraat 12
S: B-3128 Baal
S: Belgium
@@ -2599,6 +2633,10 @@ S: Eichenweg 16
S: 73650 Winterbach
S: Germany
+N: Urban Widmark
+E: urban@svenskatest.se
+D: via-rhine, misc net driver hacking
+
N: Marco van Wieringen
E: mvw@planets.elm.net
D: Author of process accounting and diskquota
diff --git a/Documentation/Changes b/Documentation/Changes
index 0a06bebdf..73511d74a 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -73,8 +73,11 @@ General Information
===================
To use System V shared memory, you have to mount the shm filesystem
-somewhere and put the mountpoint into /proc/sys/kernel/shmpath.
-Default is /var/shm.
+somewhere. You can do that automatically by adding this line to /etc/fstab:
+
+none /var/shm shm defaults 0 0
+
+Remember to create the mountpoint directory; it does not have to be /var/shm.
<CTRL><ALT><DEL> now performs a cold reboot instead of a warm reboot
for increased hardware compatibility. If you want a warm reboot and
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 6d2a38183..08acaf9f3 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -186,10 +186,22 @@ High Memory support
CONFIG_NOHIGHMEM
If you are compiling a kernel which will never run on a machine
with more than 1 Gigabyte total physical RAM, answer "off"
- here (default choice).
+ here (default choice). This will result in the old "3GB/1GB"
+ virtual/physical memory split. 3BG are mapped so as each processus
+ sees a 3GB virtual memory space.
+ The remaining part of the 4G virtual memory space is used by the
+ kernel to 'permanently map' as much physical memory as possible.
+ Certain types of applications perform better if there is more
+ 'permanently mapped' kernel memory.
+ Certain types of applications (eg. database servers) perform
+ better if they have as much virtual memory per process as possible.
Linux can use up to 64 Gigabytes of physical memory on x86 systems.
- High memory is all the physical RAM that could not be directly
+ However 32-bit x86 processors have only 4 Gigabytes of virtual memory
+ space.
+
+ Any potentially remaining part of physical memory is called
+ 'high memory' that is all the physical RAM that could not be directly
mapped by the kernel - ie. 3GB if there is 4GB RAM in the system,
7GB if there is 8GB RAM in the system.
@@ -202,6 +214,13 @@ CONFIG_NOHIGHMEM
processors (PPro and better). NOTE: The "64GB" kernel will not
boot CPUs that not support PAE!
+ The actual amount of total physical memory will either be
+ autodetected or can be forced by using a kernel command line option
+ such as "mem=256M". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time. The lilo procedure is also explained in the
+ SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto .)
+
Normal PC floppy disk support
CONFIG_BLK_DEV_FD
If you want to use the floppy disk drive(s) of your PC under Linux,
@@ -372,7 +391,7 @@ CONFIG_BLK_DEV_IDE
Useful information about large (>540 MB) IDE disks, multiple
interfaces, what to do if ATA/IDE devices are not automatically
detected, sound card ATA/IDE ports, module support, and other topics, is
- contained in Documentation/ata-ide.txt. For detailed information about
+ contained in Documentation/ide.txt. For detailed information about
hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO,
available from http://www.linuxdoc.org/docs.html#howto .
@@ -494,7 +513,7 @@ CONFIG_BLK_DEV_IDETAPE
along with other IDE devices, as "hdb" or "hdc", or something
similar, and will be mapped to a character device such as "ht0"
(check the boot messages with dmesg). Be sure to consult the
- drivers/block/ide-tape.c and Documentation/ide.txt files for usage
+ drivers/ide/ide-tape.c and Documentation/ide.txt files for usage
information.
If you want to compile the driver as a module ( = code which can be
@@ -627,7 +646,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI
the latest version of the hdparm utility from
ftp://metalab.unc.edu/pub/Linux/system/hardware/ .
- Read the comments at the beginning of drivers/block/ide-dma.c and the
+ Read the comments at the beginning of drivers/ide/ide-dma.c and the
file Documentation/ide.txt for more information.
It is safe to say Y to this question.
@@ -707,12 +726,12 @@ CONFIG_BLK_DEV_AEC6210
should say Y here, and preferably also to "Use DMA by default when
available".
- Please read the comments at the top of drivers/block/aec6210.c
+ Please read the comments at the top of drivers/ide/aec6210.c
If you say Y here, then say Y to "Use DMA by default when available" as well.
AEC6210 Tuning support (WIP)
CONFIG_AEC6210_TUNING
- Please read the comments at the top of drivers/block/aec6210.c
+ Please read the comments at the top of drivers/ide/aec6210.c
If unsure, say N.
ALI M15x3 chipset support
@@ -721,16 +740,28 @@ CONFIG_BLK_DEV_ALI15X3
1535, 1535D onboard chipsets. It also tests for Simplex mode and
enables normal dual channel support.
- Please read the comments at the top of drivers/block/alim15x3.c
+ Please read the comments at the top of drivers/ide/alim15x3.c
If you say Y here, then say Y to "Use DMA by default when available" as well.
If unsure, say N.
+ALI M15x3 WDC support (DANGEROUS)
+CONFIG_WDC_ALI15X3
+ This allows for UltraDMA support for WDC drives that ignore CRC checking.
+ You are a fool for enabling this option, but there have been requests.
+ DO NOT COMPLAIN IF YOUR DRIVE HAS FS CORUPTION, IF YOU ENABLE THIS!
+ No one will listen, just laugh for ignoring this SERIOUS WARNING.
+
+ Using this option can allow WDC drives to run at ATA-4/5 transfer rates with
+ only an ATA-2 support structure.
+
+ SAY NO!
+
AMD7409 chipset support (EXPERIMENTAL)
CONFIG_BLK_DEV_AMD7409
This driver ensures (U)DMA support for AMD756 Viper chipset.
- Please read the comments at the top of drivers/block/amd7409.c
+ Please read the comments at the top of drivers/ide/amd7409.c
If you say Y here, then say Y to "Use DMA by default when available" as well.
If unsure, say N.
@@ -776,7 +807,7 @@ CONFIG_BLK_DEV_HPT34X
HPT34X AUTODMA support (WIP)
CONFIG_HPT34X_AUTODMA
This is a dangerous thing to attempt currently!
- Please read the comments at the top of drivers/block/hpt34x.c
+ Please read the comments at the top of drivers/ide/hpt34x.c
If you say Y here, then say Y to "Use DMA by default when available" as well.
If unsure, say N.
@@ -795,7 +826,7 @@ CONFIG_BLK_DEV_HPT366
the ide-probe at boot. It is reported to support DVD II drives, by the
manufacturer.
- Please read the comments at the top of drivers/block/hpt366.c
+ Please read the comments at the top of drivers/ide/hpt366.c
If you say Y here, then say Y to "Use DMA by default when available" as well.
HPT366 Fast Interrupts (WIP)
@@ -813,12 +844,12 @@ CONFIG_BLK_DEV_NS87415
This driver adds detection and support for the NS87415 chip
(used in SPARC64, among others).
- Please read the comments at the top of drivers/block/ns87415.c.
+ Please read the comments at the top of drivers/ide/ns87415.c.
OPTi 82C621 enhanced support (EXPERIMENTAL)
CONFIG_BLK_DEV_OPTI621
This is a driver for the OPTi 82C621 EIDE controller.
- Please read the comments at the top of drivers/block/opti621.c.
+ Please read the comments at the top of drivers/ide/opti621.c.
Intel PIIXn chipsets support
CONFIG_BLK_DEV_PIIX
@@ -827,7 +858,7 @@ CONFIG_BLK_DEV_PIIX
PIO 0-4 mode settings, this allows dynamic tuning of the chipset
via the standard end-user tool 'hdparm'.
- Please read the comments at the top of drivers/block/piix.c
+ Please read the comments at the top of drivers/ide/piix.c
Should also include "PIIXn Tuning support" CONFIG_PIIX_TUNING
If unsure, say Y.
@@ -866,7 +897,7 @@ CONFIG_BLK_DEV_PDC202XX
1.11 or newer required.
If you say Y here, then say Y to "Use DMA by default when available" as well.
- Please read the comments at the top of drivers/block/pdc202xx.c
+ Please read the comments at the top of drivers/ide/pdc202xx.c
If unsure, say N.
@@ -876,7 +907,7 @@ CONFIG_PDC202XX_BURST
for PDC20246/Ultra33 that has BIOS setup failures when using 3 or
more cards.
- Please read the comments at the top of drivers/block/pdc202xx.c
+ Please read the comments at the top of drivers/ide/pdc202xx.c
If unsure, say N.
@@ -898,7 +929,7 @@ CONFIG_BLK_DEV_TRM290
This driver adds support for bus master DMA transfers
using the Tekram TRM290 PCI IDE chip. Volunteers are
needed for further tweaking and development.
- Please read the comments at the top of drivers/block/trm290.c.
+ Please read the comments at the top of drivers/ide/trm290.c.
VIA82CXXX chipset support (EXPERIMENTAL)
CONFIG_BLK_DEV_VIA82CXXX
@@ -909,7 +940,7 @@ CONFIG_BLK_DEV_VIA82CXXX
If no command line is provided, it will try to set fifo configuration
at its best. It will allow you to get a proc/ide/via display
(while running a "cat") provided you enabled "proc" support.
- Please read the comments at the top of drivers/block/via82cxxx.c
+ Please read the comments at the top of drivers/ide/via82cxxx.c
If you say Y here, then say Y to "Use DMA by default when available" as well.
@@ -943,14 +974,14 @@ CONFIG_BLK_DEV_ALI14XX
boot parameter. It enables support for the secondary IDE interface
of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
I/O speeds to be set as well. See the files Documentation/ide.txt
- and drivers/block/ali14xx.c for more info.
+ and drivers/ide/ali14xx.c for more info.
DTC-2278 support
CONFIG_BLK_DEV_DTC2278
This driver is enabled at runtime using the "ide0=dtc2278" kernel
boot parameter. It enables support for the secondary IDE interface
of the DTC-2278 card, and permits faster I/O speeds to be set as
- well. See the Documentation/ide.txt and drivers/block/dtc2278.c
+ well. See the Documentation/ide.txt and drivers/ide/dtc2278.c
files for more info.
Holtek HT6560B support
@@ -958,7 +989,7 @@ CONFIG_BLK_DEV_HT6560B
This driver is enabled at runtime using the "ide0=ht6560b" kernel
boot parameter. It enables support for the secondary IDE interface
of the Holtek card, and permits faster I/O speeds to be set as well.
- See the Documentation/ide.txt and drivers/block/ht6560b.c files for
+ See the Documentation/ide.txt and drivers/ide/ht6560b.c files for
more info.
PROMISE DC4030 support (EXPERIMENTAL)
@@ -969,13 +1000,13 @@ CONFIG_BLK_DEV_PDC4030
attached to the secondary interface. CDROM and TAPE devices are not
supported yet. This driver is enabled at runtime using the
"ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt
- and drivers/block/pdc4030.c files for more info.
+ and drivers/ide/pdc4030.c files for more info.
QDI QD6580 support
CONFIG_BLK_DEV_QD6580
This driver is enabled at runtime using the "ide0=qd6580" kernel
boot parameter. It permits faster I/O speeds to be set. See the
- files Documentation/ide.txt and drivers/block/qd6580.c for more
+ files Documentation/ide.txt and drivers/ide/qd6580.c for more
info.
UMC 8672 support
@@ -983,7 +1014,7 @@ CONFIG_BLK_DEV_UMC8672
This driver is enabled at runtime using the "ide0=umc8672" kernel
boot parameter. It enables support for the secondary IDE interface
of the UMC-8672, and permits faster I/O speeds to be set as well.
- See the files Documentation/ide.txt and drivers/block/umc8672.c for
+ See the files Documentation/ide.txt and drivers/ide/umc8672.c for
more info.
Amiga builtin Gayle IDE interface support
@@ -2135,6 +2166,14 @@ CONFIG_HUB6
Say Y here to enable support in the dumb serial driver to support
the HUB6 card.
+Support for hot-pluggable devices
+CONFIG_HOTPLUG
+ Say Y here to enable support for hot plugin of certain hardware such as
+ PCMCIA cards and the like.
+
+ At this moment, few drivers support it, but as they get converted to use the
+ new ressource allocator/manager, their number will increase.
+
PCMCIA serial device support
CONFIG_PCMCIA_SERIAL_CS
Say Y here to enable support for 16-bit PCMCIA serial devices,
@@ -2728,6 +2767,27 @@ S3 Trio frame buffer device support
CONFIG_FB_S3TRIO
If you have a S3 Trio say Y. Say N for S3 Virge.
+3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)
+CONFIG_FB_3DFX
+ This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 chips.
+ Say Y if you have such a graphics board.
+
+ The driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want). The
+ module will be called tdfxfb.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
+nVidia Riva support (EXPERIMENTAL)
+CONFIG_FB_RIVA
+ This driver supports graphics boards with the nVidia Riva (aka TNTx)
+ chips.
+ Say Y if you have such a graphics board.
+
+ The driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want). The
+ module will be called rivafb.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
ATI Mach64 display support (EXPERIMENTAL)
CONFIG_FB_ATY
This driver supports graphics boards with the ATI Mach64 chips.
@@ -2808,19 +2868,36 @@ CONFIG_FB_VGA16
running kernel whenever you want), say M here and read
Documentation/modules.txt. The module will be called vga16fb.o.
+Select other compiled-in fonts
+CONFIG_FBCON_FONTS
+ Say Y here if you would like to use fonts other than the default your frame
+ buffer console usually use.
+
+ Note that the answer to this question won't directly affect the kernel:
+ saying N will just cause this configure script to skip all the questions
+ about foreign fonts.
+
+ If unsure, say N (the default choices are safe).
+
VGA 8x16 font
CONFIG_FONT_8x16
This is the "high resolution" font for the VGA frame buffer (the one
- provided by the text console 80x25 mode.
+ provided by the VGA text console 80x25 mode.
+
+ If unsure, say Y.
Support only 8 pixels wide fonts
CONFIG_FBCON_FONTWIDTH8_ONLY
Answer Y here will make the kernel provide only the 8x8 fonts (these
are the less readable).
+ If unsure, say N.
+
Sparc console 8x16 font
CONFIG_FONT_SUN8x16
- This is the high resolution console font for Sun machines. Say Y.
+ This is the high resolution console font for Sun machines.
+
+ Say Y.
Sparc console 12x22 font (not supported by all drivers)
CONFIG_FONT_SUN12x22
@@ -2834,6 +2911,7 @@ CONFIG_FONT_8x8
provided by the text console 80x50 (and higher) modes.
Note this is a poor quality font. The VGA 8x16 font is quite a lot
more readable.
+
Given the resolution provided by the frame buffer device, answer N
here is safe.
@@ -2844,13 +2922,25 @@ CONFIG_FB_COMPAT_XPMAC
includes a server that supports the frame buffer device directly
(XF68_FBDev).
+HGA monochrome support (EXPERIMENTAL)
+Hercules mono graphics console (EXPERIMENTAL)
+CONFIG_FBCON_HGA
+ Say Y here if you have a Hercules mono graphics card.
+
+ This driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want).
+ The module will be called hgafb.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt.
+
+ As this card technology is 15 years old, most people will answer N here.
+
Matrox unified accelerated driver (EXPERIMENTAL)
CONFIG_FB_MATROX
Say Y here if you have Matrox Millennium, Matrox Millennium II,
Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
- Mystique G200, Matrox Millennium G200 or Matrox Marvel G200 video
- card in your box. At this time, support for the G100, Mystique G200
- and Marvel G200 is untested.
+ Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video or
+ Matrox G400 card in your box. At this time, support for the G100,
+ Mystique G200 and Marvel G200 is untested.
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want).
@@ -3784,6 +3874,12 @@ CONFIG_DECNET_ROUTER
See Documentation/networking/decnet.txt for more information.
+Appletalk interfaces support
+CONFIG_APPLETALK
+ AppleTalk is the way Apple computers speak to each other on a
+ network. If your Linux box is connected to such a network and you
+ want to join the conversation, say Y.
+
AppleTalk DDP
CONFIG_ATALK
AppleTalk is the way Apple computers speak to each other on a
@@ -6069,7 +6165,7 @@ CONFIG_BONDING
with a similar Bonding Linux driver, a Cisco 5500 switch or a
SunTrunking SunSoft driver.
- This is similar to the EQL driver, but it merge etherner segments instead
+ This is similar to the EQL driver, but it merge ethernet segments instead
of serial lines.
If you want to compile this as a module ( = code which can be
@@ -6718,6 +6814,17 @@ CONFIG_ECONET_NATIVE
Say Y here if you have a native Econet network card installed in
your computer.
+Wan interfaces support
+CONFIG_WAN
+ Wide Area Networks (WANs), such as X.25, frame relay and leased
+ lines, are used to interconnect Local Area Networks (LANs) over vast
+ distances with data transfer rates significantly higher than those
+ achievable with commonly used asynchronous modem connections.
+
+ Say Y here if you want to use such interconnections.
+
+ It is safe to say N. Most people won't need it.
+
WAN Router
CONFIG_WAN_ROUTER
Wide Area Networks (WANs), such as X.25, frame relay and leased
@@ -6743,6 +6850,18 @@ CONFIG_WAN_ROUTER
If unsure, say N.
+WAN router drivers
+CONFIG_WAN_ROUTER_DRIVERS
+ Wide Area Networks (WANs), such as X.25, frame relay and leased
+ lines, are used to interconnect Local Area Networks (LANs) over vast
+ distances with data transfer rates significantly higher than those
+ achievable with commonly used asynchronous modem connections.
+ Usually, a quite expensive external device called a `WAN router' is
+ needed to connect to a WAN.
+
+ Say Y here will enable the kernel to a??? as a WAN router betwenn LAN by
+ means of WAN adapters.
+
Fast switching (read help!)
CONFIG_NET_FASTROUTE
Saying Y here enables direct NIC-to-NIC (NIC = Network Interface
@@ -7037,8 +7156,14 @@ CONFIG_COSA
The module will be called cosa.o. For general information about
modules read Documentation/modules.txt.
-# Fibre Channel driver support
-# CONFIG_NET_FC
+Fibre Channel driver support
+CONFIG_NET_FC
+ Say Y here provide support for storage arrays connected to
+ the system using Fibre Optic and the "X3.269-199X Fibre Channel
+ Protocol for SCSI" specification. You'll also need the generic SCSI
+ support, as well as the drivers for the storage array itself and
+ for the interface adapter such as SOC or SOC+. This subsystem could even
+ serve for IP networking, with some code extensions. If unsure, say N.
# Interphase 5526 Tachyon chipset based adaptor support
# CONFIG_IPHASE5526
@@ -9154,6 +9279,21 @@ CONFIG_USB_DC2XX
The module will be called dc2xx.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+
+USB Mustek MDC800 Digital Camera Support
+CONFIG_USB_MDC800
+ Say Y here if you want to connect this type of still camera to
+ your computer's USB port. This driver can be used with gphoto 0.4.3
+ and higher (look at www.gphoto.org).
+ To use it create a devicenode with mknod /dev/mustek c 10 171 and
+ configure it in your software.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called mdc800.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
+
USB Mass Storage support
CONFIG_USB_STORAGE
Say Y here if you want to connect USB mass storage devices to your
@@ -9473,6 +9613,23 @@ CONFIG_VFAT_FS
say M here and read Documentation/modules.txt. The module will be
called vfat.o.
+Compressed ROM file system support
+CONFIG_CRAMFS
+ This option provides support for CramFs (Compressed ROM File System).
+ Cramfs is designed to be a simple, small, and compressed file system for ROM
+ based embedded systems.
+ CramFs is read-only, limited to 256MB file systems (with 16MB files), don't
+ support neither 16/32 bits uid/gid nor hard links. Neither are timestamps.
+ It isn't endian aware.
+
+ See Documentation/filesystems/cramfs.txt and fs/cramfs/README
+ for further information.
+
+ If you want to compile this as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called cramfs.o.
+
UMSDOS: Unix-like file system on top of standard MSDOS fs
CONFIG_UMSDOS_FS
Say Y here if you want to run Linux from within an existing DOS
@@ -9871,7 +10028,9 @@ CONFIG_PARTITION_ADVANCED
Note that the answer to this question won't directly affect the
kernel: saying N will just cause this configure script to skip all
- the questions about foreign partitioning schemes. If unsure, say N.
+ the questions about foreign partitioning schemes.
+
+ If unsure, say N.
Alpha OSF partition support
CONFIG_OSF_PARTITION
@@ -11375,11 +11534,17 @@ CONFIG_PM
This enable the kernel to lower the requested computer power by making some
devices enter in lower power levels (standy, sleep, ... modes).
Basically, this let you save power.
+
Two majors interfaces exist between the hardware and the OS, the older
Advanced Power Management (APM) and the newer Advanced Configuration and
Power Interface (ACPI).
+
Both are supported by the Linux Kernel.
+ Note that on some architectures (such as ia32), the idle task perform hlt
+ instructions which makes the CPU enter a low power mode. This can be seen as
+ the first kernel PM level.
+
Enter S1 for sleep (EXPERIMENTAL)
CONFIG_ACPI_S1_SLEEP
This enable ACPI compliant devices to enter level 1 of ACPI saving
@@ -12882,22 +13047,12 @@ CONFIG_ISDN_TTY_FAX
an ISDN-fax-machine. This must be supported by the lowlevel driver
also. See Documentation/isdn/README.fax for more information.
-AVM CAPI2.0 support
-CONFIG_ISDN_DRV_AVMB1
- This enables support for the AVM B1/T1 ISDN networking cards.In
- addition, a CAPI (Common ISDN Application Programming Interface, a
+CAPI2.0 support
+CONFIG_ISDN_CAPI
+ This provides the CAPI (Common ISDN Application Programming Interface, a
standard making it easy for programs to access ISDN hardware, see
- http://www.capi.org/; to browse the WWW, you need to have access to
- a machine on the Internet that has a program like lynx or netscape)
- interface for this card is provided. In order to use this card,
- additional firmware is necessary, which has to be downloaded into
- the card using a utility which is distributed separately. Please
- read the file Documentation/isdn/README.avmb1.
-
- This code is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called avmb1.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
+ http://www.capi.org/. This is needed for AVM's set of active ISDN
+ controllers like B1, T1, M1.
AVM B1 ISA support
CONFIG_ISDN_DRV_AVMB1_B1ISA
@@ -12907,6 +13062,10 @@ AVM B1 PCI support
CONFIG_ISDN_DRV_AVMB1_B1PCI
Enable support for the PCI version of the AVM B1 card.
+AVM B1 PCI V4 support
+CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ Enable support for the V4 version of AVM B1 PCI card.
+
AVM T1/T1-B ISA support
CONFIG_ISDN_DRV_AVMB1_T1ISA
Enable support for the AVM T1 T1B card.
@@ -12921,6 +13080,11 @@ CONFIG_ISDN_DRV_AVMB1_T1PCI
Enable support for the AVM T1 T1B card.
Note: This is a PRI card and handle 30 B-channels.
+AVM C4 support
+CONFIG_ISDN_DRV_AVMB1_C4
+ Enable support for the AVM C4 PCI card.
+ This card handle 4 BRI ISDN lines (8 channels).
+
Verbose reason code reporting (kernel size +=7K)
CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
If you say Y here, the AVM B1 driver will give verbose reasons for
@@ -13144,7 +13308,7 @@ CONFIG_IEEE1394_OHCI1394
say M here and read Documentation/modules.txt. The module will be
called ohci1394.o.
-RAW IEEE 1394 I/O support
+Raw IEEE 1394 I/O support
CONFIG_IEEE1394_RAWIO
Say Y here if you want support for the raw device. This is generally
a good idea, so you should say Y here. The raw device enables
@@ -13155,6 +13319,17 @@ CONFIG_IEEE1394_RAWIO
say M here and read Documentation/modules.txt. The module will be
called raw1394.o.
+Excessive debugging output
+CONFIG_IEEE1394_VERBOSEDEBUG
+ If you say Y here, you will get very verbose debugging logs from the
+ subsystem which includes a dump of the header of every sent and
+ received packet. This can amount to a high amount of data collected
+ in a very short time which is usually also saved to disk by the
+ system logging daemons.
+
+ Say Y if you really want or need the debugging output, everyone else
+ says N.
+
#
# m68k-specific kernel options
# Documented by Chris Lawrence <quango@themall.net> et al.
@@ -13193,6 +13368,14 @@ CONFIG_HP300
If you plan to try to use the kernel on such a machine say Y here.
Everybody else says N.
+Sun 3X support
+CONFIG_SUN3X
+ This option enables support for the Sun 3x series of workstations. Be
+ warned that this support is very experimental. You will also want to
+ say Y to 68020 support and N to the other processors below.
+
+ If you don't want to compile a kernel for a Sun 3x, say N.
+
Sun 3 support
CONFIG_SUN3
This option enables support for the Sun 3 series of workstations. Be
@@ -13256,8 +13439,8 @@ CONFIG_M68KFPU_EMU_EXTRAPREC
mantissa and round slightly incorrect, what is more then enough
for normal usage.
-Advanced processor options
-CONFIG_ADVANCED_CPU
+Advanced configuration options
+CONFIG_ADVANCED
This gives you access to some advanced options for the CPU. The
defaults should be fine for most users, but these options may make
it possible for you to improve performance somewhat if you know what
@@ -14224,45 +14407,6 @@ CONFIG_ARCH_PERSONAL_SERVER
If you have any questions or comments about the Compaq Personal
Server, send e-mail to skiff@crl.dec.com
-Virtual/Physical Memory Split
-CONFIG_1GB
- If you are compiling a kernel which will never run on a machine
- with more than 1 Gigabyte total physical RAM, answer "3GB/1GB"
- here (default choice).
-
- On 32-bit x86 systems Linux can use up to 64 Gigabytes of physical
- memory. However 32-bit x86 processors have only 4 Gigabytes of
- virtual memory space. This option specifies the maximum amount of
- virtual memory space one process can potentially use. Certain types
- of applications (eg. database servers) perform better if they have
- as much virtual memory per process as possible.
-
- The remaining part of the 4G virtual memory space is used by the
- kernel to 'permanently map' as much physical memory as possible.
- Certain types of applications perform better if there is more
- 'permanently mapped' kernel memory.
-
- [WARNING! Certain boards do not support PCI DMA to physical addresses
- bigger than 2 Gigabytes. Non-DMA-able memory must not be permanently
- mapped by the kernel, thus a 1G/3G split will not work on such boxes.]
-
- As you can see there is no 'perfect split' - the fundamental
- problem is that 4G of 32-bit virtual memory space is short. So
- you'll have to pick your own choice - depending on the application
- load of your box. A 2G/2G split is typically a good choice for a
- generic Linux server with lots of RAM.
-
- Any potentially remaining (not permanently mapped) part of physical
- memory is called 'high memory'. How much total high memory the kernel
- can handle is influenced by the (next) High Memory configuration option.
-
- The actual amount of total physical memory will either be
- autodetected or can be forced by using a kernel command line option
- such as "mem=256M". (Try "man bootparam" or see the documentation of
- your boot loader (lilo or loadlin) about how to pass options to the
- kernel at boot time. The lilo procedure is also explained in the
- SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto .)
-
Math emulation
CONFIG_NWFPE
Say Y to include the NWFPE floating point emulator in the kernel.
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 155133a0a..368f037f7 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -26,8 +26,11 @@ kernel-api.sgml: kernel-api.tmpl
$(TOPDIR)/arch/i386/kernel/mca.c \
$(TOPDIR)/arch/i386/kernel/mtrr.c \
$(TOPDIR)/drivers/char/misc.c \
- $(TOPDIR)/drivers/char/serial.c \
$(TOPDIR)/drivers/char/videodev.c \
+ $(TOPDIR)/drivers/net/net_init.c \
+ $(TOPDIR)/drivers/net/8390.c \
+ $(TOPDIR)/drivers/char/serial.c \
+ $(TOPDIR)/drivers/pci/pci.c \
$(TOPDIR)/drivers/sound/sound_core.c \
$(TOPDIR)/drivers/sound/sound_firmware.c \
$(TOPDIR)/drivers/net/wan/syncppp.c \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 96dd9ecc0..f0013b011 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -49,7 +49,7 @@
</chapter>
<chapter id="miscdev">
- <title>Miscellaneous Device</title>
+ <title>Miscellaneous Devices</title>
!Edrivers/char/misc.c
</chapter>
@@ -58,6 +58,12 @@
!Edrivers/char/videodev.c
</chapter>
+ <chapter id="netdev">
+ <title>Network devices</title>
+!Idrivers/net/net_init.c
+!Edrivers/net/8390.c
+ </chapter>
+
<chapter id="snddev">
<title>Sound Devices</title>
!Edrivers/sound/sound_core.c
@@ -89,4 +95,9 @@
!Edrivers/net/wan/z85230.c
</chapter>
+ <chapter id="pcilib">
+ <title>PCI Support Library</title>
+!Edrivers/pci/pci.c
+ </chapter>
+
</book>
diff --git a/Documentation/devices.tex b/Documentation/devices.tex
deleted file mode 100644
index f3767f5ef..000000000
--- a/Documentation/devices.tex
+++ /dev/null
@@ -1,2209 +0,0 @@
-\documentstyle{article}
-% $Id: devices.tex,v 1.14 1998/08/10 22:39:24 hpa Exp $
-% ---------------------------------------------------------------------------
-% Adopt somewhat reasonable margins, so it doesn't take a million
-% pages to print... :-) If you're actually putting this in print, you
-% may wish to change these.
-\oddsidemargin=0in
-\textwidth=6.5in
-\topmargin=0in
-\headheight=0.5in
-\headsep=0.25in
-\textheight=7.5in
-\footskip=0.75in
-\footheight=0.5in
-%
-\begin{document}
-\newcommand{\file}{\tt} % Style to use for a filename
-\newcommand{\url}{\it} % Style to use for an URL
-\newcommand{\hex}{\tt} % Style to use for a hex number
-\newcommand{\ud}{(Under development)} % Abbreviation
-\newcommand{\1}{\({}^1\)}
-\newcommand{\2}{\({}^2\)}
-\newcommand{\3}{\({}^3\)}
-\newcommand{\4}{\({}^4\)}
-\newlength{\dig}
-\settowidth{\dig}{0} % Get width of digits
-\newcommand{\num}[2]{\makebox[#1\dig][r]{#2}}
-\newcommand{\major}[4]{\num{3}{#1}#2 \> #3 \> #4 \\}
-\newcommand{\minor}[3]{\> \> \num{3}{#1} \> {\file #2} \> #3 \\}
-\newcommand{\minordots}{\> \> \> \dots \\}
-\newenvironment{devicelist}%
- {\begin{tabbing}%
-000--000 \= blockxxx \= 000 \= {\file /dev/input/keyboardxxx} \= foo \kill}%
- {\end{tabbing}}
-\newcommand{\link}[4]{{\file #1} \> {\file #2} \> #3 \> #4 \\}
-\newcommand{\vlink}[4]{{\file #1} \> {\em #2 \/} \> #3 \> #4 \\}
-\newcommand{\node}[3]{{\file #1} \> #2 \> #3 \\}
-\newcommand{\tum}{$''$}
-\newenvironment{nodelist}%
- {\begin{tabbing}%
-{\file /dev/crambamboli} \= {\file /proc/self/fd/99} \= symbolicxxx \=
-foo \kill}%
- {\end{tabbing}}
-%
-% If you reformat this document, *please* make sure this information
-% gets included! This list changes frequently, so it is crucial to
-% know the date of the revision.
-%
-\title{{\bf Linux Allocated Devices}}
-\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: August 10, 1998}
-\maketitle
-%
-\noindent
-This list is the Linux Device List, the official registry of allocated
-device numbers and {\file /dev} directory nodes for the Linux
-operating system.
-
-The latest version of this list is included with the Linux kernel
-sources in \LaTeX\ and ASCII form. It is also available separately
-from {\url ftp://ftp.kernel.org/pub/linux/docs/device-list/}. In case
-of discrepancy between the text and \LaTeX\ versions, the \LaTeX\
-version is authoritative.
-
-This document is included by reference into the Linux Filesystem
-Standard (FSSTND). The FSSTND is available from
-{\url ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/}.
-
-Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
-platform only. Allocations marked (68k/Atari) apply to Linux/68k on
-the Atari platform only.
-
-This document is in the public domain. The author requests, however,
-that semantically altered versions are not distributed without
-permission of the author, assuming the author can be contacted without
-an unreasonable effort.
-
-In particular, please don't sent patches for this list to Linus, at
-least not without contacting me first.
-
-I do not have any information about these devices beyond what appears
-on this list. Any such information requests will be deleted without
-reply.
-
-\section{How to submit a device entry}
-
-To have a major number allocated, or a minor number in situations
-where that applies (e.g. busmice), please contact me with the
-appropriate device information. Also, if you have additional
-information regarding any of the devices listed below, or if I have
-made a mistake, I would greatly appreciate a note.
-
-I do, however, make two requests about the nature of your report.
-This is necessary for me to be able to keep this list up to date and
-correct in a timely manner. First of all, {\em please\/} include the
-word ``device'' in the subject so your mail won't accidentally get
-buried! I receive hundreds of email messages a day, so mail sent with
-other subjects may very well get lost in the avalanche.
-
-Second, please include a description of the device {\em in the same
-format as this list\/}. The reason for this is that it is the only
-way I have found to ensure I have all the requisite information to
-publish your device and avoid conflicts.
-
-Your cooperation is appreciated.
-
-\section{Major numbers}
-
-\begin{devicelist}
-\major{ 0}{}{ }{Unnamed devices (e.g. non-device mounts)}
-\major{ 1}{}{char }{Memory devices}
-\major{ }{}{block}{RAM disk}
-\major{ 2}{}{char }{Pseudo-TTY masters}
-\major{ }{}{block}{Floppy disks}
-\major{ 3}{}{char }{Pseudo-TTY slaves}
-\major{ }{}{block}{First MFM, RLL or IDE hard disk/CD-ROM interface}
-\major{ 4}{}{char }{TTY devices}
-\major{ 5}{}{char }{Alternate TTY devices}
-\major{ 6}{}{char }{Parallel printer devices}
-\major{ 7}{}{char }{Virtual console access devices}
-\major{ }{}{block}{Loopback devices}
-\major{ 8}{}{block}{SCSI disk devices (0-15)}
-\major{ 9}{}{char }{SCSI tape devices}
-\major{ }{}{block}{Metadisk (RAID) devices}
-\major{10}{}{char }{Non-serial mice, misc features}
-\major{11}{}{char }{Raw keyboard device}
-\major{ }{}{block}{SCSI CD-ROM devices}
-\major{12}{}{char }{QIC-02 tape}
-\major{ }{}{block}{MSCDEX CD-ROM callback support}
-\major{13}{}{char }{PC speaker}
-\major{ }{}{block}{8-bit MFM/RLL/IDE controller}
-\major{14}{}{char }{Sound card}
-\major{ }{}{block}{BIOS harddrive callback support}
-\major{15}{}{char }{Joystick}
-\major{ }{}{block}{Sony CDU-31A/CDU-33A CD-ROM}
-\major{16}{}{char }{Non-SCSI scanners}
-\major{ }{}{block}{GoldStar CD-ROM}
-\major{17}{}{char }{Chase serial card}
-\major{ }{}{block}{Optics Storage CD-ROM}
-\major{18}{}{char }{Chase serial card -- alternate devices}
-\major{ }{}{block}{Sanyo CD-ROM}
-\major{19}{}{char }{Cyclades serial card}
-\major{ }{}{block}{``Double'' compressed disk}
-\major{20}{}{char }{Cyclades serial card -- alternate devices}
-\major{ }{}{block}{Hitachi CD-ROM}
-\major{21}{}{char }{Generic SCSI access}
-\major{ }{}{block }{Acorn MFM hard drive interface}
-\major{22}{}{char }{Digiboard serial card}
-\major{ }{}{block}{Second IDE hard disk/CD-ROM interface}
-\major{23}{}{char }{Digiboard serial card -- alternate devices}
-\major{ }{}{block}{Mitsumi proprietary CD-ROM}
-\major{24}{}{char }{Stallion serial card}
-\major{ }{}{block}{Sony CDU-535 CD-ROM}
-\major{25}{}{char }{Stallion serial card -- alternate devices}
-\major{ }{}{block}{First Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{26}{}{char }{Quanta WinVision frame grabber}
-\major{ }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{27}{}{char }{QIC-117 tape}
-\major{ }{}{block}{Third Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{28}{}{char }{Stallion serial card -- card programming}
-\major{ }{}{char }{Atari SLM ACSI laser printer (68k/Atari)}
-\major{ }{}{block}{Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{ }{}{block}{ACSI disk/CD-ROM (68k/Atari)}
-\major{29}{}{char }{Universal frame buffer}
-\major{ }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM}
-\major{30}{}{char }{iBCS-2 compatibility devices}
-\major{ }{}{block}{Philips LMS CM-205 CD-ROM}
-\major{31}{}{char }{MPU-401 MIDI}
-\major{ }{}{block}{ROM/flash memory card}
-\major{32}{}{char }{Specialix serial card}
-\major{ }{}{block}{Philips LMS CM-206 CD-ROM}
-\major{33}{}{char }{Specialix serial card -- alternate devices}
-\major{ }{}{block}{Third IDE hard disk/CD-ROM interface}
-\major{34}{}{char }{Z8530 HDLC driver}
-\major{ }{}{block}{Fourth IDE hard disk/CD-ROM interface}
-\major{35}{}{char }{tclmidi MIDI driver}
-\major{ }{}{block}{Slow memory ramdisk}
-\major{36}{}{char }{Netlink support}
-\major{ }{}{block}{MCA ESDI hard disk}
-\major{37}{}{char }{IDE tape}
-\major{ }{}{block}{Zorro II ramdisk}
-\major{38}{}{char }{Myricom PCI Myrinet board}
-\major{ }{}{block}{Reserved for Linux/AP+}
-\major{39}{}{char }{ML-16P experimental I/O board}
-\major{ }{}{block}{Reserved for Linux/AP+}
-\major{40}{}{char }{Matrox Meteor frame grabber}
-\major{ }{}{block}{Syquest EZ135 parallel port removable drive}
-\major{41}{}{char }{Yet Another Micro Monitor}
-\major{ }{}{block}{MicroSolutions BackPack parallel port CD-ROM}
-\major{42}{}{}{Demo/sample use}
-\major{43}{}{char }{isdn4linux virtual modem}
-\major{ }{}{block}{Network block devices}
-\major{44}{}{char }{isdn4linux virtual modem -- alternate devices}
-\major{ }{}{block}{Flash Translation Layer (FTL) filesystems}
-\major{45}{}{char }{isdn4linux ISDN BRI driver}
-\major{ }{}{block}{Parallel port IDE disk devices}
-\major{46}{}{char }{Comtrol Rocketport serial card}
-\major{ }{}{block}{Parallel port ATAPI CD-ROM devices}
-\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
-\major{ }{}{block}{Parallel port ATAPI disk devices}
-\major{48}{}{char }{SDL RISCom serial card}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{49}{}{char }{SDL RISCom serial card -- alternate devices}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{50}{}{char}{Reserved for GLINT}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{51}{}{char }{Baycom radio modem}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{54}{}{char }{Electrocardiognosis Holter serial card}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{55}{}{char }{DSP56001 digital signal processor}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{56}{}{char }{Apple Desktop Bus}
-\major{ }{}{block}{Fifth IDE hard disk/CD-ROM interface}
-\major{57}{}{char }{Hayes ESP serial card}
-\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface}
-\major{58}{}{char }{Hayes ESP serial card -- alternate devices}
-\major{ }{}{block}{Reserved for logical volume manager}
-\major{59}{}{char }{sf firewall package}
-\major{60}{--63}{}{Local/experimental use}
-\major{64}{}{char }{ENskip kernel encryption package}
-\major{65}{}{char }{Sundance ``plink'' Transputer boards}
-\major{ }{}{block}{SCSI disk devices (16-31)}
-\major{66}{}{char }{YARC PowerPC PCI coprocessor card}
-\major{ }{}{block}{SCSI disk devices (32-47)}
-\major{67}{}{char }{Coda network filesystem}
-\major{ }{}{block}{SCSI disk devices (48-63)}
-\major{68}{}{char }{CAPI 2.0 interface}
-\major{ }{}{block}{SCSI disk devices (64-79)}
-\major{69}{}{char }{MA16 numeric accelerator card}
-\major{ }{}{block}{SCSI disk devices (80-95)}
-\major{70}{}{char }{SpellCaster Protocol Services Interface}
-\major{ }{}{block}{SCSI disk devices (96-111)}
-\major{71}{}{char }{Computone IntelliPort II serial card}
-\major{ }{}{block}{SCSI disk devices (112-127)}
-\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices}
-\major{73}{}{char }{Computone IntelliPort II serial card -- control devices}
-\major{74}{}{char }{SCI bridge}
-\major{75}{}{char }{Specialix IO8+ serial card}
-\major{76}{}{char }{Specialix IO8+ serial card -- alternate devices}
-\major{77}{}{char }{ComScire Quantum Noise Generator}
-\major{78}{}{char }{PAM Software's multimodem boards}
-\major{79}{}{char }{PAM Software's multimodem boards -- alternate devices}
-\major{80}{}{char }{Photometrics AT200 CCD camera}
-\major{81}{}{char }{video4linux}
-\major{82}{}{char }{WiNRADiO communications receiver card}
-\major{83}{}{char }{Teletext/videotext interfaces}
-\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
-\major{85}{}{char }{Linux/SGI shared memory input queue}
-\major{86}{}{char }{SCSI media changer}
-\major{87}{}{char }{Sony Control-A1 stereo control bus}
-\major{88}{}{char }{COMX synchronous serial card}
-\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface}
-\major{89}{}{char }{I$^2$C bus interface}
-\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface}
-\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
-\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface}
-\major{91}{}{char }{CAN-Bus controller}
-\major{ }{}{block}{Tenth IDE hard disk/CD-ROM interface}
-\major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card}
-\major{93}{}{char }{IBM Smart Capture Card frame grabber}
-\major{94}{}{char }{miroVIDEO DC10/30 capture/playback device}
-\major{95}{}{char }{IP filter}
-\major{96}{}{char }{Parallel port ATAPI tape devices}
-\major{97}{}{char }{Parallel port generic ATAPI interface}
-\major{98}{}{char }{Control and Mesurement Device (comedi)}
-\major{99}{}{char }{Raw parallel ports}
-\major{100}{}{char }{POTS (analogue telephone) A/B port}
-\major{101}{}{char }{Motorola DSP 56xxx board}
-\major{102}{}{char }{Philips SAA5249 Teletext signal decoder}
-\major{103}{}{char }{Arla network file system}
-\major{104}{}{char }{Flash BIOS support}
-\major{105}{}{char }{Comtrol VS-1000 serial card}
-\major{106}{}{char }{Comtrol VS-1000 serial card -- alternate devices}
-\major{107}{}{char }{3Dfx Voodoo Graphics device}
-\major{108}{}{char }{Device independent PPP interface}
-\major{109}{}{char }{Reserved for logical volume manager}
-\major{110}{}{char }{miroMEDIA Surround board}
-\major{111}{--119}{}{Unallocated}
-\major{120}{--127}{}{Local/experimental use}
-\major{128}{--135}{char }{Unix98 PTY masters}
-\major{136}{--143}{char }{Unix98 PTY slaves}
-\major{144}{--239}{}{Unallocated}
-\major{240}{--254}{}{Local/experimental use}
-\major{255}{}{}{Reserved}
-\end{devicelist}
-
-\section{Minor numbers}
-
-\begin{devicelist}
-\major{ 0}{}{}{Unnamed devices (e.g. non-device mounts)}
- \minor{0}{}{reserved as null device number}
-\end{devicelist}
-
-\begin{devicelist}
-\major{ 1}{}{char}{Memory devices}
- \minor{1}{/dev/mem}{Physical memory access}
- \minor{2}{/dev/kmem}{Kernel virtual memory access}
- \minor{3}{/dev/null}{Null device}
- \minor{4}{/dev/port}{I/O port access}
- \minor{5}{/dev/zero}{Null byte source}
- \minor{6}{/dev/core}{OBSOLETE -- should be a link to {\file /proc/kcore}}
- \minor{7}{/dev/full}{Returns ENOSPC on write}
- \minor{8}{/dev/random}{Nondeterministic random number generator}
- \minor{9}{/dev/urandom}{Less secure, but faster random number generator}
-\\
-\major{}{}{block}{RAM disk}
- \minor{0}{/dev/ram0}{First RAM disk}
- \minordots
- \minor{7}{/dev/ram7}{Eighth RAM disk}
- \minor{250}{/dev/initrd}{Initial RAM disk}
-\end{devicelist}
-
-\noindent
-Earlier kernels had {\file /dev/ramdisk} (1, 1) here. {\file /dev/initrd}
-refers to a RAM disk which was preloaded by the boot loader.
-
-\begin{devicelist}
-\major{ 2}{}{char}{Pseudo-TTY masters}
- \minor{0}{/dev/ptyp0}{First PTY master}
- \minor{1}{/dev/ptyp1}{Second PTY master}
- \minordots
- \minor{255}{/dev/ptyef}{256th PTY master}
-\end{devicelist}
-
-\noindent
-Pseudo-TTY's are named as follows:
-\begin{itemize}
-\item Masters are {\file pty}, slaves are {\file tty};
-\item the fourth letter is one of {\file pqrstuvwxyzabcde} indicating
-the 1st through 16th series of 16 pseudo-ttys each, and
-\item the fifth letter is one of {\file 0123456789abcdef} indicating
-the position within the series.
-\end{itemize}
-
-\noindent
-These are the old-style (BSD) PTY devices; Unix98 devices are on major
-128 and above and use the PTY master multiplex ({\file /dev/ptmx}) to
-acquire a PTY on demand.
-
-\begin{devicelist}
-\major{}{}{block}{Floppy disks}
- \minor{0}{/dev/fd0}{Controller 1, drive 1 autodetect}
- \minor{1}{/dev/fd1}{Controller 1, drive 2 autodetect}
- \minor{2}{/dev/fd2}{Controller 1, drive 3 autodetect}
- \minor{3}{/dev/fd3}{Controller 1, drive 4 autodetect}
- \minor{128}{/dev/fd4}{Controller 2, drive 1 autodetect}
- \minor{129}{/dev/fd5}{Controller 2, drive 2 autodetect}
- \minor{130}{/dev/fd6}{Controller 2, drive 3 autodetect}
- \minor{131}{/dev/fd7}{Controller 2, drive 4 autodetect}
-\\
-\major{}{}{}{To specify format, add to the autodetect device number}
- \minor{ 0}{/dev/fd?}{Autodetect format}
- \minor{}{}{}
- \minor{ 4}{/dev/fd?d360}{5.25\tum\ \num{4}{360}K in a \num{4}{360}K drive\1}
- \minor{ 20}{/dev/fd?h360}{5.25\tum\ \num{4}{360}K in a 1200K drive\1}
- \minor{ 48}{/dev/fd?h410}{5.25\tum\ \num{4}{410}K in a 1200K drive}
- \minor{ 64}{/dev/fd?h420}{5.25\tum\ \num{4}{420}K in a 1200K drive}
- \minor{ 24}{/dev/fd?h720}{5.25\tum\ \num{4}{720}K in a 1200K drive}
- \minor{ 80}{/dev/fd?h880}{5.25\tum\ \num{4}{880}K in a 1200K drive\1}
- \minor{ 8}{/dev/fd?h1200}{5.25\tum\ 1200K in a 1200K drive\1}
- \minor{ 40}{/dev/fd?h1440}{5.25\tum\ 1440K in a 1200K drive\1}
- \minor{ 56}{/dev/fd?h1476}{5.25\tum\ 1476K in a 1200K drive}
- \minor{ 72}{/dev/fd?h1494}{5.25\tum\ 1494K in a 1200K drive}
- \minor{ 92}{/dev/fd?h1600}{5.25\tum\ 1600K in a 1200K drive\1}
- \minor{}{}{}
- \minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density\2}
- \minor{ 16}{/dev/fd?u720}{3.5\tum\ \num{4}{720}K Double Density\1}
- \minor{120}{/dev/fd?u800}{3.5\tum\ \num{4}{800}K Double Density\2}
- \minor{ 52}{/dev/fd?u820}{3.5\tum\ \num{4}{820}K Double Density}
- \minor{ 68}{/dev/fd?u830}{3.5\tum\ \num{4}{830}K Double Density}
- \minor{ 84}{/dev/fd?u1040}{3.5\tum\ 1040K Double Density\1}
- \minor{ 88}{/dev/fd?u1120}{3.5\tum\ 1120K Double Density\1}
- \minor{ 28}{/dev/fd?u1440}{3.5\tum\ 1440K High Density\1}
- \minor{124}{/dev/fd?u1600}{3.5\tum\ 1600K High Density\1}
- \minor{ 44}{/dev/fd?u1680}{3.5\tum\ 1680K High Density\3}
- \minor{ 60}{/dev/fd?u1722}{3.5\tum\ 1722K High Density}
- \minor{ 76}{/dev/fd?u1743}{3.5\tum\ 1743K High Density}
- \minor{ 96}{/dev/fd?u1760}{3.5\tum\ 1760K High Density}
- \minor{116}{/dev/fd?u1840}{3.5\tum\ 1840K High Density\3}
- \minor{100}{/dev/fd?u1920}{3.5\tum\ 1920K High Density\1}
- \minor{ 32}{/dev/fd?u2880}{3.5\tum\ 2880K Extra Density\1}
- \minor{104}{/dev/fd?u3200}{3.5\tum\ 3200K Extra Density}
- \minor{108}{/dev/fd?u3520}{3.5\tum\ 3520K Extra Density}
- \minor{112}{/dev/fd?u3840}{3.5\tum\ 3840K Extra Density\1}
- \minor{}{}{}
- \minor{36}{/dev/fd?CompaQ}{Compaq 2880K drive; probably obsolete}
-\\
-\major{}{}{}{\1 Autodetectable format}
-\major{}{}{}{\2 Autodetectable format in a Double Density (720K) drive only}
-\major{}{}{}{\3 Autodetectable format in a High Density (1440K) drive only}
-\end{devicelist}
-
-NOTE: The letter in the device name ({\file d}, {\file q}, {\file h}
-or {\file u}) signifies the type of drive supported: 5.25\tum\ Double
-Density ({\file d}), 5.25\tum\ Quad Density ({\file q}), 5.25\tum\
-High Density ({\file h}) or 3.5\tum\ (any type, {\file u}). The
-capital letters {\file D}, {\file H}, or {\file E} for the 3.5\tum\
-models have been deprecated, since the drive type is insignificant for
-these devices.
-
-\begin{devicelist}
-\major{ 3}{}{char}{Pseudo-TTY slaves}
- \minor{0}{/dev/ttyp0}{First PTY slave}
- \minor{1}{/dev/ttyp1}{Second PTY slave}
- \minordots
- \minor{255}{/dev/ttyef}{256th PTY slave}
-\end{devicelist}
-
-\noindent
-These are the old-style (BSD) PTY devices; Unix98 devices are on major
-136 and above.
-
-\begin{devicelist}
-\major{}{}{block}{First MFM, RLL and IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hda}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdb}{Slave: whole disk (or CD-ROM)}
-\\
-\major{}{}{}{For partitions, add to the whole disk device number}
- \minor{0}{/dev/hd?}{Whole disk}
- \minor{1}{/dev/hd?1}{First partition}
- \minor{2}{/dev/hd?2}{Second partition}
- \minordots
- \minor{63}{/dev/hd?63}{63rd partition}
-\end{devicelist}
-
-\noindent
-For MS-DOS style partition tables (typically used by Linux/i386 and
-sometimes on Linux/Alpha), partitions 1-4 are the primary partitions,
-partitions 5 and up are logical partitions. For other partitioning
-schemes, the meaning of the numbers vary.
-
-\begin{devicelist}
-\major{ 4}{}{char }{TTY devices}
- \minor{0}{/dev/tty0}{Current virtual console}
- \minor{1}{/dev/tty1}{First virtual console}
- \minordots
- \minor{63}{/dev/tty63}{63rd virtual console}
- \minor{64}{/dev/ttyS0}{First serial port}
- \minordots
- \minor{127}{/dev/ttyS63}{64th serial port}
- \minor{128}{/dev/ptyp0}{OBSOLETE}
- \minordots
- \minor{191}{/dev/ptysf}{OBSOLETE}
- \minor{192}{/dev/ttyp0}{OBSOLETE}
- \minordots
- \minor{255}{/dev/ttysf}{OBSOLETE}
-\end{devicelist}
-
-\noindent
-Older versions of the Linux kernel used this major number for BSD PTY
-devices. As of Linux 2.1.115, this is no longer supported. Use major
-numbers 2 and 3.
-
-\begin{devicelist}
-\major{ 5}{}{char }{Alternate TTY devices}
- \minor{0}{/dev/tty}{Current TTY device}
- \minor{1}{/dev/console}{System console}
- \minor{2}{/dev/ptmx}{PTY master multiplex}
- \minor{64}{/dev/cua0}{Callout device corresponding to {\file ttyS0}}
- \minordots
- \minor{127}{/dev/cua63}{Callout device corresponding to {\file ttyS63}}
-\end{devicelist}
-
-\noindent
-(5,1) is {\file /dev/console} starting with Linux 2.1.71. See the
-section on terminal devices for more information on {\file /dev/console}.
-
-\begin{devicelist}
-\major{ 6}{}{char }{Parallel printer devices}
- \minor{0}{/dev/lp0}{First parallel printer ({\hex 0x3bc})}
- \minor{1}{/dev/lp1}{Second parallel printer ({\hex 0x378})}
- \minor{2}{/dev/lp2}{Third parallel printer ({\hex 0x278})}
-\end{devicelist}
-
-\noindent
-Not all computers have the {\hex 0x3bc} parallel port, hence the
-"first" printer may be either {\file /dev/lp0} or {\file /dev/lp1}.
-
-\begin{devicelist}
-\major{ 7}{}{char }{Virtual console access devices}
- \minor{0}{/dev/vcs}{Current vc text access}
- \minor{1}{/dev/vcs1}{tty1 text access}
- \minordots
- \minor{63}{/dev/vcs63}{tty63 text access}
- \minor{128}{/dev/vcsa}{Current vc text/attribute access}
- \minor{129}{/dev/vcsa1}{tty1 text/attribute access}
- \minordots
- \minor{191}{/dev/vcsa63}{tty63 text/attribute access}
-\end{devicelist}
-
-\noindent
-NOTE: These devices permit both read and write access.
-
-\begin{devicelist}
-\major{ }{}{block}{Loopback devices}
- \minor{0}{/dev/loop0}{First loopback device}
- \minor{1}{/dev/loop1}{Second loopback device}
- \minordots
-\end{devicelist}
-
-\noindent
-The loopback devices are used to mount filesystems not associated with
-block devices. The binding to the loopback devices is handled by
-{\bf mount}(8) or {\bf losetup}(8).
-
-\begin{devicelist}
-\major{ 8}{}{block}{SCSI disk devices (0-15)}
- \minor{0}{/dev/sda}{First SCSI disk whole disk}
- \minor{16}{/dev/sdb}{Second SCSI disk whole disk}
- \minor{32}{/dev/sdc}{Third SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sdp}{Sixteenth SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{ 9}{}{char }{SCSI tape devices}
- \minor{0}{/dev/st0}{First SCSI tape, mode 0}
- \minor{1}{/dev/st1}{Second SCSI tape, mode 0}
- \minordots
- \minor{32}{/dev/st0l}{First SCSI tape, mode 1}
- \minor{33}{/dev/st1l}{Second SCSI tape, mode 1}
- \minordots
- \minor{64}{/dev/st0m}{First SCSI tape, mode 2}
- \minor{65}{/dev/st1m}{Second SCSI tape, mode 2}
- \minordots
- \minor{96}{/dev/st0a}{First SCSI tape, mode 3}
- \minor{97}{/dev/st1a}{Second SCSI tape, mode 4}
- \minordots
- \minor{128}{/dev/nst0}{First SCSI tape, mode 0, no rewind}
- \minor{129}{/dev/nst1}{Second SCSI tape, mode 0, no rewind}
- \minordots
- \minor{160}{/dev/nst0l}{First SCSI tape, mode 1, no rewind}
- \minor{161}{/dev/nst1l}{Second SCSI tape, mode 1, no rewind}
- \minordots
- \minor{192}{/dev/nst0m}{First SCSI tape, mode 2, no rewind}
- \minor{193}{/dev/nst1m}{Second SCSI tape, mode 2, no rewind}
- \minordots
- \minor{224}{/dev/nst0a}{First SCSI tape, mode 3, no rewind}
- \minor{225}{/dev/nst1a}{Second SCSI tape, mode 3, no rewind}
- \minordots
-\end{devicelist}
-
-\noindent
-``No rewind'' refers to the omission of the default automatic rewind
-on device close. The {\file MTREW} or {\file MTOFFL} ioctl()s can be
-used to rewind the tape regardless of the device used to access it.
-
-\begin{devicelist}
-\major{ }{}{block}{Metadisk (RAID) devices}
- \minor{0}{/dev/md0}{First metadisk group}
- \minor{1}{/dev/md1}{Second metadisk group}
- \minordots
-\end{devicelist}
-
-\noindent
-The metadisk driver is used to span a filesystem across multiple
-physical disks.
-
-\begin{devicelist}
-\major{10}{}{char }{Non-serial mice, misc features}
- \minor{0}{/dev/logibm}{Logitech bus mouse}
- \minor{1}{/dev/psaux}{PS/2-style mouse port}
- \minor{2}{/dev/inportbm}{Microsoft Inport bus mouse}
- \minor{3}{/dev/atibm}{ATI XL bus mouse}
- \minor{4}{/dev/jbm}{J-mouse}
- \minor{4}{/dev/amigamouse}{Amiga mouse (68k/Amiga)}
- \minor{5}{/dev/atarimouse}{Atari mouse}
- \minor{6}{/dev/sunmouse}{Sun mouse}
- \minor{7}{/dev/amigamouse1}{Second Amiga mouse}
- \minor{8}{/dev/smouse}{Simple serial mouse driver}
- \minor{9}{/dev/pc110pad}{IBM PC-110 digitizer pad}
- \minor{128}{/dev/beep}{Fancy beep device}
- \minor{129}{/dev/modreq}{Kernel module load request}
- \minor{130}{/dev/watchdog}{Watchdog timer port}
- \minor{131}{/dev/temperature}{Machine internal temperature}
- \minor{132}{/dev/hwtrap}{Hardware fault trap}
- \minor{133}{/dev/exttrp}{External device trap}
- \minor{134}{/dev/apm\_bios}{Advanced Power Management BIOS}
- \minor{135}{/dev/rtc}{Real Time Clock}
- \minor{139}{/dev/openprom}{SPARC OpenBoot PROM}
- \minor{140}{/dev/relay8}{Berkshire Products Octal relay card}
- \minor{141}{/dev/relay16}{Berkshire Products ISO-16 relay card}
- \minor{142}{/dev/msr}{x86 model specific registers}
- \minor{143}{/dev/pciconf}{PCI configuration space}
- \minor{144}{/dev/nvram}{Non-volatile configuration RAM}
- \minor{145}{/dev/hfmodem}{Soundcard shortwave modem control}
- \minor{146}{/dev/graphics}{Linux/SGI graphics device}
- \minor{147}{/dev/opengl}{Linux/SGI OpenGL pipe}
- \minor{148}{/dev/gfx}{Linux/SGI graphics effects device}
- \minor{149}{/dev/input/mouse}{Linux/SGI Irix emulation mouse}
- \minor{150}{/dev/input/keyboard}{Linux/SGI Irix emulation keyboard}
- \minor{151}{/dev/led}{Front panel LEDs}
- \minor{153}{/dev/mergemem}{Memory merge device}
- \minor{154}{/dev/pmu}{Macintosh PowerBook power manager}
-\end{devicelist}
-
-\begin{devicelist}
-\major{11}{}{char }{Raw keyboard device}
- \minor{0}{/dev/kbd}{Raw keyboard device}
-\end{devicelist}
-
-\noindent
-The raw keyboard device is used on Linux/SPARC only.
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI CD-ROM devices}
- \minor{0}{/dev/sr0}{First SCSI CD-ROM}
- \minor{1}{/dev/sr1}{Second SCSI CD-ROM}
- \minordots
-\end{devicelist}
-
-\noindent
-The prefix {\file /dev/scd} instead of {\file /dev/sr} has been used
-as well, and might make more sense.
-
-\begin{devicelist}
-\major{12}{}{char }{QIC-02 tape}
- \minor{2}{/dev/ntpqic11}{QIC-11, no rewind-on-close}
- \minor{3}{/dev/tpqic11}{QIC-11, rewind-on-close}
- \minor{4}{/dev/ntpqic24}{QIC-24, no rewind-on-close}
- \minor{5}{/dev/tpqic24}{QIC-24, rewind-on-close}
- \minor{6}{/dev/ntpqic120}{QIC-120, no rewind-on-close}
- \minor{7}{/dev/tpqic120}{QIC-120, rewind-on-close}
- \minor{8}{/dev/ntpqic150}{QIC-150, no rewind-on-close}
- \minor{9}{/dev/tpqic150}{QIC-150, rewind-on-close}
-\end{devicelist}
-
-\noindent
-The device names specified are proposed -- if there are ``standard''
-names for these devices, please let me know.
-
-\begin{devicelist}
-\major{ }{}{block}{MSCDEX CD-ROM callback support}
- \minor{0}{/dev/dos\_cd0}{First MSCDEX CD-ROM}
- \minor{1}{/dev/dos\_cd1}{Second MSCDEX CD-ROM}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{13}{}{char }{PC speaker}
- \minor{0}{/dev/pcmixer}{Emulates {\file /dev/mixer}}
- \minor{3}{/dev/pcsp}{Emulates {\file /dev/dsp} (8-bit)}
- \minor{4}{/dev/pcaudio}{Emulates {\file /dev/audio}}
- \minor{5}{/dev/pcsp16}{Emulates {\file /dev/dsp} (16-bit)}
-\\
-\major{ }{}{block}{8-bit MFM/RLL/IDE controller}
- \minor{0}{/dev/xda}{First XT disk whole disk}
- \minor{64}{/dev/xdb}{Second XT disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3).
-
-\begin{devicelist}
-\major{14}{}{char }{Sound card}
- \minor{0}{/dev/mixer}{Mixer control}
- \minor{1}{/dev/sequencer}{Audio sequencer}
- \minor{2}{/dev/midi00}{First MIDI port}
- \minor{3}{/dev/dsp}{Digital audio}
- \minor{4}{/dev/audio}{Sun-compatible digital audio}
- \minor{6}{/dev/sndstat}{Sound card status information}
- \minor{8}{/dev/sequencer2}{Sequencer -- alternate device}
- \minor{16}{/dev/mixer1}{Second soundcard mixer control}
- \minor{17}{/dev/patmgr0}{Sequencer patch manager}
- \minor{18}{/dev/midi01}{Second MIDI port}
- \minor{19}{/dev/dsp1}{Second soundcard digital audio}
- \minor{20}{/dev/audio1}{Second soundcard Sun digital audio}
- \minor{33}{/dev/patmgr1}{Sequencer patch manager}
- \minor{34}{/dev/midi02}{Third MIDI port}
- \minor{50}{/dev/midi03}{Fourth MIDI port}
-\\
-\major{ }{}{block}{BIOS harddrive callback support}
- \minor{0}{/dev/dos\_hda}{First BIOS harddrive whole disk}
- \minor{64}{/dev/dos\_hdb}{Second BIOS harddrive whole disk}
- \minor{128}{/dev/dos\_hdc}{Third BIOS harddrive whole disk}
- \minor{192}{/dev/dos\_hdd}{Fourth BIOS harddrive whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3).
-
-\begin{devicelist}
-\major{15}{}{char }{Joystick}
- \minor{0}{/dev/js0}{First analog joystick}
- \minor{1}{/dev/js1}{Second analog joystick}
- \minordots
- \minor{128}{/dev/djs0}{First digital joystick}
- \minor{129}{/dev/djs1}{Second digital joystick}
- \minordots
-\\
-\major{ }{}{block}{Sony CDU-31A/CDU-33A CD-ROM}
- \minor{0}{/dev/sonycd}{Sony CDU-31A CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{16}{}{char }{Non-SCSI scanners}
- \minor{0}{/dev/gs4500}{Genius 4500 handheld scanner}
-\\
-\major{ }{}{block}{GoldStar CD-ROM}
- \minor{0}{/dev/gscd}{GoldStar CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{17}{}{char }{Chase serial card}
- \minor{0}{/dev/ttyH0}{First Chase port}
- \minor{1}{/dev/ttyH1}{Second Chase port}
- \minordots
-\\
-\major{ }{}{block}{Optics Storage CD-ROM}
- \minor{0}{/dev/optcd}{Optics Storage CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{18}{}{char }{Chase serial card -- alternate devices}
- \minor{0}{/dev/cuh0}{Callout device corresponding to {\file ttyH0}}
- \minor{1}{/dev/cuh1}{Callout device corresponding to {\file ttyH1}}
- \minordots
-\\
-\major{ }{}{block}{Sanyo CD-ROM}
- \minor{0}{/dev/sjcd}{Sanyo CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{19}{}{char }{Cyclades serial card}
- \minor{0}{/dev/ttyC0}{First Cyclades port}
- \minordots
- \minor{31}{/dev/ttyC31}{32nd Cyclades port}
-\\
-\major{ }{}{block}{``Double'' compressed disk}
- \minor{0}{/dev/double0}{First compressed disk}
- \minordots
- \minor{7}{/dev/double7}{Eighth compressed disk}
- \minor{128}{/dev/cdouble0}{Mirror of first compressed disk}
- \minordots
- \minor{135}{/dev/cdouble7}{Mirror of eighth compressed disk}
-\end{devicelist}
-
-\noindent
-See the Double documentation for an explanation of the ``mirror'' devices.
-
-\begin{devicelist}
-\major{20}{}{char }{Cyclades serial card -- alternate devices}
- \minor{0}{/dev/cub0}{Callout device corresponding to {\file ttyC0}}
- \minordots
- \minor{31}{/dev/cub31}{Callout device corresponding to {\file ttyC31}}
-\\
-\major{ }{}{block}{Hitachi CD-ROM}
- \minor{0}{/dev/hitcd}{Hitachi CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{21}{}{char }{Generic SCSI access}
- \minor{0}{/dev/sg0}{First generic SCSI device}
- \minor{1}{/dev/sg1}{Second generic SCSI device}
- \minordots
-\end{devicelist}
-
-\noindent
-Most distributions name these {\file /dev/sga}, {\file /dev/sgb}...
-This sets an unneccesary limit of 26 SCSI devices in the system, and
-is counter to standard Linux device-naming practice.
-
-\begin{devicelist}
-\major{ }{}{block }{Acorn MFM hard drive interface}
- \minor{0}{/dev/mfma}{First MFM drive whole disk}
- \minor{64}{/dev/mfmb}{Second MFM drive whole disk}
-\end{devicelist}
-
-\noindent
-This device is used on the ARM-based Acorn RiscPC. Partitions are
-handled the same way as for IDE disks (see major number 3).
-
-\begin{devicelist}
-\major{22}{}{char }{Digiboard serial card}
- \minor{0}{/dev/ttyD0}{First Digiboard port}
- \minor{1}{/dev/ttyD1}{Second Digiboard port}
- \minordots
-\\
-\major{ }{}{block}{Second IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hdc}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdd}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{23}{}{char }{Digiboard serial card -- alternate devices}
- \minor{0}{/dev/cud0}{Callout device corresponding to {\file ttyD0}}
- \minor{1}{/dev/cud1}{Callout device corresponding to {\file ttyD1}}
- \minordots
-\major{ }{}{block}{Mitsumi proprietary CD-ROM}
- \minor{0}{/dev/mcd}{Mitsumi CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}\
-\major{24}{}{char }{Stallion serial card}
- \minor{0}{/dev/ttyE0}{Stallion port 0 board 0}
- \minor{1}{/dev/ttyE1}{Stallion port 1 board 0}
- \minordots
- \minor{64}{/dev/ttyE64}{Stallion port 0 board 1}
- \minor{65}{/dev/ttyE65}{Stallion port 1 board 1}
- \minordots
- \minor{128}{/dev/ttyE128}{Stallion port 0 board 2}
- \minor{129}{/dev/ttyE129}{Stallion port 1 board 2}
- \minordots
- \minor{192}{/dev/ttyE192}{Stallion port 0 board 3}
- \minor{193}{/dev/ttyE193}{Stallion port 1 board 3}
- \minordots
-\\
-\major{ }{}{block}{Sony CDU-535 CD-ROM}
- \minor{0}{/dev/cdu535}{Sony CDU-535 CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{25}{}{char }{Stallion serial card -- alternate devices}
- \minor{0}{/dev/cue0}{Callout device corresponding to {\file ttyE0}}
- \minor{1}{/dev/cue1}{Callout device corresponding to {\file ttyE1}}
- \minordots
- \minor{64}{/dev/cue64}{Callout device corresponding to {\file ttyE64}}
- \minor{65}{/dev/cue65}{Callout device corresponding to {\file ttyE65}}
- \minordots
- \minor{128}{/dev/cue128}{Callout device corresponding to {\file ttyE128}}
- \minor{129}{/dev/cue129}{Callout device corresponding to {\file ttyE129}}
- \minordots
- \minor{192}{/dev/cue192}{Callout device corresponding to {\file ttyE192}}
- \minor{193}{/dev/cue193}{Callout device corresponding to {\file ttyE193}}
- \minordots
-\\
-\major{ }{}{block}{First Matsushita (Panasonic/SoundBlaster) CD-ROM}
- \minor{0}{/dev/sbpcd0}{Panasonic CD-ROM controller 0 unit 0}
- \minor{1}{/dev/sbpcd1}{Panasonic CD-ROM controller 0 unit 1}
- \minor{2}{/dev/sbpcd2}{Panasonic CD-ROM controller 0 unit 2}
- \minor{3}{/dev/sbpcd3}{Panasonic CD-ROM controller 0 unit 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{26}{}{char }{Quanta WinVision frame grabber}
- \minor{0}{/dev/wvisfgrab}{Quanta WinVision frame grabber}
-\\
-\major{ }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM}
- \minor{0}{/dev/sbpcd4}{Panasonic CD-ROM controller 1 unit 0}
- \minor{1}{/dev/sbpcd5}{Panasonic CD-ROM controller 1 unit 1}
- \minor{2}{/dev/sbpcd6}{Panasonic CD-ROM controller 1 unit 2}
- \minor{3}{/dev/sbpcd7}{Panasonic CD-ROM controller 1 unit 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{27}{}{char }{QIC-117 tape}
- \minor{0}{/dev/qft0}{Unit 0, rewind-on-close}
- \minor{1}{/dev/qft1}{Unit 1, rewind-on-close}
- \minor{2}{/dev/qft2}{Unit 2, rewind-on-close}
- \minor{3}{/dev/qft3}{Unit 3, rewind-on-close}
- \minor{4}{/dev/nqft0}{Unit 0, no rewind-on-close}
- \minor{5}{/dev/nqft1}{Unit 1, no rewind-on-close}
- \minor{6}{/dev/nqft2}{Unit 2, no rewind-on-close}
- \minor{7}{/dev/nqft3}{Unit 3, no rewind-on-close}
- \minor{16}{/dev/zqft0}{Unit 0, rewind-on-close, compression}
- \minor{17}{/dev/zqft1}{Unit 1, rewind-on-close, compression}
- \minor{18}{/dev/zqft2}{Unit 2, rewind-on-close, compression}
- \minor{19}{/dev/zqft3}{Unit 3, rewind-on-close, compression}
- \minor{20}{/dev/nzqft0}{Unit 0, no rewind-on-close, compression}
- \minor{21}{/dev/nzqft1}{Unit 1, no rewind-on-close, compression}
- \minor{22}{/dev/nzqft2}{Unit 2, no rewind-on-close, compression}
- \minor{23}{/dev/nzqft3}{Unit 3, no rewind-on-close, compression}
- \minor{32}{/dev/rawqft0}{Unit 0, rewind-on-close, no file marks}
- \minor{33}{/dev/rawqft1}{Unit 1, rewind-on-close, no file marks}
- \minor{34}{/dev/rawqft2}{Unit 2, rewind-on-close, no file marks}
- \minor{35}{/dev/rawqft3}{Unit 3, rewind-on-close, no file marks}
- \minor{36}{/dev/nrawqft0}{Unit 0, no rewind-on-close, no file marks}
- \minor{37}{/dev/nrawqft1}{Unit 1, no rewind-on-close, no file marks}
- \minor{38}{/dev/nrawqft2}{Unit 2, no rewind-on-close, no file marks}
- \minor{39}{/dev/nrawqft3}{Unit 3, no rewind-on-close, no file marks}
-\\
-\major{ }{}{block}{Third Matsushita (Panasonic/SoundBlaster) CD-ROM}
- \minor{0}{/dev/sbpcd8}{Panasonic CD-ROM controller 2 unit 0}
- \minor{1}{/dev/sbpcd9}{Panasonic CD-ROM controller 2 unit 1}
- \minor{2}{/dev/sbpcd10}{Panasonic CD-ROM controller 2 unit 2}
- \minor{3}{/dev/sbpcd11}{Panasonic CD-ROM controller 2 unit 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{28}{}{char }{Stallion serial card -- card programming}
- \minor{0}{/dev/staliomem0}{First Stallion I/O card memory}
- \minor{1}{/dev/staliomem1}{Second Stallion I/O card memory}
- \minor{2}{/dev/staliomem2}{Third Stallion I/O card memory}
- \minor{3}{/dev/staliomem3}{Fourth Stallion I/O card memory}
-\\
-\major{ }{}{char }{Atari SLM ACSI laser printer (68k/Atari)}
- \minor{0}{/dev/slm0}{First SLM laser printer}
- \minor{1}{/dev/slm1}{Second SLM laser printer}
- \minordots
-\\
-\major{ }{}{block}{Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM}
- \minor{0}{/dev/sbpcd12}{Panasonic CD-ROM controller 3 unit 0}
- \minor{1}{/dev/sbpcd13}{Panasonic CD-ROM controller 3 unit 1}
- \minor{2}{/dev/sbpcd14}{Panasonic CD-ROM controller 3 unit 2}
- \minor{3}{/dev/sbpcd15}{Panasonic CD-ROM controller 3 unit 3}
-\\
-\major{ }{}{block}{ACSI disk/CD-ROM (68k/Atari)}
- \minor{0}{/dev/ada}{First ACSI disk whole disk}
- \minor{16}{/dev/adb}{Second ACSI disk whole disk}
- \minor{32}{/dev/adc}{Third ACSI disk whole disk}
- \minordots
- \minor{240}{/dev/adp}{Sixteenth ACSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk (same as SCSI.)
-
-\begin{devicelist}
-\major{29}{}{char }{Universal frame buffer}
- \minor{0}{/dev/fb0}{First frame buffer}
- \minor{1}{/dev/fb1}{Second frame buffer}
- \minor{2}{/dev/fb2}{Third frame buffer}
- \minordots
- \minor{31}{/dev/fb31}{32nd frame buffer}
-\end{devicelist}
-
-\noindent
-All additional minor device numbers are reserved.
-
-\begin{devicelist}
-\major{ }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM}
- \minor{0}{/dev/aztcd}{Aztech CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{30}{}{char }{iBCS-2 compatibility devices}
- \minor{0}{/dev/socksys}{Socket access}
- \minor{1}{/dev/spx}{SVR3 local X interface}
- \minor{2}{/dev/inet/arp}{Network access}
- \minor{2}{/dev/inet/icmp}{Network access}
- \minor{2}{/dev/inet/ip}{Network access}
- \minor{2}{/dev/inet/udp}{Network access}
- \minor{2}{/dev/inet/tcp}{Network access}
-\end{devicelist}
-
-\noindent
-Additionally, iBCS-2 requires {\file /dev/nfsd} to be a link to {\file
-/dev/socksys} and {\file /dev/X0R} to be a link to {\file /dev/null}.
-
-\begin{devicelist}
-\major{ }{}{block}{Philips LMS CM-205 CD-ROM}
- \minor{0}{/dev/cm205cd}{Philips LMS CM-205 CD-ROM}
-\end{devicelist}
-
-\noindent
-{\file /dev/lmscd} is an older name for this drive. This driver does
-not work with the CM-205MS CD-ROM.
-
-\begin{devicelist}
-\major{31}{}{char }{MPU-401 MIDI}
- \minor{0}{/dev/mpu401data}{MPU-401 data port}
- \minor{1}{/dev/mpu401stat}{MPU-401 status port}
-\\
-\major{ }{}{block}{ROM/flash memory card}
- \minor{0}{/dev/rom0}{First ROM card (rw)}
- \minordots
- \minor{7}{/dev/rom7}{Eighth ROM card (rw)}
- \minor{8}{/dev/rrom0}{First ROM card (ro)}
- \minordots
- \minor{15}{/dev/rrom0}{Eighth ROM card (ro)}
- \minor{16}{/dev/flash0}{First flash memory card (rw)}
- \minordots
- \minor{23}{/dev/flash7}{Eighth flash memory card (rw)}
- \minor{24}{/dev/rflash0}{First flash memory card (ro)}
- \minordots
- \minor{31}{/dev/rflash7}{Eighth flash memory card (ro)}
-\end{devicelist}
-
-\noindent
-The read-write (rw) devices support back-caching written data in RAM,
-as well as writing to flash RAM devices. The read-only devices (ro)
-support reading only.
-
-\begin{devicelist}
-\major{32}{}{char }{Specialix serial card}
- \minor{0}{/dev/ttyX0}{First Specialix port}
- \minor{1}{/dev/ttyX1}{Second Specialix port}
- \minordots
-\\
-\major{ }{}{block}{Philips LMS CM-206 CD-ROM}
- \minor{0}{/dev/cm206cd}{Philips LMS CM-206 CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{33}{}{char }{Specialix serial card -- alternate devices}
- \minor{0}{/dev/cux0}{Callout device corresponding to {\file ttyX0}}
- \minor{1}{/dev/cux1}{Callout device corresponding to {\file ttyX1}}
- \minordots
-\\
-\major{ }{}{block}{Third IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hde}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdf}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{34}{}{char }{Z8530 HDLC driver}
- \minor{0}{/dev/scc0}{First Z8530, first port}
- \minor{1}{/dev/scc1}{First Z8530, second port}
- \minor{2}{/dev/scc2}{Second Z8530, first port}
- \minor{3}{/dev/scc3}{Second Z8530, second port}
- \minordots
-\end{devicelist}
-
-\noindent
-In a previous version these devices were named {\file /dev/sc1} for
-{\file /dev/scc0}, {\file /dev/sc2} for {\file /dev/scc1}, and so on.
-
-\begin{devicelist}
-\major{ }{}{block}{Fourth IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hdg}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdh}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{35}{}{char }{tclmidi MIDI driver}
- \minor{0}{/dev/midi0}{First MIDI port, kernel timed}
- \minor{1}{/dev/midi1}{Second MIDI port, kernel timed}
- \minor{2}{/dev/midi2}{Third MIDI port, kernel timed}
- \minor{3}{/dev/midi3}{Fourth MIDI port, kernel timed}
- \minor{64}{/dev/rmidi0}{First MIDI port, untimed}
- \minor{65}{/dev/rmidi1}{Second MIDI port, untimed}
- \minor{66}{/dev/rmidi2}{Third MIDI port, untimed}
- \minor{67}{/dev/rmidi3}{Fourth MIDI port, untimed}
- \minor{128}{/dev/smpte0}{First MIDI port, SMPTE timed}
- \minor{129}{/dev/smpte1}{Second MIDI port, SMPTE timed}
- \minor{130}{/dev/smpte2}{Third MIDI port, SMPTE timed}
- \minor{131}{/dev/smpte3}{Fourth MIDI port, SMPTE timed}
-\\
-\major{ }{}{block}{Slow memory ramdisk}
- \minor{0}{/dev/slram}{Slow memory ramdisk}
-\end{devicelist}
-
-\begin{devicelist}
-\major{36}{}{char }{Netlink support}
- \minor{0}{/dev/route}{Routing, device updates (kernel to user)}
- \minor{1}{/dev/skip}{enSKIP security cache control}
-\\
-\major{ }{}{block}{MCA ESDI hard disk}
- \minor{0}{/dev/eda}{First ESDI disk whole disk}
- \minor{64}{/dev/edb}{Second ESDI disk whole disk}
- \minordots
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for IDE disks (see major number
-3).
-
-\begin{devicelist}
-\major{37}{}{char }{IDE tape}
- \minor{0}{/dev/ht0}{First IDE tape}
- \minor{128}{/dev/nht0}{First IDE tape, no rewind-on-close}
-\end{devicelist}
-
-\noindent
-Currently, only one IDE tape drive is supported.
-
-\begin{devicelist}
-\major{ }{}{block}{Zorro II ramdisk}
- \minor{0}{/dev/z2ram}{Zorro II ramdisk}
-\end{devicelist}
-
-\begin{devicelist}
-\major{38}{}{char }{Myricom PCI Myrinet board}
- \minor{0}{/dev/mlanai0}{First Myrinet board}
- \minor{1}{/dev/mlanai1}{Second Myrinet board}
- \minordots
-\end{devicelist}
-
-\noindent
-This device is used for board control, status query and ``user level
-packet I/O''. The board is also accessible as a regular {\file eth}
-networking device.
-
-\begin{devicelist}
-\major{ }{}{block}{Reserved for Linux/AP+}
-\end{devicelist}
-
-\begin{devicelist}
-\major{39}{}{char }{ML-16P experimental I/O board}
- \minor{0}{/dev/ml16pa-a0}{First card, first analog channel}
- \minor{1}{/dev/ml16pa-a1}{First card, second analog channel}
- \minordots
- \minor{15}{/dev/ml16pa-a15}{First card, 16th analog channel}
- \minor{16}{/dev/ml16pa-d}{First card, digital lines}
- \minor{17}{/dev/ml16pa-c0}{First card, first counter/timer}
- \minor{18}{/dev/ml16pa-c1}{First card, second counter/timer}
- \minor{19}{/dev/ml16pa-c2}{First card, third counter/timer}
- \minor{32}{/dev/ml16pb-a0}{Second card, first analog channel}
- \minor{33}{/dev/ml16pb-a1}{Second card, second analog channel}
- \minordots
- \minor{47}{/dev/ml16pb-a15}{Second card, 16th analog channel}
- \minor{48}{/dev/ml16pb-d}{Second card, digital lines}
- \minor{49}{/dev/ml16pb-c0}{Second card, first counter/timer}
- \minor{50}{/dev/ml16pb-c1}{Second card, second counter/timer}
- \minor{51}{/dev/ml16pb-c2}{Second card, third counter/timer}
- \minordots
-\\
-\major{ }{}{block}{Reserved for Linux/AP+}
-\end{devicelist}
-
-\begin{devicelist}
-\major{40}{}{char }{Matrox Meteor frame grabber}
- \minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber}
-\\
-\major{ }{}{block}{Syquest EZ135 parallel port removable drive}
- \minor{0}{/dev/eza}{Parallel EZ135 drive whole disk}
-\end{devicelist}
-
-\noindent
-This device is obsolete and will be removed in a future version of
-Linux. It has been replaced with the parallel port IDE disk driver at
-major number 45. Partitions are handled the same way as for IDE disks
-(see major number 3).
-
-\begin{devicelist}
-\major{41}{}{char }{Yet Another Micro Monitor}
- \minor{0}{/dev/yamm}{Yet Another Micro Monitor}
-\\
-\major{ }{}{block}{MicroSolutions BackPack parallel port CD-ROM}
- \minor{0}{/dev/bpcd}{BackPack CD-ROM}
-\end{devicelist}
-
-\noindent
-This device is obsolete and will be removed in a future version of
-Linux. It has been replaced with the parallel port ATAPI CD-ROM
-driver at major number 46.
-
-\begin{devicelist}
-\major{42}{}{}{Demo/sample use}
-\end{devicelist}
-
-\noindent
-This number is intended for use in sample code, as well as a general
-``example'' device number. It should never be used for a device
-driver that is being distributed; either obtain an official number or
-use the local/experimental range. The sudden addition or removal of a
-driver with this number should not cause ill effects to the system
-(bugs excepted.)
-
-IN PARTICULAR, ANY DISTRIBUTION WHICH CONTAINS A DEVICE DRIVER USING
-MAJOR NUMBER 42 IS NONCOMPLIANT.
-
-\begin{devicelist}
-\major{43}{}{char }{isdn4linux virtual modem}
- \minor{0}{/dev/ttyI0}{First virtual modem}
- \minordots
- \minor{63}{/dev/ttyI63}{64th virtual modem}
-\\
-\major{ }{}{block}{Network block devices}
- \minor{0}{/dev/nd0}{First network block device}
- \minor{1}{/dev/nd1}{Second network block device}
- \minordots
-\end{devicelist}
-
-\noindent
-Network Block Device is somehow similar to loopback devices: If you
-read from it, it sends packet accross network asking server for
-data. If you write to it, it sends packet telling server to write. It
-could be used to mounting filesystems over the net, swapping over the
-net, implementing block device in userland etc.
-
-\begin{devicelist}
-\major{44}{}{char }{isdn4linux virtual modem -- alternate devices}
- \minor{0}{/dev/cui0}{Callout device corresponding to {\file ttyI0}}
- \minordots
- \minor{63}{/dev/cui63}{Callout device corresponding to {\file ttyI63}}
-\\
-\major{ }{}{block}{Flash Translation Layer (FTL) filesystems}
- \minor{0}{/dev/ftla}{FTL on first Memory Technology Device}
- \minor{16}{/dev/ftlb}{FTL on second Memory Technology Device}
- \minor{32}{/dev/ftlc}{FTL on third Memory Technology Device}
- \minordots
- \minor{240}{/dev/ftlp}{FTL on 16th Memory Technology Device}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) expect that the partition limit is 15 rather than 63 per
-disk (same as SCSI.)
-
-\begin{devicelist}
-\major{45}{}{char }{isdn4linux ISDN BRI driver}
- \minor{0}{/dev/isdn0}{First virtual B channel raw data}
- \minordots
- \minor{63}{/dev/isdn63}{64th virtual B channel raw data}
- \minor{64}{/dev/isdnctrl0}{First channel control/debug}
- \minordots
- \minor{127}{/dev/isdnctrl63}{64th channel control/debug}
- \minor{128}{/dev/ippp0}{First SyncPPP device}
- \minordots
- \minor{191}{/dev/ippp63}{64th SyncPPP device}
- \minor{255}{/dev/isdninfo}{ISDN monitor interface}
-\\
-\major{ }{}{block}{Parallel port IDE disk devices}
- \minor{0}{/dev/pda}{First parallel port IDE disk}
- \minor{16}{/dev/pdb}{Second parallel port IDE disk}
- \minor{32}{/dev/pdc}{Third parallel port IDE disk}
- \minor{48}{/dev/pdd}{Fourth parallel port IDE disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{46}{}{char }{Comtrol Rocketport serial card}
- \minor{0}{/dev/ttyR0}{First Rocketport port}
- \minor{1}{/dev/ttyR1}{Second Rocketport port}
- \minordots
-\\
-\major{ }{}{block}{Parallel port ATAPI CD-ROM devices}
- \minor{0}{/dev/pcd0}{First parallel port ATAPI CD-ROM}
- \minor{1}{/dev/pcd1}{Second parallel port ATAPI CD-ROM}
- \minor{2}{/dev/pcd2}{Third parallel port ATAPI CD-ROM}
- \minor{3}{/dev/pcd3}{Fourth parallel port ATAPI CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
- \minor{0}{/dev/cur0}{Callout device corresponding to {\file ttyR0}}
- \minor{1}{/dev/cur1}{Callout device corresponding to {\file ttyR1}}
- \minordots
-\\
-\major{ }{}{block}{Parallel port ATAPI disk devices}
- \minor{0}{/dev/pf0}{First parallel port ATAPI disk}
- \minor{1}{/dev/pf1}{Second parallel port ATAPI disk}
- \minor{2}{/dev/pf2}{Third parallel port ATAPI disk}
- \minor{3}{/dev/pf3}{Fourth parallel port ATAPI disk}
-\end{devicelist}
-
-\noindent
-This driver is intended for floppy disks and similar devices and hence
-does not support partitioning.
-
-\begin{devicelist}
-\major{48}{}{char }{SDL RISCom serial card}
- \minor{0}{/dev/ttyL0}{First RISCom port}
- \minor{1}{/dev/ttyL1}{Second RISCom port}
- \minordots
-\\
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{49}{}{char }{SDL RISCom serial card -- alternate devices}
- \minor{0}{/dev/cul0}{Callout device corresponding to {\file ttyL0}}
- \minor{1}{/dev/cul1}{Callout device corresponding to {\file ttyL1}}
- \minordots
-\\
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{50}{}{char}{Reserved for GLINT}
-\\
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{51}{}{char }{Baycom radio modem}
- \minor{0}{/dev/bc0}{First Baycom radio modem}
- \minor{1}{/dev/bc1}{Second Baycom radio modem}
- \minordots
-\\
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card}
- \minor{0}{/dev/dcbri0}{First DataComm card}
- \minor{1}{/dev/dcbri1}{Second DataComm card}
- \minor{2}{/dev/dcbri2}{Third DataComm card}
- \minor{3}{/dev/dcbri3}{Fourth DataComm card}
-\\
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers}
- \minor{0}{/dev/pd\_bdm0}{PD BDM interface on {\file lp0}}
- \minor{1}{/dev/pd\_bdm1}{PD BDM interface on {\file lp1}}
- \minor{2}{/dev/pd\_bdm2}{PD BDM interface on {\file lp2}}
- \minor{4}{/dev/icd\_bdm0}{ICD BDM interface on {\file lp0}}
- \minor{5}{/dev/icd\_bdm1}{ICD BDM interface on {\file lp1}}
- \minor{6}{/dev/icd\_bdm2}{ICD BDM interface on {\file lp2}}
-\end{devicelist}
-
-\noindent
-This device is used for the interfacing to the MC683xx
-microcontrollers via Background Debug Mode by use of a Parallel Port
-interface. PD is the Motorola Public Domain Interface and ICD is the
-commercial interface by P\&E.
-
-\begin{devicelist}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{54}{}{char }{Electrocardiognosis Holter serial card}
- \minor{0}{/dev/holter0}{First Holter port}
- \minor{1}{/dev/holter1}{Second Holter port}
- \minor{2}{/dev/holter2}{Third Holter port}
-\end{devicelist}
-
-\noindent
-A custom serial card used by Electrocardiognosis SRL
-$<$mseritan@ottonel.pub.ro$>$ to transfer data from Holter 24-hour
-heart monitoring equipment.
-
-\begin{devicelist}
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{55}{}{char }{DSP56001 digital signal processor}
- \minor{0}{/dev/dsp56k}{First DSP56001}
-\\
-\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{56}{}{char }{Apple Desktop Bus}
- \minor{0}{/dev/adb}{ADB bus control}
-\end{devicelist}
-
-\noindent
-Additional devices will be added to this number, all starting with
-{\file /dev/adb}.
-
-\begin{devicelist}
-\major{ }{}{block}{Fifth IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hdi}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdj}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{57}{}{char }{Hayes ESP serial card}
- \minor{0}{/dev/ttyP0}{First ESP port}
- \minor{1}{/dev/ttyP1}{Second ESP port}
- \minordots
-\\
-\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hdk}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdl}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{58}{}{char }{Hayes ESP serial card -- alternate devices}
- \minor{0}{/dev/cup0}{Callout device corresponding to {\file ttyP0}}
- \minor{1}{/dev/cup1}{Callout device corresponding to {\file ttyP1}}
- \minordots
-\\
-\major{ }{}{block}{Reserved for logical volume manager}
-\end{devicelist}
-
-\begin{devicelist}
-\major{59}{}{char }{sf firewall package}
- \minor{0}{/dev/firewall}{Communication with sf kernel module}
-\end{devicelist}
-
-\begin{devicelist}
-\major{60}{--63}{}{Local/experimental use}
-\end{devicelist}
-
-\noindent
-For devices not assigned official numbers, these ranges should be
-used, in order to avoid conflict with future assignments.
-
-\begin{devicelist}
-\major{64}{}{char }{ENskip kernel encryption package}
- \minor{0}{/dev/enskip}{Communication with ENskip kernel
- module}
-\end{devicelist}
-
-\begin{devicelist}
-\major{65}{}{char }{Sundance ``plink'' Transputer boards}
- \minor{0}{/dev/plink0}{First plink device}
- \minor{1}{/dev/plink1}{Second plink device}
- \minor{2}{/dev/plink2}{Third plink device}
- \minor{3}{/dev/plink3}{Fourth plink device}
- \minor{64}{/dev/rplink0}{First plink device, raw}
- \minor{65}{/dev/rplink1}{Second plink device, raw}
- \minor{66}{/dev/rplink2}{Third plink device, raw}
- \minor{67}{/dev/rplink3}{Fourth plink device, raw}
- \minor{128}{/dev/plink0d}{First plink device, debug}
- \minor{129}{/dev/plink1d}{Second plink device, debug}
- \minor{130}{/dev/plink2d}{Third plink device, debug}
- \minor{131}{/dev/plink3d}{Fourth plink device, debug}
- \minor{192}{/dev/rplink0d}{First plink device, raw, debug}
- \minor{193}{/dev/rplink1d}{Second plink device, raw, debug}
- \minor{194}{/dev/rplink2d}{Third plink device, raw, debug}
- \minor{195}{/dev/rplink3d}{Fourth plink device, raw, debug}
-\end{devicelist}
-
-\noindent
-This is a commercial driver; contact James Howes
-$<$jth@prosig.demon.co.uk$>$ for information.
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI disk devices (16-31)}
- \minor{0}{/dev/sdq}{17th SCSI disk whole disk}
- \minor{16}{/dev/sdr}{18th SCSI disk whole disk}
- \minor{32}{/dev/sds}{19th SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sdaf}{32nd SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{66}{}{char }{YARC PowerPC PCI coprocessor card}
- \minor{0}{/dev/yppcpci0}{First YARC card}
- \minor{1}{/dev/yppcpci1}{Second YARC card}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI disk devices (32-47)}
- \minor{0}{/dev/sdag}{33rd SCSI disk whole disk}
- \minor{16}{/dev/sdah}{34th SCSI disk whole disk}
- \minor{32}{/dev/sdai}{35th SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sdav}{48th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{67}{}{char }{Coda network filesystem}
- \minor{0}{/dev/cfs0}{Coda cache manager}
-\end{devicelist}
-
-\noindent
-See {\url http://www.coda.cs.cmu.edu\/} for information about Coda.
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI disk devices (48-63)}
- \minor{0}{/dev/sdaw}{49th SCSI disk whole disk}
- \minor{16}{/dev/sdax}{50th SCSI disk whole disk}
- \minor{32}{/dev/sday}{51st SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sdbl}{64th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{68}{}{char }{CAPI 2.0 interface}
- \minor{0}{/dev/capi20}{Control device}
- \minor{1}{/dev/capi20.00}{First CAPI 2.0 application}
- \minor{2}{/dev/capi20.01}{Second CAPI 2.0 application}
- \minordots
- \minor{20}{/dev/capi20.19}{19th CAPI 2.0 application}
-\end{devicelist}
-
-\noindent
-ISDN CAPI 2.0 driver for use with CAPI 2.0 applications; currently
-supports the AVM B1 card.
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI disk devices (64-79)}
- \minor{0}{/dev/sdbm}{65th SCSI disk whole disk}
- \minor{16}{/dev/sdbn}{66th SCSI disk whole disk}
- \minor{32}{/dev/sdbo}{67th SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sdcb}{80th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{69}{}{char }{MA16 numeric accelerator card}
- \minor{0}{/dev/ma16}{Board memory access}
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI disk devices (80-95)}
- \minor{0}{/dev/sdcc}{81st SCSI disk whole disk}
- \minor{16}{/dev/sdcd}{82nd SCSI disk whole disk}
- \minor{32}{/dev/sdce}{83th SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sdcr}{96th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{70}{}{char }{SpellCaster Protocol Services Interface}
- \minor{0}{/dev/apscfg}{Configuration interface}
- \minor{1}{/dev/apsauth}{Authentication interface}
- \minor{2}{/dev/apslog}{Logging interface}
- \minor{3}{/dev/apsdbg}{Debugging interface}
- \minor{64}{/dev/apsisdn}{ISDN command interface}
- \minor{65}{/dev/apsasync}{Async command interface}
- \minor{128}{/dev/apsmon}{Monitor interface}
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI disk devices (96-111)}
- \minor{0}{/dev/sdcs}{97th SCSI disk whole disk}
- \minor{16}{/dev/sdct}{98th SCSI disk whole disk}
- \minor{32}{/dev/sdcu}{99th SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sddh}{112th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{71}{}{char }{Computone IntelliPort II serial card}
- \minor{0}{/dev/ttyF0}{IntelliPort II board 0, port 0}
- \minor{1}{/dev/ttyF1}{IntelliPort II board 0, port 1}
- \minordots
- \minor{63}{/dev/ttyF63}{IntelliPort II board 0, port 63}
- \minor{64}{/dev/ttyF64}{IntelliPort II board 1, port 0}
- \minor{65}{/dev/ttyF65}{IntelliPort II board 1, port 1}
- \minordots
- \minor{127}{/dev/ttyF127}{IntelliPort II board 1, port 63}
- \minor{128}{/dev/ttyF128}{IntelliPort II board 2, port 0}
- \minor{129}{/dev/ttyF129}{IntelliPort II board 2, port 1}
- \minordots
- \minor{191}{/dev/ttyF191}{IntelliPort II board 2, port 63}
- \minor{192}{/dev/ttyF192}{IntelliPort II board 3, port 0}
- \minor{193}{/dev/ttyF193}{IntelliPort II board 3, port 1}
- \minordots
- \minor{255}{/dev/ttyF255}{IntelliPort II board 3, port 63}
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{SCSI disk devices (112-127)}
- \minor{0}{/dev/sddi}{113th SCSI disk whole disk}
- \minor{16}{/dev/sddj}{114th SCSI disk whole disk}
- \minor{32}{/dev/sddk}{115th SCSI disk whole disk}
- \minordots
- \minor{240}{/dev/sddx}{128th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices}
- \minor{0}{/dev/cuf0}{Callout device corresponding to {\file ttyF0}}
- \minor{1}{/dev/cuf1}{Callout device corresponding to {\file ttyF1}}
- \minordots
- \minor{63}{/dev/cuf63}{Callout device corresponding to {\file ttyF63}}
- \minor{64}{/dev/cuf64}{Callout device corresponding to {\file ttyF64}}
- \minor{65}{/dev/cuf65}{Callout device corresponding to {\file ttyF65}}
- \minordots
- \minor{127}{/dev/cuf127}{Callout device corresponding to {\file ttyF127}}
- \minor{128}{/dev/cuf128}{Callout device corresponding to {\file ttyF128}}
- \minor{129}{/dev/cuf129}{Callout device corresponding to {\file ttyF129}}
- \minordots
- \minor{191}{/dev/cuf191}{Callout device corresponding to {\file ttyF191}}
- \minor{192}{/dev/cuf192}{Callout device corresponding to {\file ttyF192}}
- \minor{193}{/dev/cuf193}{Callout device corresponding to {\file ttyF193}}
- \minordots
- \minor{255}{/dev/cuf255}{Callout device corresponding to {\file ttyF255}}
-\end{devicelist}
-
-\begin{devicelist}
-\major{73}{}{char }{Computone IntelliPort II serial card -- control devices}
- \minor{0}{/dev/ip2ipl0}{Loadware device for board 0}
- \minor{1}{/dev/ip2stat0}{Status device for board 0}
- \minor{4}{/dev/ip2ipl1}{Loadware device for board 1}
- \minor{5}{/dev/ip2stat1}{Status device for board 1}
- \minor{8}{/dev/ip2ipl2}{Loadware device for board 2}
- \minor{9}{/dev/ip2stat2}{Status device for board 2}
- \minor{12}{/dev/ip2ipl3}{Loadware device for board 3}
- \minor{13}{/dev/ip2stat3}{Status device for board 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{74}{}{char }{SCI bridge}
- \minor{0}{/dev/SCI/0}{SCI device 0}
- \minor{1}{/dev/SCI/1}{SCI device 1}
- \minordots
-\end{devicelist}
-
-\noindent
-Currently for Dolphin Interconnect Solutions' PCI-SCI bridge.
-
-\begin{devicelist}
-\major{75}{}{char }{Specialix IO8+ serial card}
- \minor{0}{/dev/ttyW0}{First IO8+ port, first card}
- \minor{1}{/dev/ttyW1}{Second IO8+ port, first card}
- \minordots
- \minor{8}{/dev/ttyW8}{First IO8+ port, second card}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{76}{}{char }{Specialix IO8+ serial card -- alternate devices}
- \minor{0}{/dev/cuw0}{Callout device corresponding to {\file ttyW0}}
- \minor{1}{/dev/cuw1}{Callout device corresponding to {\file ttyW1}}
- \minordots
- \minor{8}{/dev/cuw8}{Callout device corresponding to {\file ttyW8}}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{77}{}{char }{ComScire Quantum Noise Generator}
- \minor{0}{/dev/qng}{ComScire Quantum Noise Generator}
-\end{devicelist}
-
-\begin{devicelist}
-\major{78}{}{char }{PAM Software's multimodem boards}
- \minor{0}{/dev/ttyM0}{First PAM modem}
- \minor{1}{/dev/ttyM1}{Second PAM modem}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{79}{}{char }{PAM Software's multimodem boards -- alternate devices}
- \minor{0}{/dev/cum0}{Callout device corresponding to {\file ttyM0}}
- \minor{1}{/dev/cum1}{Callout device corresponding to {\file ttyM1}}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{80}{}{char }{Photometrics AT200 CCD camera}
- \minor{0}{/dev/at200}{Photometrics AT200 CCD camera}
-\end{devicelist}
-
-\begin{devicelist}
-\major{81}{}{char }{video4linux}
- \minor{0}{/dev/video0}{Video capture/overlay device}
- \minordots
- \minor{63}{/dev/video63}{Video capture/overlay device}
- \minor{64}{/dev/radio0}{Radio device}
- \minordots
- \minor{127}{/dev/radio63}{Radio device}
- \minor{192}{/dev/vtx0}{Teletext device}
- \minordots
- \minor{223}{/dev/vtx31}{Teletext device}
- \minor{224}{/dev/vbi0}{Vertical blank interupt}
- \minordots
- \minor{255}{/dev/vbi31}{Vertical blank interupt}
-\end{devicelist}
-
-\begin{devicelist}
-\major{82}{}{char }{WiNRADiO communications receiver card}
- \minor{0}{/dev/winradio0}{First WiNRADiO card}
- \minor{1}{/dev/winradio1}{Second WiNRADiO card}
- \minordots
-\end{devicelist}
-
-\noindent
-The driver and documentation may be obtained from
-{\url http://www.proximity.com.au/~brian/winradio/\/}.
-
-\begin{devicelist}
-\major{83}{}{char }{Teletext/videotext interfaces}
- \minor{0}{/dev/vtx}{Teletext decoder}
- \minor{16}{/dev/vttuner}{TV tuner on teletext interface}
-\end{devicelist}
-
-\noindent
-Devices for the driver contained in the VideoteXt package. More information
-on {\url http://home.pages.de/~videotext/\/}.
-
-\begin{devicelist}
-\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
- \minor{0}{/dev/ihcp0}{First Greensheet port}
- \minor{1}{/dev/ihcp1}{Second Greensheet port}
-\end{devicelist}
-
-\begin{devicelist}
-\major{85}{}{char }{Linux/SGI shared memory input queue}
- \minor{0}{/dev/shmiq}{Master shared input queue}
- \minor{1}{/dev/qcntl0}{First device pushed}
- \minor{2}{/dev/qcntl1}{Second device pushed}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{86}{}{char }{SCSI media changer}
- \minor{0}{/dev/sch0}{First SCSI media changer}
- \minor{1}{/dev/sch1}{Second SCSI media changer}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{87}{}{char }{Sony Control-A1 stereo control bus}
- \minor{0}{/dev/controla0}{First device on chain}
- \minor{1}{/dev/controla1}{Second device on chain}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{88}{}{char }{COMX synchronous serial card}
- \minor{0}{/dev/comx0}{Channel 0}
- \minor{1}{/dev/comx1}{Channel 1}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hdm}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdn}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{89}{}{char }{I$^2$C bus interface}
- \minor{0}{/dev/i2c0}{First I$^2$C adapter}
- \minor{1}{/dev/i2c1}{Second I$^2$C adapter}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hdo}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdp}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
- \minor{0}{/dev/mtd0}{First MTD (rw)}
- \minor{1}{/dev/mtdr0}{First MTD (ro)}
- \minordots
- \minor{30}{/dev/mtd15}{16th MTD (rw)}
- \minor{31}{/dev/mtdr15}{16th MTD (ro)}
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hdq}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdr}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{91}{}{char }{CAN-Bus controller}
- \minor{0}{/dev/can0}{First CAN-Bus controller}
- \minor{1}{/dev/can1}{Second CAN-Bus controller}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{ }{}{block}{Tenth IDE hard disk/CD-ROM interface}
- \minor{0}{/dev/hds}{Master: whole disk (or CD-ROM)}
- \minor{64}{/dev/hdt}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card}
-\end{devicelist}
-
-\begin{devicelist}
-\major{93}{}{char }{IBM Smart Capture Card frame grabber}
- \minor{0}{/dev/iscc0}{First Smart Capture Card}
- \minor{1}{/dev/iscc1}{Second Smart Capture Card}
- \minordots
- \minor{128}{/dev/isccctl0}{First Smart Capture Card control}
- \minor{129}{/dev/isccctl1}{Second Smart Capture Card control}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{94}{}{char }{miroVIDEO DC10/30 capture/playback device}
- \minor{0}{/dev/dcxx0}{First capture card}
- \minor{1}{/dev/dcxx1}{Second capture card}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{95}{}{char }{IP filter}
- \minor{0}{/dev/ipl}{Filter control device/log file}
- \minor{1}{/dev/ipnat}{NAT control device/log file}
- \minor{2}{/dev/ipstate}{State information log file}
- \minor{3}{/dev/ipauth}{Authentication control device/log file}
-\end{devicelist}
-
-\begin{devicelist}
-\major{96}{}{char }{Parallel port ATAPI tape devices}
- \minor{0}{/dev/pt0}{First parallel port ATAPI tape}
- \minor{1}{/dev/pt1}{Second parallel port ATAPI tape}
- \minor{2}{/dev/pt2}{Third parallel port ATAPI tape}
- \minor{3}{/dev/pt3}{Fourth parallel port ATAPI tape}
- \minor{128}{/dev/npt0}{First parallel port ATAPI tape, no rewind}
- \minor{129}{/dev/npt1}{Second parallel port ATAPI tape, no rewind}
- \minor{130}{/dev/npt2}{Third parallel port ATAPI tape, no rewind}
- \minor{131}{/dev/npt3}{Fourth parallel port ATAPI tape, no rewind}
-\end{devicelist}
-
-\begin{devicelist}
-\major{97}{}{char }{Parallel port generic ATAPI interface}
- \minor{0}{/dev/pg0}{First parallel port ATAPI device}
- \minor{1}{/dev/pg1}{Second parallel port ATAPI device}
- \minor{2}{/dev/pg2}{Third parallel port ATAPI device}
- \minor{3}{/dev/pg3}{Fourth parallel port ATAPI device}
-\end{devicelist}
-
-\noindent
-These devices support the same API as the generic SCSI devices.
-
-\begin{devicelist}
-\major{98}{}{char }{Control and Mesurement Device (comedi)}
- \minor{0}{/dev/comedi0}{First comedi device}
- \minor{1}{/dev/comedi1}{Second comedi device}
- \minordots
-\end{devicelist}
-
-\noindent
-See {\url http://stm.lbl.gov/comedi/} or {\url
-http://www.llp.fu-berlin.de/}.
-
-\begin{devicelist}
-\major{99}{}{char }{Raw parallel ports}
- \minor{0}{/dev/parport0}{First parallel port}
- \minor{1}{/dev/parport1}{Second parallel port}
- \minordots
-\end{devicelist}
-
-\noindent
-These devices can be used to drive parallel port devices from
-user-space while interacting with the parport sharing code.
-
-\begin{devicelist}
-\major{100}{}{char }{POTS (analogue telephone) A/B port}
- \minor{0}{/dev/phone0}{First telephone port}
- \minor{1}{/dev/phone1}{Second telephone port}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{101}{}{char }{Motorola DSP 56xxx board}
- \minor{0}{/dev/mdspstat}{Status information}
- \minor{1}{/dev/mdsp1}{First DSP board I/O and controls}
- \minordots
- \minor{16}{/dev/mdsp16}{16th DSP board I/O and controls}
-\end{devicelist}
-
-\begin{devicelist}
-\major{102}{}{char }{Philips SAA5249 Teletext signal decoder}
- \minor{0}{/dev/tlk0}{First Teletext decoder}
- \minor{1}{/dev/tlk1}{Second Teletext decoder}
- \minor{2}{/dev/tlk2}{Third Teletext decoder}
- \minor{3}{/dev/tlk3}{Fourth Teletext decoder}
-\end{devicelist}
-
-\begin{devicelist}
-\major{103}{}{char }{Arla network file system}
- \minor{0}{/dev/xfs0}{Arla XFS}
-\end{devicelist}
-
-\noindent
-Arla is a free clone of the Andrew File System, AFS. Any resemblance
-with the Swedish milk producer is coincidental. For more information
-about the project, write to $<$arla-drinkers@stacken.kth.se$>$ or
-subscribe to the arla-announce mailing list by sending a mail to
-$<$arla-announce-request@stacken.kth.se$>$.
-
-\begin{devicelist}
-\major{104}{}{char }{Flash BIOS support}
-\end{devicelist}
-
-\begin{devicelist}
-\major{105}{}{char }{Comtrol VS-1000 serial card}
- \minor{0}{/dev/ttyV0}{First VS-1000 port}
- \minor{1}{/dev/ttyV1}{Second VS-1000 port}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{106}{}{char }{Comtrol VS-1000 serial card -- alternate devices}
- \minor{0}{/dev/cuv0}{Callout device corresponding to {\file ttyV0}}
- \minor{1}{/dev/cuv1}{Callout device corresponding to {\file ttyV1}}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{107}{}{char }{3Dfx Voodoo Graphics device}
- \minor{0}{/dev/3dfx}{Primary 3Dfx graphics device}
-\end{devicelist}
-
-\begin{devicelist}
-\major{108}{}{char }{Device independent PPP interface}
- \minor{0}{/dev/ppp}{Device independent PPP interface}
-\end{devicelist}
-
-\begin{devicelist}
-\major{109}{}{char }{Reserved for logical volume manager}
-\end{devicelist}
-
-\begin{devicelist}
-\major{110}{}{char }{miroMEDIA Surround board}
- \minor{0}{/dev/srnd0}{First miroMEDIA Surround board}
- \minor{1}{/dev/srnd1}{First miroMEDIA Surround board}
- \minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{111}{--119}{}{Unallocated}
-\end{devicelist}
-
-\begin{devicelist}
-\major{120}{--127}{}{Local/experimental use}
-\end{devicelist}
-
-\begin{devicelist}
-\major{128}{--135}{char }{Unix98 PTY masters}
-\end{devicelist}
-
-\noindent
-These devices should not have corresponding device nodes; instead they
-should be accessed through the {\file /dev/ptmx} cloning device.
-
-\begin{devicelist}
-\major{136}{--143}{char }{Unix98 PTY slaves}
- \minor{0}{/dev/pts/0}{First Unix98 pseudo-TTY}
- \minor{1}{/dev/pts/1}{Second Unix98 pseudo-TTY}
- \minordots
-\end{devicelist}
-
-\noindent
-These device nodes are automatically generated with the proper
-permissions and modes by mounting the {\file devpts} filesystem onto
-{\file /dev/pts} with the appropriate mount options (distribution
-dependent.)
-
-\begin{devicelist}
-\major{144}{--239}{}{Unallocated}
-\end{devicelist}
-
-\begin{devicelist}
-\major{240}{--254}{}{Local/experimental use}
-\end{devicelist}
-
-\begin{devicelist}
-\major{255}{}{}{Reserved}
-\end{devicelist}
-
-\noindent
-This major is reserved to assist the expansion to a larger number
-space. No device nodes with this major should ever be created on any
-filesystem.
-
-\section{Additional /dev directory entries}
-
-This section details additional entries that should or may exist in the
-{\file /dev} directory. It is preferred that symbolic links use the
-same form (absolute or relative) as is indicated here. Links are
-classified as {\em hard\/} or {\em symbolic\/} depending on the
-preferred type of link; if possible, the indicated type of link should
-be used.
-
-\subsection{Compulsory links}
-
-These links should exist on all systems:
-
-\begin{nodelist}
-\link{/dev/fd}{/proc/self/fd}{symbolic}{File descriptors}
-\link{/dev/stdin}{fd/0}{symbolic}{Standard input file descriptor}
-\link{/dev/stdout}{fd/1}{symbolic}{Standard output file descriptor}
-\link{/dev/stderr}{fd/2}{symbolic}{Standard error file descriptor}
-\link{/dev/nfsd}{socksys}{symbolic}{Required by iBCS-2}
-\link{/dev/X0R}{null}{symbolic}{Required by iBCS-2}
-\end{nodelist}
-
-\noindent
-Note: The last device is: $<$letter {\tt X}$>$-$<$digit {\tt
-0}$>$-$<$letter {\tt R}$>$.
-
-\subsection{Recommended links}
-
-It is recommended that these links exist on all systems:
-
-\begin{nodelist}
-\link{/dev/core}{/proc/kcore}{symbolic}{Backward compatibility}
-\link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility}
-\link{/dev/ftape}{qft0}{symbolic}{Backward compatibility}
-\link{/dev/bttv0}{video0}{symbolic}{Backward compatibility}
-\link{/dev/radio}{radio0}{symbolic}{Backward compatibility}
-\link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs}
-\end{nodelist}
-
-\subsection{Locally defined links}
-
-The following links may be established locally to conform to the
-configuration of the system. This is merely a tabulation of existing
-practice, and does not constitute a recommendation. However, if they
-exist, they should have the following uses.
-
-\begin{nodelist}
-\vlink{/dev/mouse}{mouse port}{symbolic}{Current mouse device}
-\vlink{/dev/tape}{tape device}{symbolic}{Current tape device}
-\vlink{/dev/cdrom}{CD-ROM device}{symbolic}{Current CD-ROM device}
-\vlink{/dev/cdwriter}{CD-writer}{symbolic}{Current CD-writer device}
-\vlink{/dev/scanner}{scanner device}{symbolic}{Current scanner device}
-\vlink{/dev/modem}{modem port}{symbolic}{Current dialout device}
-\vlink{/dev/root}{root device}{symbolic}{Current root filesystem}
-\vlink{/dev/swap}{swap device}{symbolic}{Current swap device}
-\end{nodelist}
-
-\noindent
-{\file /dev/modem} should not be used for a modem which supports
-dialin as well as dialout, as it tends to cause lock file problems.
-If it exists, {\file /dev/modem} should point to the appropriate
-primary TTY device (the use of the alternate callout devices is
-deprecated.)
-
-For SCSI devices, {\file /dev/tape} and {\file /dev/cdrom} should
-point to the ``cooked'' devices ({\file /dev/st*} and {\file
-/dev/sr*}, respectively), whereas {\file /dev/cdwriter} and {\file
-/dev/scanner} should point to the appropriate generic SCSI devices
-({\file /dev/sg*}).
-
-{\file /dev/mouse} may point to a primary serial TTY device, a
-hardware mouse device, or a socket for a mouse driver program
-(e.g. {\file /dev/gpmdata}).
-
-\subsection{Sockets and pipes}
-
-Non-transient sockets or named pipes may exist in {\file /dev}.
-Common entries are:
-
-\begin{nodelist}
-\node{/dev/printer}{socket}{{\file lpd} local socket}
-\node{/dev/log}{socket}{{\file syslog} local socket}
-\node{/dev/gpmdata}{socket}{{\file gpm} mouse multiplexer}
-\end{nodelist}
-
-\section{Terminal devices}
-
-Terminal, or TTY devices are a special class of character devices. A
-terminal device is any device that could act as a controlling terminal
-for a session; this includes virtual consoles, serial ports, and
-pseudoterminals (PTYs).
-
-All terminal devices share a common set of capabilities known as line
-diciplines; these include the common terminal line dicipline as well
-as SLIP and PPP modes.
-
-All terminal devices are named similarly; this section explains the
-naming and use of the various types of TTYs. Note that the naming
-conventions include several historical warts; some of these are
-Linux-specific, some were inherited from other systems, and some
-reflect Linux outgrowing a borrowed convention.
-
-A hash mark ($\#$) in a device name is in all cases used here to
-indicate a decimal number without leading zeroes.
-
-\subsection{Virtual consoles and the console device}
-
-Virtual consoles are full-screen terminal displays on the system video
-monitor. Virtual consoles are named {\file /dev/tty$\#$}, with
-numbering starting at {\file /dev/tty1}; {\file /dev/tty0} is the
-current virtual console. {\file /dev/tty0} is the device that should
-be used to access the system video card on those architectures for
-which the frame buffer devices ({\file /dev/fb*}) are not applicable.
-Do not use {\file /dev/console} for this purpose.
-
-The {\em console device\/}, {\file /dev/console}, is the device to
-which system messages should be sent, and on which logins should be
-permitted in single-user mode. Starting with Linux 2.1.71, {\file
-/dev/console} is managed by the kernel; for previous versions it
-should be a symbolic link to either {\file /dev/tty0}, a specific
-virtual console such as {\file /dev/tty1}, or to a serial port primary
-({\file tty*}, not {\file cu*}) device, depending on the configuration
-of the system.
-
-\subsection{Serial ports}
-
-Serial ports are RS-232 serial ports and any device which simulates
-one, either in hardware (such as internal modems) or in software (such
-as the ISDN driver.) Under Linux, each serial ports has two device
-names, the primary or callin device and the alternate or callout one.
-Each kind of device is indicated by a different letter. For any
-letter $X$, the names of the devices are {\file /dev/tty${X\#}$} and
-{\file /dev/cu${x\#}$}, respectively; for historical reasons, {\file
-/dev/ttyS$\#$} and {\file /dev/ttyC$\#$} correspond to {\file
-/dev/cua$\#$} and {\file /dev/cub$\#$}. In the future, it should be
-expected that multiple letters will be used; all letters will be upper
-case for the {\file tty} device (e.g. {\file /dev/ttyDP$\#$} and lower
-case for the {\file cu} device (e.g. {\file /dev/cudp$\#$}.
-
-The use of the callout devices is deprecated.
-
-The names {\file /dev/ttyQ$\#$} and {\file /dev/cuq$\#$} are reserved
-for local use.
-
-The alternate devices provide for kernel-based exclusion and somewhat
-different defaults than the primary devices. Their main purpose is to
-allow the use of serial ports with programs with no inherent or broken
-support for serial ports. Their use is deprecated, and they may be
-removed from a future version of Linux.
-
-Arbitration of serial ports is provided by the use of lock files with
-the names {\file /var/lock/LCK..tty${X\#}$}. The contents of the lock
-file should be the PID of the locking process as an ASCII number.
-
-It is common practice to install links such as {\file /dev/modem\/}
-which point to serial ports. In order to ensure proper locking in the
-presence of these links, it is recommended that software chase
-symlinks and lock all possible names; additionally, it is recommended
-that a lock file be installed with the corresponding alternate
-device. In order to avoid deadlocks, it is recommended that the locks
-are acquired in the following order, and released in the reverse:
-\begin{itemize}
-\item{The symbolic link name, if any ({\file /var/lock/LCK..modem})}
-\item{The {\file tty} name ({\file /var/lock/LCK..ttyS2})}
-\item{The alternate device name ({\file /var/lock/LCK..cua2})}
-\end{itemize}
-In the case of nested symbolic links, the lock files should be
-installed in the order the symlinks are resolved.
-
-Under no circumstances should an application hold a lock while waiting
-for another to be released. In addition, applications which attempt
-to create lock files for the corresponding alternate device names
-should take into account the possibility of being used on a non-serial
-port TTY, for which no alternate device would exist.
-
-\subsection{Pseudoterminals (PTYs)}
-
-Pseudoterminals, or PTYs, are used to create login sessions or provide
-other capabilities requiring a TTY line dicipline (including SLIP or
-PPP capability) to arbitrary data-generation processes. Each PTY has
-a {\em master\/} side, named {\file /dev/pty[p-za-e][0-9a-f]\/}, and a
-{\em slave\/} side, named {\file /dev/tty[p-za-e][0-9a-f]\/}. The
-kernel arbitrates the use of PTYs by allowing each master side to be
-opened only once.
-
-Once the master side has been opened, the corresponding slave device
-can be used in the same manner as any TTY device. The master and
-slave devices are connected by the kernel, generating the equivalent
-of a bidirectional pipe with TTY capabilities.
-
-Recent versions of the Linux kernels and GNU libc contain support for
-the System V/Unix98 naming scheme for PTYs, which assigns a common
-device {\file /dev/ptmx\/} to all the masters (opening it will
-automatically give you a previously unassigned PTY) and a subdirectory
-{\file /dev/pts\/} for the slaves; the slaves are named with decimal
-integers ({\file /dev/pts/$\#$\/} in our notation). This removes the
-problem of exhausting the namespace and enables the kernel to
-automatically create the device nodes for the slaves on demand using
-the {\file devpts\/} filesystem.
-
-\end{document}
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index c17b77188..6332b478e 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -1,7 +1,7 @@
LINUX ALLOCATED DEVICES
Maintained by H. Peter Anvin <hpa@zytor.com>
- Last revised: December 16, 1999
+ Last revised: March 23, 2000
This list is the Linux Device List, the official registry of allocated
device numbers and /dev directory nodes for the Linux operating
@@ -14,12 +14,15 @@ ftp://ftp.kernel.org/pub/linux/docs/device-list/. The LaTeX version
of this document is no longer maintained.
This document is included by reference into the Filesystem Hierarchy
-Standard (FHS). The FHS is available from http://www.pathname.com/fhs/.
+Standard (FHS). The FHS is available from http://www.pathname.com/fhs/.
Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
platform only. Allocations marked (68k/Atari) apply to Linux/68k on
the Atari platform only.
+The symbol {2.6} means the allocation is obsolete and scheduled for
+removal once kernel version 2.6 (or equivalent) is released.
+
This document is in the public domain. The author requests, however,
that semantically altered versions are not distributed without
permission of the author, assuming the author can be contacted without
@@ -198,7 +201,7 @@ Your cooperation is appreciated.
Older versions of the Linux kernel used this major
number for BSD PTY devices. As of Linux 2.1.115, this
- is no longer supported. Use major numbers 2 and 3.
+ is no longer supported. Use major numbers 2 and 3.
5 char Alternate TTY devices
0 = /dev/tty Current TTY device
@@ -304,8 +307,11 @@ Your cooperation is appreciated.
7 = /dev/amigamouse1 Second Amiga mouse
8 = /dev/smouse Simple serial mouse driver
9 = /dev/pc110pad IBM PC-110 digitizer pad
+ 10 = /dev/adbmouse Apple Desktop Bus mouse
+ 11 = /dev/vrtpanel Vr41xx embedded touch panel
+ 13 = /dev/vpcmouse Connectix Virtual PC Mouse
128 = /dev/beep Fancy beep device
- 129 = /dev/modreq Kernel module load request
+ 129 = /dev/modreq Kernel module load request {2.6}
130 = /dev/watchdog Watchdog timer port
131 = /dev/temperature Machine internal temperature
132 = /dev/hwtrap Hardware fault trap
@@ -318,7 +324,7 @@ Your cooperation is appreciated.
142 = /dev/msr x86 model-specific registers
143 = /dev/pciconf PCI configuration space
144 = /dev/nvram Non-volatile configuration RAM
- 145 = /dev/hfmodem Soundcard shortwave modem control
+ 145 = /dev/hfmodem Soundcard shortwave modem control {2.6}
146 = /dev/graphics Linux/SGI graphics device
147 = /dev/opengl Linux/SGI OpenGL pipe
148 = /dev/gfx Linux/SGI graphics effects device
@@ -352,6 +358,11 @@ Your cooperation is appreciated.
177 = /dev/cbm Serial CBM bus
178 = /dev/jsflash JavaStation OS flash SIMM
179 = /dev/xsvc High-speed shared-mem/semaphore service
+ 180 = /dev/vrbuttons Vr41xx button input device
+ 181 = /dev/toshiba Toshiba laptop SMM support
+ 182 = /dev/perfctr Performance-monitoring counters
+ 183 = /dev/intel_rng Intel i8x0 random number generator
+ 184 = /dev/cpu/microcode CPU microcode update interface
240-255 Reserved for local use
11 char Raw keyboard device
@@ -380,7 +391,7 @@ Your cooperation is appreciated.
The device names specified are proposed -- if there
are "standard" names for these devices, please let me know.
- block MSCDEX CD-ROM callback support
+ block MSCDEX CD-ROM callback support {2.6}
0 = /dev/dos_cd0 First MSCDEX CD-ROM
1 = /dev/dos_cd1 Second MSCDEX CD-ROM
...
@@ -407,7 +418,7 @@ Your cooperation is appreciated.
2 = /dev/midi00 First MIDI port
3 = /dev/dsp Digital audio
4 = /dev/audio Sun-compatible digital audio
- 6 = /dev/sndstat Sound card status information
+ 6 = /dev/sndstat Sound card status information {2.6}
7 = /dev/audioctl SPARC audio control device
8 = /dev/sequencer2 Sequencer -- alternate device
16 = /dev/mixer1 Second soundcard mixer control
@@ -418,7 +429,7 @@ Your cooperation is appreciated.
33 = /dev/patmgr1 Sequencer patch manager
34 = /dev/midi02 Third MIDI port
50 = /dev/midi03 Fourth MIDI port
- block BIOS harddrive callback support
+ block BIOS harddrive callback support {2.6}
0 = /dev/dos_hda First BIOS harddrive whole disk
64 = /dev/dos_hdb Second BIOS harddrive whole disk
128 = /dev/dos_hdc Third BIOS harddrive whole disk
@@ -549,7 +560,7 @@ Your cooperation is appreciated.
2 = /dev/sbpcd2 Panasonic CD-ROM controller 0 unit 2
3 = /dev/sbpcd3 Panasonic CD-ROM controller 0 unit 3
- 26 char Quanta WinVision frame grabber
+ 26 char Quanta WinVision frame grabber {2.6}
0 = /dev/wvisfgrab Quanta WinVision frame grabber
block Second Matsushita (Panasonic/SoundBlaster) CD-ROM
0 = /dev/sbpcd4 Panasonic CD-ROM controller 1 unit 0
@@ -569,7 +580,7 @@ Your cooperation is appreciated.
16 = /dev/zqft0 Unit 0, rewind-on-close, compression
17 = /dev/zqft1 Unit 1, rewind-on-close, compression
18 = /dev/zqft2 Unit 2, rewind-on-close, compression
- 19 = /dev/zqtf3 Unit 3, rewind-on-close, compression
+ 19 = /dev/zqft3 Unit 3, rewind-on-close, compression
20 = /dev/nzqft0 Unit 0, no rewind-on-close, compression
21 = /dev/nzqft1 Unit 1, no rewind-on-close, compression
22 = /dev/nzqft2 Unit 2, no rewind-on-close, compression
@@ -613,12 +624,11 @@ Your cooperation is appreciated.
disks (see major number 3) except that the limit on
partitions is 15, like SCSI.
- 29 char Universal frame buffers
+ 29 char Universal frame buffer
0 = /dev/fb0 First frame buffer
- 1 = /dev/fb1 Second frame buffer
- 2 = /dev/fb2 Third frame buffer
+ 32 = /dev/fb1 Second frame buffer
...
- 31 = /dev/fb31 32nd frame buffer
+ 224 = /dev/fb7 Eighth frame buffer
All additional minor numbers are reserved.
@@ -777,7 +787,7 @@ Your cooperation is appreciated.
...
block Reserved for Linux/AP+
- 40 char Matrox Meteor frame grabber
+ 40 char Matrox Meteor frame grabber {2.6}
0 = /dev/mmetfgrab Matrox Meteor frame grabber
block Syquest EZ135 parallel port removable drive
0 = /dev/eza Parallel EZ135 drive, whole disk
@@ -1265,7 +1275,7 @@ Your cooperation is appreciated.
disks (see major number 3) except that the limit on
partitions is 15.
- 83 char Teletext/videotext interfaces
+ 83 char Teletext/videotext interfaces {2.6}
0 = /dev/vtx Teletext decoder
16 = /dev/vttuner TV tuner on teletext interface
@@ -1356,8 +1366,8 @@ Your cooperation is appreciated.
89 char I2C bus interface
- 0 = /dev/i2c0 First I2C adapter
- 1 = /dev/i2c1 Second I2C adapter
+ 0 = /dev/i2c-0 First I2C adapter
+ 1 = /dev/i2c-1 Second I2C adapter
...
block Eighth IDE hard disk/CD-ROM interface
@@ -1404,7 +1414,7 @@ Your cooperation is appreciated.
disks (see major number 3) except that the limit on
partitions is 15.
- 93 char IBM Smart Capture Card frame grabber
+ 93 char IBM Smart Capture Card frame grabber {2.6}
0 = /dev/iscc0 First Smart Capture Card
1 = /dev/iscc1 Second Smart Capture Card
...
@@ -1418,7 +1428,7 @@ Your cooperation is appreciated.
...
240 = /dev/nftlp 16th NTFL layer
- 94 char miroVIDEO DC10/30 capture/playback device
+ 94 char miroVIDEO DC10/30 capture/playback device {2.6}
0 = /dev/dcxx0 First capture card
1 = /dev/dcxx1 Second capture card
...
@@ -1462,6 +1472,11 @@ Your cooperation is appreciated.
These devices support the same API as the generic SCSI
devices.
+ block Packet writing for CD/DVD devices
+ 0 = /dev/pktcdvd0 First packet-writing module
+ 1 = /dev/pktcdvd1 Second packet-writing module
+ ...
+
98 char Control and Measurement Device (comedi)
0 = /dev/comedi0 First comedi device
1 = /dev/comedi1 Second comedi device
@@ -1469,23 +1484,34 @@ Your cooperation is appreciated.
See http://stm.lbl.gov/comedi or http://www.llp.fu-berlin.de/.
+ block User-mode virtual block device
+ 0 = /dev/ubd0 First user-mode block device
+ 1 = /dev/ubd1 Second user-mode block device
+ ...
+
+ This device is used by the user-mode virtual kernel port.
+
99 char Raw parallel ports
0 = /dev/parport0 First parallel port
1 = /dev/parport1 Second parallel port
...
-100 char POTS (analogue telephone) A/B port
+100 char POTS (analogue telephone) A/B port {2.6}
0 = /dev/phone0 First telephone port
1 = /dev/phone1 Second telephone port
...
+ The names have been reallocated to Telephony For
+ Linux, major 159. All use of major 100 should be
+ considered legacy and deprecated.
+
101 char Motorola DSP 56xxx board
0 = /dev/mdspstat Status information
1 = /dev/mdsp1 First DSP board I/O controls
...
16 = /dev/mdsp16 16th DSP board I/O controls
-102 char Philips SAA5249 Teletext signal decoder
+102 char Philips SAA5249 Teletext signal decoder {2.6}
0 = /dev/tlk0 First Teletext decoder
1 = /dev/tlk1 Second Teletext decoder
2 = /dev/tlk2 Third Teletext decoder
@@ -1526,7 +1552,7 @@ Your cooperation is appreciated.
1 = /dev/srnd1 Second miroMEDIA Surround board
...
-111 char Philips SAA7146-based audio/video card
+111 char Philips SAA7146-based audio/video card {2.6}
0 = /dev/av0 First A/V card
1 = /dev/av1 Second A/V card
...
@@ -1562,7 +1588,7 @@ Your cooperation is appreciated.
Plays music using IBM BASIC style strings.
-116 char Advanced Linux System Driver (ALSA)
+116 char Advanced Linux Sound Driver (ALSA)
117 char COSA/SRP synchronous serial card
0 = /dev/cosa0c0 1st board, 1st channel
@@ -1691,9 +1717,9 @@ Your cooperation is appreciated.
1 = /dev/gfax1 GammaLink channel 1
...
-159 char Quicknet Technologies Internet PhoneJack/LineJack
- 0 = /dev/ixj0 First device
- 1 = /dev/ixj1 Second device
+159 char Telephony for Linux
+ 0 = /dev/phone0 First telephony device
+ 1 = /dev/phone1 Second telephony device
...
160 char General Purpose Instrument Bus (GPIB)
@@ -1735,9 +1761,9 @@ Your cooperation is appreciated.
63 = /dev/ttyCH63 AT/PCI-Fast board 3, port 15
165 char Chase Research AT/PCI-Fast serial card - alternate devices
- 0 = /dev/cuch0 Callout device corresponding to ttyCH0
+ 0 = /dev/cuch0 Callout device for ttyCH0
...
- 63 = /dev/cuch63 Callout device corresponding to ttyCH63
+ 63 = /dev/cuch63 Callout device for ttyCH63
166 char ACM USB modems
0 = /dev/ttyACM0 First ACM modem
@@ -1796,13 +1822,13 @@ Your cooperation is appreciated.
...
177 char TI PCILynx memory spaces
- 0 = /dev/pcilynx/aux0 AUX space of first PCILynx card
+ 0 = /dev/pcilynx/aux0 AUX space of first PCILynx card
...
15 = /dev/pcilynx/aux15 AUX space of 16th PCILynx card
- 16 = /dev/pcilynx/rom0 ROM space of first PCILynx card
+ 16 = /dev/pcilynx/rom0 ROM space of first PCILynx card
...
31 = /dev/pcilynx/rom15 ROM space of 16th PCILynx card
- 32 = /dev/pcilynx/ram0 RAM space of first PCILynx card
+ 32 = /dev/pcilynx/ram0 RAM space of first PCILynx card
...
47 = /dev/pcilynx/ram15 RAM space of 16th PCILynx card
@@ -1829,6 +1855,7 @@ Your cooperation is appreciated.
48 = /dev/usb/scanner0 First USB scanner
...
63 = /dev/usb/scanner15 16th USB scanner
+ 64 = /dev/usb/rio500 Diamond Rio 500
181 char Conrad Electronic parallel port radio clocks
0 = /dev/pcfclock0 First Conrad radio clock
@@ -1836,7 +1863,7 @@ Your cooperation is appreciated.
...
182 char Picture Elements THR2 binarizer
- 0 = /dev/pethr0 First THR2 board
+ 0 = /dev/pethr0 First THR2 board
1 = /dev/pethr1 Second THR2 board
...
@@ -1853,7 +1880,12 @@ Your cooperation is appreciated.
1 = /dev/pevss1 Second sender board
...
-185 char Reserved for InterMezzo high availability file system
+185 char InterMezzo high availability file system
+ 0 = /dev/intermezzo0 First cache manager
+ 1 = /dev/intermezzo1 Second cache manager
+ ...
+
+ See http://www.inter-mezzo.org/ for more information.
186 char Object-based storage control device
0 = /dev/obd0 First obd control device
@@ -1862,7 +1894,10 @@ Your cooperation is appreciated.
See ftp://ftp.lustre.org/pub/obd for code and information.
-187 char UNALLOCATED
+187 char DESkey hardware encryption device
+ 0 = /dev/deskey0 First DES key
+ 1 = /dev/deskey1 Second DES key
+ ...
188 char USB serial converters
0 = /dev/ttyUSB0 First USB serial converter
@@ -1870,11 +1905,46 @@ Your cooperation is appreciated.
...
189 char USB serial converters - alternate devices
- 0 = /dev/cuusb0 Callout device corresponding to ttyUSB0
- 1 = /dev/cuusb1 Callout device corresponding to ttyUSB1
+ 0 = /dev/cuusb0 Callout device for ttyUSB0
+ 1 = /dev/cuusb1 Callout device for ttyUSB1
...
-190-239 UNALLOCATED
+190 char Kansas City tracker/tuner card
+ 0 = /dev/kctt0 First KCT/T card
+ 1 = /dev/kctt1 Second KCT/T card
+ ...
+
+191 char Reserved for PCMCIA
+
+192 char Kernel profiling interface
+ 0 = /dev/profile Profiling control device
+ 1 = /dev/profile0 Profiling device for CPU 0
+ 2 = /dev/profile1 Profiling device for CPU 1
+ ...
+
+193 char Kernel event-tracing interface
+ 0 = /dev/trace Tracing control device
+ 1 = /dev/trace0 Tracing device for CPU 0
+ 2 = /dev/trace1 Tracing device for CPU 1
+ ...
+
+194 char linVideoStreams (LINVS)
+ 0 = /dev/mvideo/status0 Video compression status
+ 1 = /dev/mvideo/stream0 Video stream
+ 2 = /dev/mvideo/frame0 Single compressed frame
+ 3 = /dev/mvideo/rawframe0 Raw uncompressed frame
+ 4 = /dev/mvideo/codec0 Direct codec access
+ 5 = /dev/mvideo/video4linux0 Video4Linux compatibility
+
+ 16 = /dev/mvideo/status1 Second device
+ ...
+ 32 = /dev/mvideo/status2 Third device
+ ...
+ ...
+ 240 = /dev/mvideo/status15 16th device
+ ...
+
+195-239 UNALLOCATED
240-254 LOCAL/EXPERIMENTAL USE
@@ -1903,7 +1973,6 @@ These links should exist on all systems:
/dev/stderr fd/2 symbolic stderr file descriptor
/dev/nfsd socksys symbolic Required by iBCS-2
/dev/X0R null symbolic Required by iBCS-2
-/dev/i2o* /dev/i2o/* symbolic Backward compatibility
Note: /dev/X0R is <letter X>-<digit 0>-<letter R>.
@@ -1916,6 +1985,7 @@ It is recommended that these links exist on all systems:
/dev/ftape qft0 symbolic Backward compatibility
/dev/bttv0 video0 symbolic Backward compatibility
/dev/radio radio0 symbolic Backward compatibility
+/dev/i2o* /dev/i2o/* symbolic Backward compatibility
/dev/scd? sr? hard Alternate SCSI CD-ROM name
Locally defined links
@@ -1983,7 +2053,7 @@ monitor. Virtual consoles are named /dev/tty#, with numbering
starting at /dev/tty1; /dev/tty0 is the current virtual console.
/dev/tty0 is the device that should be used to access the system video
card on those architectures for which the frame buffer devices
-(/dev/fb*) are not applicable. Do not use /dev/console
+(/dev/fb*) are not applicable. Do not use /dev/console
for this purpose.
The console device, /dev/console, is the device to which system
@@ -2000,10 +2070,10 @@ Serial ports are RS-232 serial ports and any device which simulates
one, either in hardware (such as internal modems) or in software (such
as the ISDN driver.) Under Linux, each serial ports has two device
names, the primary or callin device and the alternate or callout one.
-Each kind of device is indicated by a different letter. For any
+Each kind of device is indicated by a different letter. For any
letter X, the names of the devices are /dev/ttyX# and /dev/cux#,
respectively; for historical reasons, /dev/ttyS# and /dev/ttyC#
-correspond to /dev/cua# and /dev/cub#. In the future, it should be
+correspond to /dev/cua# and /dev/cub#. In the future, it should be
expected that multiple letters will be used; all letters will be upper
case for the "tty" device (e.g. /dev/ttyDP#) and lower case for the
"cu" device (e.g. /dev/cudp#).
@@ -2017,7 +2087,7 @@ support for serial ports. Their use is deprecated, and they may be
removed from a future version of Linux.
Arbitration of serial ports is provided by the use of lock files with
-the names /var/lock/LCK..ttyX#. The contents of the lock file should
+the names /var/lock/LCK..ttyX#. The contents of the lock file should
be the PID of the locking process as an ASCII number.
It is common practice to install links such as /dev/modem
@@ -2025,7 +2095,7 @@ which point to serial ports. In order to ensure proper locking in the
presence of these links, it is recommended that software chase
symlinks and lock all possible names; additionally, it is recommended
that a lock file be installed with the corresponding alternate
-device. In order to avoid deadlocks, it is recommended that the locks
+device. In order to avoid deadlocks, it is recommended that the locks
are acquired in the following order, and released in the reverse:
1. The symbolic link name, if any (/var/lock/LCK..modem)
@@ -2045,7 +2115,7 @@ port TTY, for which no alternate device would exist.
Pseudoterminals, or PTYs, are used to create login sessions or provide
other capabilities requiring a TTY line dicipline (including SLIP or
-PPP capability) to arbitrary data-generation processes. Each PTY has
+PPP capability) to arbitrary data-generation processes. Each PTY has
a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named
/dev/tty[p-za-e][0-9a-f]. The kernel arbitrates the use of PTYs by
allowing each master side to be opened only once.
diff --git a/Documentation/isapnp.txt b/Documentation/isapnp.txt
index 4054ecf2f..4cb7a9b59 100644
--- a/Documentation/isapnp.txt
+++ b/Documentation/isapnp.txt
@@ -64,10 +64,10 @@ extern struct pci_bus *isapnp_find_card(unsigned short vendor,
unsigned short device,
struct pci_bus *from);
-The above function finds a ISA PnP card. For the vendor device should
+This function finds a ISA PnP card. For the vendor device should
be used ISAPNP_VENDOR(a,b,c) where a,b,c are characters or integers.
For the device number should be used ISAPNP_DEVICE(x) macro where x is
-integer value. Both vendor and device numbers can be get from contents
+integer value. Both vendor and device numbers can be taken from contents
of the /proc/isapnp file.
extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
@@ -75,12 +75,37 @@ extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
unsigned short function,
struct pci_dev *from);
-The above function finds the ISA PnP device. If card is NULL, then
+This function finds the ISA PnP device. If card is NULL, then
the global search mode is used (all devices are used for the searching).
Otherwise only devices which belongs to the specified card are verified.
For the function number can be used ISAPNP_FUNCTION(x) macro which works
similarly as the ISAPNP_DEVICE(x) macro.
+extern int isapnp_probe_cards(const struct isapnp_card_id *ids,
+ int (*probe)(struct pci_bus *card,
+ const struct isapnp_card_id *id));
+
+
+This function is a helper for drivers which requires to use more than
+one device from an ISA PnP card. For each cards is called the probe
+callback with appropriate information.
+
+Example for ids parameter initialization:
+
+static struct isapnp_card_id ids[] __devinitdata = {
+ {
+ ISAPNP_CARD_ID('A','D','V', 0x550a),
+ devs: {
+ ISAPNP_DEVICE_ID('A', 'D', 'V', 0x0010),
+ ISAPNP_DEVICE_ID('A', 'D', 'V', 0x0011)
+ },
+ driver_data: 0x1234,
+ },
+ {
+ ISAPNP_CARD_END,
+ }
+};
+
ISA PnP configuration
=====================
@@ -99,19 +124,25 @@ otherwise the access to the ISA PnP configuration functions will be blocked.
Second way is auto-configuration
--------------------------------
-These two functions gives to the driver the real power of the ISA PnP
-feature. First function dev->prepare() only initialize the resource
-members in the device structure. This structure contains all resources
-set to auto configuration values after the initialization. The driver for
-ISA PnP device may modify (or not) some resources to skip auto configuration
-for the given resource.
+This feature gives to the driver the real power of the ISA PnP code.
+Function dev->prepare() initializes the resource members in the device
+structure. This structure contains all resources set to auto configuration
+values after the initialization. The device driver may modify some resources
+to skip the auto configuration for a given resource.
-The function isapnp_configure does:
- - resources which have the auto configuration value are configured
+Once the device structure contains all requested resource values, the function
+dev->activate() must be called to assign free resources to resource members
+with the auto configuration value.
+
+Function dev->activate() does:
+ - resources with the auto configuration value are configured
- the auto configuration is created using ISA PnP resource map
- the function writes configuration to ISA PnP configuration registers
- the function returns to the caller actual used resources
+When the device driver is removing, function dev->deactivate() has to be
+called to free all assigned resources.
+
Example (game port initialization)
==================================
diff --git a/Documentation/isdn/README.eicon b/Documentation/isdn/README.eicon
index 73d8c92dd..87b40c6dd 100644
--- a/Documentation/isdn/README.eicon
+++ b/Documentation/isdn/README.eicon
@@ -1,4 +1,4 @@
-$Id: README.eicon,v 1.6 2000/01/27 09:54:44 armin Exp $
+$Id: README.eicon,v 1.7 2000/03/06 16:38:43 armin Exp $
(c) 1999,2000 Armin Schindler (mac@melware.de)
(c) 1999,2000 Cytronics & Melware (info@melware.de)
@@ -78,6 +78,10 @@ Example for loading and starting a BRI card with E-DSS1 Protocol.
eiconctrl [-d DriverId] load etsi
+Example for a BRI card with E-DSS1 Protocol with PtP configuration.
+
+ eiconctrl [-d DriverId] load etsi -n -t0 -s1
+
Example for loading and starting a PRI card with E-DSS1 Protocol.
diff --git a/Documentation/networking/tlan.txt b/Documentation/networking/tlan.txt
index 4e1347395..1485930fb 100644
--- a/Documentation/networking/tlan.txt
+++ b/Documentation/networking/tlan.txt
@@ -1,8 +1,8 @@
(C) 1997-1998 Caldera, Inc.
(C) 1998 James Banks
-(C) 1999-2000 Torben Mathiasen <torben.mathiasen@compaq.com>
+(C) 1999-2000 Torben Mathiasen <tmm@image.dk, torben.mathiasen@compaq.com>
-TLAN driver for Linux, version 1.3
+TLAN driver for Linux, version 1.5
README
diff --git a/Documentation/networking/tulip.txt b/Documentation/networking/tulip.txt
index ecef178b0..f4b553705 100644
--- a/Documentation/networking/tulip.txt
+++ b/Documentation/networking/tulip.txt
@@ -125,7 +125,7 @@ them. The MII transceiver status is polled using an kernel timer.
Source tree tour
-----------------
+================
The following is a list of files comprising the Tulip ethernet driver in
drivers/net/tulip subdirectory.
@@ -140,5 +140,24 @@ tulip_core.c - Driver core (a.k.a. where "everything else" goes)
+Version history
+===============
+0.9.4.2 (March 21, 2000):
+* Fix 21041 CSR7, CSR13/14/15 handling
+* Merge some PCI ids from tulip 0.91x
+* Merge some HAS_xxx flags and flag settings from tulip 0.91x
+* asm/io.h fix (submitted by many) and cleanup
+* s/HAS_NWAY143/HAS_NWAY/
+* Cleanup 21041 mode reporting
+* Small code cleanups
+
+0.9.4.1 (March 18, 2000):
+* Finish PCI DMA conversion (davem)
+* Do not netif_start_queue() at end of tulip_tx_timeout() (kuznet)
+* PCI DMA fix (kuznet)
+* eeprom.c code cleanup
+* Remove Xircom Tulip crud
+
+
[EOF]
diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README
index 4d8298772..868feedb9 100644
--- a/Documentation/video4linux/bttv/README
+++ b/Documentation/video4linux/bttv/README
@@ -84,6 +84,13 @@ trouble with some specific TV card, try to ask there instead of
mailing me directly. The chance that someone with the same card
listens there is much higher...
+For problems with sound: There are alot of different systems used
+for TV sound all over the world. And there are also different chips
+which decode the audio signal. Reports about sound problems ("stereo
+does'nt work") are pretty useless unless you include some details
+about your hardware and the TV sound scheme used in your country (or
+at least the country you are living in).
+
Finally: If you mail some patches for bttv around the world (to
linux-kernel/Alan/Linus/...), please Cc: me.
diff --git a/MAINTAINERS b/MAINTAINERS
index f03fbb625..932d4dd44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -495,36 +495,32 @@ S: Maintained
IEEE 1394 SUBSYSTEM
P: Andreas Bombe
M: andreas.bombe@munich.netsurf.de
-L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
+L: linux1394-devel@lists.sourceforge.net
+W: http://linux1394.sourceforge.net/
S: Maintained
IEEE 1394 AIC5800 DRIVER
P: Emanuel Pirker
M: epirker@edu.uni-klu.ac.at
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
IEEE 1394 OHCI DRIVER
P: Sebastien Rougeaux
M: sebastien.rougeaux@anu.edu.au
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
IEEE 1394 PCILYNX DRIVER
P: Andreas Bombe
M: andreas.bombe@munich.netsurf.de
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
IEEE 1394 RAW I/O DRIVER
P: Andreas Bombe
M: andreas.bombe@munich.netsurf.de
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
@@ -1027,6 +1023,7 @@ S: Maintained
TLAN NETWORK DRIVER
P: Torben Mathiasen
M: torben.mathiasen@compaq.com
+M: tmm@image.dk
L: tlan@vuser.vu.union.edu
S: Maintained
@@ -1136,6 +1133,13 @@ L: linux-usb@suse.com
S: Maintained
W: http://www.kroah.com/linux-usb/
+USB MASS STORAGE DRIVER
+P: Matthew Dharm
+M: mdharm-usb@one-eyed-alien.net
+L: linux-usb@suse.com
+S: Maintained
+W: http://www.one-eyed-alien.net/~mdharm/linux-usb/
+
USB UHCI DRIVER
P: Georg Acher
M: usb@in.tum.de
diff --git a/Makefile b/Makefile
index e3f5fff90..8558b0ef3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 3
SUBLEVEL = 99
-EXTRAVERSION = -pre2
+EXTRAVERSION = -pre3
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -86,6 +86,9 @@ endif
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
AFLAGS := $(CPPFLAGS)
+# use '-fno-strict-aliasing', but only if the compiler can take it
+CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
+
export CPPFLAGS CFLAGS AFLAGS
#
@@ -139,7 +142,7 @@ DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.a
DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.a
DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.a
DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnet.a
-DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.a
+DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
DRIVERS-$(CONFIG_IDE) += drivers/ide/ide.a
DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsi.a
DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394.a
@@ -175,14 +178,10 @@ DRIVERS += $(DRIVERS-y)
include arch/$(ARCH)/Makefile
-export CORE_FILES NETWORKS DRIVERS LIBS HEAD LDFLAGS LIBS LINKFLAGS \
- MAKEBOOT ASFLAGS
-
-# use '-fno-strict-aliasing', but only if the compiler can take it
-CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
+export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.s $<
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -traditional -o $*.s $<
.S.o:
$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
@@ -395,6 +394,7 @@ mrproper: clean archmrproper
rm -f .hdepend scripts/mkdep scripts/split-include scripts/docproc
rm -f $(TOPDIR)/include/linux/modversions.h
rm -rf $(TOPDIR)/include/linux/modules
+ make clean TOPDIR=$(TOPDIR) -C Documentation/DocBook
distclean: mrproper
find . -type f \( -name core -o -name '*.orig' -o -name '*.rej' \
diff --git a/Rules.make b/Rules.make
index 6f8a10f2e..b1dd7c429 100644
--- a/Rules.make
+++ b/Rules.make
@@ -244,7 +244,7 @@ $(TOPDIR)/include/linux/modversions.h:
endif # CONFIG_MODVERSIONS
ifneq "$(strip $(SYMTAB_OBJS))" ""
-$(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h $(SYMTAB_OBJS:.o=.c)
+$(SYMTAB_OBJS): $(SYMTAB_OBJS:.o=.c) $(TOPDIR)/include/linux/modversions.h
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c)
@ ( \
echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index d70d42421..d73afb558 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -55,7 +55,7 @@ choice 'Alpha system type' \
# clear all implied options (don't want default values for those):
unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6
-unset CONFIG_PCI CONFIG_ISA CONFIG_ALPHA_EISA
+unset CONFIG_ALPHA_EISA
unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
@@ -66,10 +66,13 @@ unset CONFIG_ALPHA_BROKEN_IRQ_MASK
# and this doesn't activate hordes of code, so do it always.
define_bool CONFIG_ISA y
-if [ "$CONFIG_ALPHA_GENERIC" = "y" ]
+if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
then
+ define_bool CONFIG_PCI n
+else
define_bool CONFIG_PCI y
fi
+
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]
then
define_bool CONFIG_ALPHA_NONAME y
@@ -77,22 +80,18 @@ fi
if [ "$CONFIG_ALPHA_NONAME" = "y" -o "$CONFIG_ALPHA_EB66" = "y" \
-o "$CONFIG_ALPHA_EB66P" = "y" -o "$CONFIG_ALPHA_P2K" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV4 y
define_bool CONFIG_ALPHA_LCA y
fi
if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_XL" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV4 y
define_bool CONFIG_ALPHA_APECS y
fi
if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
- -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" \
- -o "$CONFIG_ALPHA_TAKARA" = "y" ]
+ -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV5 y
define_bool CONFIG_ALPHA_CIA y
fi
@@ -107,11 +106,9 @@ then
define_bool CONFIG_ALPHA_EV4 y
define_bool CONFIG_ALPHA_APECS y
fi
- define_bool CONFIG_PCI y
fi
if [ "$CONFIG_ALPHA_SABLE" = "y" ]
then
- define_bool CONFIG_PCI y
bool 'EV5 CPU(s) (model 5/xxx)?' CONFIG_ALPHA_GAMMA
if [ "$CONFIG_ALPHA_GAMMA" = "y" ]
then
@@ -124,26 +121,22 @@ fi
if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \
-o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV5 y
define_bool CONFIG_ALPHA_CIA y
define_bool CONFIG_ALPHA_PYXIS y
fi
if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV6 y
define_bool CONFIG_ALPHA_TSUNAMI y
fi
if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV5 y
define_bool CONFIG_ALPHA_MCPCIA y
fi
if [ "$CONFIG_ALPHA_RX164" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV5 y
define_bool CONFIG_ALPHA_POLARIS y
fi
@@ -153,7 +146,6 @@ then
fi
if [ "$CONFIG_ALPHA_NAUTILUS" = "y" ]
then
- define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_EV6 y
define_bool CONFIG_ALPHA_IRONGATE y
fi
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index c4752a216..03be84794 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -1,6 +1,7 @@
#
# Automatically generated make config: don't edit
#
+# CONFIG_UID16 is not set
#
# Code maturity level options
@@ -44,7 +45,9 @@ CONFIG_ALPHA_GENERIC=y
# CONFIG_ALPHA_SX164 is not set
# CONFIG_ALPHA_SABLE is not set
# CONFIG_ALPHA_TAKARA is not set
+CONFIG_ISA=y
CONFIG_PCI=y
+CONFIG_ALPHA_BROKEN_IRQ_MASK=y
# CONFIG_SMP is not set
CONFIG_PCI_NAMES=y
# CONFIG_HOTPLUG is not set
@@ -58,6 +61,10 @@ CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_BINFMT_EM86=y
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
#
@@ -70,7 +77,10 @@ CONFIG_BINFMT_EM86=y
# Block devices
#
CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
#
# Additional Block Devices
@@ -79,10 +89,6 @@ CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
#
# Networking options
@@ -113,11 +119,14 @@ CONFIG_SKB_LARGE=y
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
#
# ATA/IDE/MFM/RLL support
#
# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
@@ -128,9 +137,11 @@ CONFIG_SCSI=y
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
# CONFIG_CHR_DEV_ST is not set
CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
# CONFIG_CHR_DEV_SG is not set
#
@@ -144,6 +155,7 @@ CONFIG_SCSI_CONSTANTS=y
#
# SCSI low-level drivers
#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -178,6 +190,7 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_QLOGIC_FAS is not set
CONFIG_SCSI_QLOGIC_ISP=y
# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
@@ -194,6 +207,7 @@ CONFIG_NETDEVICES=y
#
# CONFIG_ARCNET is not set
CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_NET_SB1000 is not set
@@ -207,15 +221,17 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
-# CONFIG_DEC_ELCP is not set
+# CONFIG_TULIP is not set
# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_EEPRO100 is not set
# CONFIG_NE2K_PCI is not set
+# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
@@ -236,7 +252,7 @@ CONFIG_DE4X5=y
# CONFIG_NET_RADIO is not set
#
-# Token Ring driver support
+# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
@@ -321,15 +337,20 @@ CONFIG_PSMOUSE=y
# CONFIG_USB is not set
#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
@@ -337,7 +358,10 @@ CONFIG_ISO9660_FS=y
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
@@ -349,6 +373,7 @@ CONFIG_EXT2_FS=y
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
# CONFIG_NFSD is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
@@ -361,8 +386,6 @@ CONFIG_LOCKD=y
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_OSF_PARTITION=y
CONFIG_MSDOS_PARTITION=y
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c
index 51e5b1174..41143ff99 100644
--- a/arch/alpha/kernel/core_apecs.c
+++ b/arch/alpha/kernel/core_apecs.c
@@ -376,9 +376,13 @@ apecs_init_arch(void)
pci_isa_hose = hose = alloc_pci_controler();
hose->io_space = &ioport_resource;
hose->mem_space = &iomem_resource;
- hose->config_space = APECS_CONF;
hose->index = 0;
+ hose->sparse_mem_base = APECS_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = APECS_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = APECS_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
/*
* Set up the PCI to main memory translation windows.
*
diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c
index 481a682b1..88c88a4e6 100644
--- a/arch/alpha/kernel/core_cia.c
+++ b/arch/alpha/kernel/core_cia.c
@@ -529,7 +529,7 @@ verify_tb_operation(void)
/* Fifth, verify that a previously invalid PTE entry gets
filled from the page table. */
- data0 = 0xabcdef123;
+ data0 = 0xabcdef12;
page[0] = data0;
arena->ptes[5] = pte0;
mcheck_expected(0) = 1;
@@ -640,7 +640,6 @@ do_init_arch(int is_pyxis)
pci_isa_hose = hose = alloc_pci_controler();
hose->io_space = &ioport_resource;
hose->mem_space = &iomem_resource;
- hose->config_space = CIA_CONF;
hose->index = 0;
if (! is_pyxis) {
@@ -654,6 +653,16 @@ do_init_arch(int is_pyxis)
if (request_resource(&iomem_resource, hae_mem) < 0)
printk(KERN_ERR "Failed to request HAE_MEM\n");
+
+ hose->sparse_mem_base = CIA_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = CIA_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = CIA_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+ } else {
+ hose->sparse_mem_base = 0;
+ hose->dense_mem_base = CIA_BW_MEM - IDENT_ADDR;
+ hose->sparse_io_base = 0;
+ hose->dense_io_base = CIA_BW_IO - IDENT_ADDR;
}
/*
diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c
index 5109f07ae..453766d2e 100644
--- a/arch/alpha/kernel/core_irongate.c
+++ b/arch/alpha/kernel/core_irongate.c
@@ -346,12 +346,22 @@ irongate_init_arch(void)
* Create our single hose.
*/
- hose = alloc_pci_controler();
+ pci_isa_hose = hose = alloc_pci_controler();
hose->io_space = &ioport_resource;
hose->mem_space = &iomem_resource;
- hose->config_space = IRONGATE_CONF;
hose->index = 0;
+ /* This is for userland consumption. For some reason, the 40-bit
+ PIO bias that we use in the kernel through KSEG didn't work for
+ the page table based user mappings. So make sure we get the
+ 43-bit PIO bias. */
+ hose->sparse_mem_base = 0;
+ hose->sparse_io_base = 0;
+ hose->dense_mem_base
+ = (IRONGATE_MEM & 0xffffffffff) | 0x80000000000;
+ hose->dense_io_base
+ = (IRONGATE_IO & 0xffffffffff) | 0x80000000000;
+
hose->sg_isa = hose->sg_pci = NULL;
__direct_map_base = 0;
__direct_map_size = 0xffffffff;
diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c
index 8039c0d14..5329acfac 100644
--- a/arch/alpha/kernel/core_lca.c
+++ b/arch/alpha/kernel/core_lca.c
@@ -298,9 +298,13 @@ lca_init_arch(void)
pci_isa_hose = hose = alloc_pci_controler();
hose->io_space = &ioport_resource;
hose->mem_space = &iomem_resource;
- hose->config_space = LCA_CONF;
hose->index = 0;
+ hose->sparse_mem_base = LCA_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = LCA_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = LCA_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
/*
* Set up the PCI to main memory translation windows.
*
diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c
index 7564d83e9..527c4f5eb 100644
--- a/arch/alpha/kernel/core_mcpcia.c
+++ b/arch/alpha/kernel/core_mcpcia.c
@@ -189,7 +189,7 @@ mk_conf_addr(struct pci_dev *dev, int where, struct pci_controler *hose,
bus = 0;
addr = (bus << 16) | (devfn << 8) | (where);
addr <<= 5; /* swizzle for SPARSE */
- addr |= hose->config_space;
+ addr |= hose->config_space_base;
*pci_addr = addr;
DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
@@ -337,13 +337,19 @@ mcpcia_new_hose(int h)
int mid = MCPCIA_HOSE2MID(h);
hose = alloc_pci_controler();
+ if (h == 0)
+ pci_isa_hose = hose;
io = alloc_resource();
mem = alloc_resource();
hae_mem = alloc_resource();
hose->io_space = io;
hose->mem_space = hae_mem;
- hose->config_space = MCPCIA_CONF(mid);
+ hose->sparse_mem_base = MCPCIA_SPARSE(mid) - IDENT_ADDR;
+ hose->dense_mem_base = MCPCIA_DENSE(mid) - IDENT_ADDR;
+ hose->sparse_io_base = MCPCIA_IO(mid) - IDENT_ADDR;
+ hose->dense_io_base = 0;
+ hose->config_space_base = MCPCIA_CONF(mid);
hose->index = h;
io->start = MCPCIA_IO(mid) - MCPCIA_IO_BIAS;
diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c
index f76ac0654..56601c4c5 100644
--- a/arch/alpha/kernel/core_polaris.c
+++ b/arch/alpha/kernel/core_polaris.c
@@ -192,12 +192,16 @@ polaris_init_arch(void)
* Create our single hose.
*/
- hose = alloc_pci_controler();
+ pci_isa_hose = hose = alloc_pci_controler();
hose->io_space = &ioport_resource;
hose->mem_space = &iomem_resource;
- hose->config_space = POLARIS_DENSE_CONFIG_BASE;
hose->index = 0;
+ hose->sparse_mem_base = 0;
+ hose->dense_mem_base = POLARIS_DENSE_MEM_BASE - IDENT_ADDR;
+ hose->sparse_io_base = 0;
+ hose->dense_io_base = POLARIS_DENSE_IO_BASE - IDENT_ADDR;
+
hose->sg_isa = hose->sg_pci = NULL;
/* The I/O window is fixed at 2G @ 2G. */
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
index d1037f57b..26aac4a38 100644
--- a/arch/alpha/kernel/core_t2.c
+++ b/arch/alpha/kernel/core_t2.c
@@ -384,12 +384,16 @@ t2_init_arch(void)
* Create our single hose.
*/
- hose = alloc_pci_controler();
+ pci_isa_hose = hose = alloc_pci_controler();
hose->io_space = &ioport_resource;
hose->mem_space = &iomem_resource;
- hose->config_space = T2_CONF;
hose->index = 0;
+ hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
+ hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
+ hose->sparse_io_base = T2_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
hose->sg_isa = hose->sg_pci = NULL;
__direct_map_base = 0x40000000;
__direct_map_size = 0x40000000;
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
index 1ddcd36d1..5e3943fec 100644
--- a/arch/alpha/kernel/core_tsunami.c
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -104,7 +104,7 @@ mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr,
*type1 = (bus != 0);
addr = (bus << 16) | (device_fn << 8) | where;
- addr |= hose->config_space;
+ addr |= hose->config_space_base;
*pci_addr = addr;
DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
@@ -291,7 +291,18 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index)
hose->io_space = alloc_resource();
hose->mem_space = alloc_resource();
- hose->config_space = TSUNAMI_CONF(index);
+ /* This is for userland consumption. For some reason, the 40-bit
+ PIO bias that we use in the kernel through KSEG didn't work for
+ the page table based user mappings. So make sure we get the
+ 43-bit PIO bias. */
+ hose->sparse_mem_base = 0;
+ hose->sparse_io_base = 0;
+ hose->dense_mem_base
+ = (TSUNAMI_MEM(index) & 0xffffffffff) | 0x80000000000;
+ hose->dense_io_base
+ = (TSUNAMI_IO(index) & 0xffffffffff) | 0x80000000000;
+
+ hose->config_space_base = TSUNAMI_CONF(index);
hose->index = index;
hose->io_space->start = TSUNAMI_IO(index) - TSUNAMI_IO_BIAS;
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 0b9e1786d..55e622d66 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -8,7 +8,7 @@
#define SIGCHLD 20
-#define NR_SYSCALLS 376
+#define NR_SYSCALLS 377
/*
* These offsets must match with alpha_mv in <asm/machvec.h>.
@@ -1156,3 +1156,4 @@ sys_call_table:
.quad sys_ni_syscall /* sys_dipc */
.quad sys_pivot_root
.quad sys_mincore /* 375 */
+ .quad sys_pciconfig_iobase
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 0395f87f1..a7110bf23 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -811,21 +811,8 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
/* Return current software fp control & status bits. */
/* Note that DU doesn't verify available space here. */
- /* EV6 implements most of the bits in hardware. If
- UNDZ is not set, UNFD is maintained in software. */
- if (implver() == IMPLVER_EV6) {
- unsigned long fpcr = rdfpcr();
- w = ieee_fpcr_to_swcr(fpcr);
- if (!(fpcr & FPCR_UNDZ)) {
- w &= ~IEEE_TRAP_ENABLE_UNF;
- w |= (current->thread.flags
- & IEEE_TRAP_ENABLE_UNF);
- }
- } else {
- /* Otherwise we are forced to do everything in sw. */
- w = current->thread.flags & IEEE_SW_MASK;
- }
-
+ w = current->thread.flags & IEEE_SW_MASK;
+ w = swcr_update_status(w, rdfpcr());
if (put_user(w, (unsigned long *) buffer))
return -EFAULT;
return 0;
@@ -876,7 +863,7 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
{
switch (op) {
case SSI_IEEE_FP_CONTROL: {
- unsigned long swcr, fpcr, undz;
+ unsigned long swcr, fpcr;
/*
* Alpha Architecture Handbook 4.7.7.3:
@@ -891,14 +878,18 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
current->thread.flags &= ~IEEE_SW_MASK;
current->thread.flags |= swcr & IEEE_SW_MASK;
- /* Update the real fpcr. Keep UNFD off if not UNDZ. */
+ /* Update the real fpcr. */
fpcr = rdfpcr();
- undz = (fpcr & FPCR_UNDZ);
- fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ);
+ fpcr &= FPCR_DYN_MASK;
fpcr |= ieee_swcr_to_fpcr(swcr);
- fpcr &= ~(undz << 1);
wrfpcr(fpcr);
-
+
+ /* If any exceptions are now unmasked, send a signal. */
+ if (((swcr & IEEE_STATUS_MASK)
+ >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr) {
+ send_sig(SIGFPE, current, 1);
+ }
+
return 0;
}
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 12e3f0df9..81178976a 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -377,3 +377,39 @@ alloc_resource(void)
return res;
}
+
+
+/* Provide information on locations of various I/O regions in physical
+ memory. Do this on a per-card basis so that we choose the right hose. */
+
+asmlinkage long
+sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)
+{
+ struct pci_controler *hose;
+ struct pci_dev *dev;
+
+ /* Special hook for ISA access. */
+ if (bus == 0 && dfn == 0) {
+ hose = pci_isa_hose;
+ } else {
+ dev = pci_find_slot(bus, dfn);
+ if (!dev)
+ return -ENODEV;
+ hose = dev->sysdata;
+ }
+
+ switch (which) {
+ case IOBASE_HOSE:
+ return hose->index;
+ case IOBASE_SPARSE_MEM:
+ return hose->sparse_mem_base;
+ case IOBASE_DENSE_MEM:
+ return hose->dense_mem_base;
+ case IOBASE_SPARSE_IO:
+ return hose->sparse_io_base;
+ case IOBASE_DENSE_IO:
+ return hose->dense_io_base;
+ }
+
+ return -EOPNOTSUPP;
+}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 2e462550f..aa9dfbf64 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -251,12 +251,9 @@ void
flush_thread(void)
{
/* Arrange for each exec'ed process to start off with a clean slate
- with respect to the FPU. This is all exceptions disabled. Note
- that EV6 defines UNFD valid only with UNDZ, which we don't want
- for IEEE conformance -- so that disabled bit remains in software. */
-
+ with respect to the FPU. This is all exceptions disabled. */
current->thread.flags &= ~IEEE_SW_MASK;
- wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED);
+ wrfpcr(FPCR_DYN_NORMAL | ieee_swcr_to_fpcr(0));
}
void
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index b650de6b1..b79d42257 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -17,6 +17,7 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
+#include <asm/fpu.h>
#include "proto.h"
@@ -113,18 +114,30 @@ get_reg_addr(struct task_struct * task, unsigned long regno)
/*
* Get contents of register REGNO in task TASK.
*/
-static inline long
+static long
get_reg(struct task_struct * task, unsigned long regno)
{
+ /* Special hack for fpcr -- combine hardware and software bits. */
+ if (regno == 63) {
+ unsigned long fpcr = *get_reg_addr(task, regno);
+ unsigned long swcr = task->thread.flags & IEEE_SW_MASK;
+ swcr = swcr_update_status(swcr, fpcr);
+ return fpcr | swcr;
+ }
return *get_reg_addr(task, regno);
}
/*
* Write contents of register REGNO in task TASK.
*/
-static inline int
+static int
put_reg(struct task_struct *task, unsigned long regno, long data)
{
+ if (regno == 63) {
+ task->thread.flags = ((task->thread.flags & ~IEEE_SW_MASK)
+ | (data & IEEE_SW_MASK));
+ data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);
+ }
*get_reg_addr(task, regno) = data;
return 0;
}
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
index 2f5400632..ae09ecbd1 100644
--- a/arch/alpha/kernel/sys_jensen.c
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -29,6 +29,7 @@
#include "proto.h"
#include "irq_impl.h"
+#include "pci_impl.h"
#include "machvec_impl.h"
@@ -123,6 +124,22 @@ jensen_init_irq(void)
static void __init
jensen_init_arch(void)
{
+ struct pci_controler *hose;
+
+ /* Create a hose so that we can report i/o base addresses to
+ userland. */
+
+ pci_isa_hose = hose = alloc_pci_controler();
+ hose->io_space = &ioport_resource;
+ hose->mem_space = &iomem_resource;
+ hose->index = 0;
+
+ hose->sparse_mem_base = EISA_MEM - IDENT_ADDR;
+ hose->dense_mem_base = 0;
+ hose->sparse_io_base = EISA_IO - IDENT_ADDR;
+ hose->dense_io_base = 0;
+
+ hose->sg_isa = hose->sg_pci = NULL;
__direct_map_base = 0;
__direct_map_size = 0xffffffff;
}
diff --git a/arch/alpha/math-emu/math.c b/arch/alpha/math-emu/math.c
index c0ece7bcb..ed2efe087 100644
--- a/arch/alpha/math-emu/math.c
+++ b/arch/alpha/math-emu/math.c
@@ -160,8 +160,7 @@ alpha_fp_emul (unsigned long pc)
FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
unsigned long fa, fb, fc, func, mode, src;
- unsigned long fpcw = current->thread.flags;
- unsigned long res, va, vb, vc, fpcr;
+ unsigned long res, va, vb, vc, swcr, fpcr;
__u32 insn;
MOD_INC_USE_COUNT;
@@ -175,10 +174,11 @@ alpha_fp_emul (unsigned long pc)
mode = (insn >> 11) & 0x3;
fpcr = rdfpcr();
+ swcr = swcr_update_status(current->thread.flags, fpcr);
if (mode == 3) {
- /* Dynamic -- get rounding mode from fpcr. */
- mode = (fpcr >> FPCR_DYN_SHIFT) & 3;
+ /* Dynamic -- get rounding mode from fpcr. */
+ mode = (fpcr >> FPCR_DYN_SHIFT) & 3;
}
switch (src) {
@@ -231,9 +231,14 @@ alpha_fp_emul (unsigned long pc)
}
FP_CMP_D(res, DA, DB, 3);
vc = 0x4000000000000000;
- /* CMPTEQ, CMPTUN don't trap on QNaN, while CMPTLT and CMPTLE do */
- if (res == 3 && ((func & 3) >= 2 || FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
+ /* CMPTEQ, CMPTUN don't trap on QNaN,
+ while CMPTLT and CMPTLE do */
+ if (res == 3
+ && ((func & 3) >= 2
+ || FP_ISSIGNAN_D(DA)
+ || FP_ISSIGNAN_D(DB))) {
FP_SET_EXCEPTION(FP_EX_INVALID);
+ }
switch (func) {
case FOP_FNC_CMPxUN: if (res != 3) vc = 0; break;
case FOP_FNC_CMPxEQ: if (res) vc = 0; break;
@@ -285,9 +290,11 @@ alpha_fp_emul (unsigned long pc)
}
case FOP_FNC_CVTxQ:
- if (DB_c == FP_CLS_NAN && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D))
- vc = 0; /* AAHB Table B-2 sais QNaN should not trigger INV */
- else
+ if (DB_c == FP_CLS_NAN
+ && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D)) {
+ /* AAHB Table B-2 says QNaN should not trigger INV */
+ vc = 0;
+ } else
FP_TO_INT_ROUND_D(vc, DB, 64, 2);
goto done_d;
}
@@ -321,11 +328,15 @@ alpha_fp_emul (unsigned long pc)
pack_s:
FP_PACK_SP(&vc, SR);
+ if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ))
+ vc = 0;
alpha_write_fp_reg_s(fc, vc);
goto done;
pack_d:
FP_PACK_DP(&vc, DR);
+ if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ))
+ vc = 0;
done_d:
alpha_write_fp_reg(fc, vc);
goto done;
@@ -345,16 +356,16 @@ done_d:
done:
if (_fex) {
/* Record exceptions in software control word. */
- current->thread.flags
- = fpcw |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
+ swcr |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
+ current->thread.flags |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
- /* Update hardware control register */
+ /* Update hardware control register. */
fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
- fpcr |= ieee_swcr_to_fpcr(fpcw);
+ fpcr |= ieee_swcr_to_fpcr(swcr);
wrfpcr(fpcr);
/* Do we generate a signal? */
- if (_fex & fpcw & IEEE_TRAP_ENABLE_MASK) {
+ if (_fex & swcr & IEEE_TRAP_ENABLE_MASK) {
MOD_DEC_USE_COUNT;
return 0;
}
@@ -378,7 +389,7 @@ long
alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
{
unsigned long trigger_pc = regs->pc - 4;
- unsigned long insn, opcode, rc;
+ unsigned long insn, opcode, rc, no_signal = 0;
MOD_INC_USE_COUNT;
@@ -402,15 +413,13 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
case OPC_PAL:
case OPC_JSR:
case 0x30 ... 0x3f: /* branches */
- MOD_DEC_USE_COUNT;
- return 0;
+ goto egress;
case OPC_MISC:
switch (insn & 0xffff) {
case MISC_TRAPB:
case MISC_EXCB:
- MOD_DEC_USE_COUNT;
- return 0;
+ goto egress;
default:
break;
@@ -432,16 +441,15 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
break;
}
if (!write_mask) {
- if (alpha_fp_emul(trigger_pc)) {
- /* re-execute insns in trap-shadow: */
- regs->pc = trigger_pc + 4;
- MOD_DEC_USE_COUNT;
- return 1;
- }
- break;
+ /* Re-execute insns in the trap-shadow. */
+ regs->pc = trigger_pc + 4;
+ no_signal = alpha_fp_emul(trigger_pc);
+ goto egress;
}
trigger_pc -= 4;
}
+
+egress:
MOD_DEC_USE_COUNT;
- return 0;
+ return no_signal;
}
diff --git a/arch/arm/config.in b/arch/arm/config.in
index 2ff7f6414..cf6312fc1 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -119,6 +119,8 @@ if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \
"$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
define_bool CONFIG_PCI y
source drivers/pci/Config.in
+else
+ define_bool CONFIG_PCI n
fi
#
@@ -127,8 +129,10 @@ fi
if [ "$CONFIG_ARCH_CATS" = "y" -o \
"$CONFIG_ARCH_SHARK" = "y" -o \
"$CONFIG_ARCH_NETWINDER" = "y" ]; then
+ define_bool CONFIG_ISA y
define_bool CONFIG_ISA_DMA y
else
+ define_bool CONFIG_ISA n
define_bool CONFIG_ISA_DMA n
fi
diff --git a/arch/arm/defconfig b/arch/arm/defconfig
index 45c89eeb3..79cac7fa3 100644
--- a/arch/arm/defconfig
+++ b/arch/arm/defconfig
@@ -2,6 +2,7 @@
# Automatically generated make config: don't edit
#
CONFIG_ARM=y
+CONFIG_UID16=y
#
# Code maturity level options
@@ -19,14 +20,17 @@ CONFIG_FOOTBRIDGE=y
CONFIG_HOST_FOOTBRIDGE=y
# CONFIG_ADDIN_FOOTBRIDGE is not set
CONFIG_ARCH_EBSA285=y
-# CONFIG_CATS is not set
+# CONFIG_ARCH_CATS is not set
CONFIG_ARCH_NETWINDER=y
+# CONFIG_ARCH_PERSONAL_SERVER is not set
# CONFIG_ARCH_ACORN is not set
CONFIG_CPU_32=y
# CONFIG_CPU_26 is not set
CONFIG_CPU_32v4=y
CONFIG_CPU_SA110=y
CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+CONFIG_ISA=y
CONFIG_ISA_DMA=y
# CONFIG_ALIGNMENT_TRAP is not set
@@ -51,10 +55,14 @@ CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_ARTHUR is not set
+
+#
+# Parallel port support
+#
CONFIG_PARPORT=y
CONFIG_PARPORT_PC=y
CONFIG_PARPORT_PC_FIFO=y
-# CONFIG_PARPORT_PC_PCMCIA is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
# CONFIG_PARPORT_ARC is not set
# CONFIG_PARPORT_AMIGA is not set
# CONFIG_PARPORT_MFC3 is not set
@@ -68,6 +76,11 @@ CONFIG_LEDS_TIMER=y
# CONFIG_LEDS_CPU is not set
#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
# I2O device support
#
# CONFIG_I2O is not set
@@ -87,24 +100,9 @@ CONFIG_ISAPNP=y
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=m
-CONFIG_MD_STRIPED=m
-CONFIG_MD_MIRRORING=m
-CONFIG_MD_RAID5=m
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=y
#
# Parallel IDE high-level drivers
@@ -132,6 +130,19 @@ CONFIG_PARIDE_KBIC=m
CONFIG_PARIDE_KTTI=m
CONFIG_PARIDE_ON20=m
CONFIG_PARIDE_ON26=m
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
#
# Character devices
@@ -149,6 +160,11 @@ CONFIG_PRINTER=m
# CONFIG_PPDEV is not set
#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
@@ -172,6 +188,7 @@ CONFIG_WATCHDOG=y
CONFIG_SOFT_WATCHDOG=y
# CONFIG_PCWATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_MIXCOMWD is not set
# CONFIG_21285_WATCHDOG is not set
CONFIG_977_WATCHDOG=m
CONFIG_DS1620=y
@@ -188,29 +205,32 @@ CONFIG_VIDEO_DEV=y
# CONFIG_I2C_PARPORT is not set
#
-# Radio/Video Adapters
+# Radio Adapters
#
# CONFIG_RADIO_CADET is not set
# CONFIG_RADIO_RTRACK is not set
# CONFIG_RADIO_RTRACK2 is not set
# CONFIG_RADIO_AZTECH is not set
-# CONFIG_VIDEO_BT848 is not set
# CONFIG_RADIO_GEMTEK is not set
-# CONFIG_VIDEO_PMS is not set
# CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_VIDEO_BWQCAM is not set
-# CONFIG_VIDEO_CQCAM is not set
-# CONFIG_VIDEO_SAA5249 is not set
# CONFIG_RADIO_SF16FMI is not set
-# CONFIG_VIDEO_STRADIS is not set
# CONFIG_RADIO_TERRATEC is not set
# CONFIG_RADIO_TRUST is not set
# CONFIG_RADIO_TYPHOON is not set
# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
# CONFIG_VIDEO_ZORAN is not set
# CONFIG_VIDEO_BUZ is not set
# CONFIG_VIDEO_ZR36120 is not set
-CONFIG_VIDEO_CYBERPRO=m
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -221,15 +241,10 @@ CONFIG_VIDEO_CYBERPRO=m
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
# CONFIG_DRM_TDFX is not set
-
-#
-# PCMCIA character device support
-#
-# CONFIG_PCMCIA_SERIAL_CS is not set
# CONFIG_AGP is not set
#
-# Support for USB
+# USB support
#
CONFIG_USB=m
@@ -237,32 +252,49 @@ CONFIG_USB=m
# USB Controllers
#
# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=m
-CONFIG_USB_OHCI_DEBUG=y
-CONFIG_USB_OHCI_HCD=m
-CONFIG_USB_OHCI_VROOTHUB=y
#
# Miscellaneous USB options
#
-# CONFIG_USB_DEBUG_ISOC is not set
-CONFIG_USB_PROC=y
-# CONFIG_USB_EZUSB is not set
+CONFIG_USB_DEVICEFS=y
#
# USB Devices
#
-CONFIG_USB_MOUSE=m
-# CONFIG_USB_HP_SCANNER is not set
-CONFIG_USB_KBD=m
+CONFIG_USB_PRINTER=m
+# CONFIG_USB_SCANNER is not set
CONFIG_USB_AUDIO=m
CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
# CONFIG_USB_SERIAL is not set
# CONFIG_USB_CPIA is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_SCSI is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_STORAGE is not set
# CONFIG_USB_USS720 is not set
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_DSBR is not set
+
+#
+# USB HID
+#
+# CONFIG_USB_HID is not set
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_WMFORCE is not set
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_MIX=y
+# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
#
# Console drivers
@@ -300,6 +332,7 @@ CONFIG_FBCON_CFB24=y
# CONFIG_FBCON_MAC is not set
# CONFIG_FBCON_VGA_PLANES is not set
CONFIG_FBCON_VGA=y
+# CONFIG_FBCON_HGA is not set
# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
CONFIG_FBCON_FONTS=y
CONFIG_FONT_8x8=y
@@ -379,6 +412,7 @@ CONFIG_NETDEVICES=y
#
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_NET_SB1000 is not set
@@ -398,30 +432,30 @@ CONFIG_VORTEX=y
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_RTL8139 is not set
-# CONFIG_DM9102 is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
# CONFIG_DE4X5 is not set
-CONFIG_DEC_ELCP=m
+CONFIG_TULIP=m
# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
# CONFIG_LNE390 is not set
# CONFIG_NE3210 is not set
CONFIG_NE2K_PCI=y
+# CONFIG_RTL8129 is not set
+# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_ES3210 is not set
# CONFIG_EPIC100 is not set
-# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
#
@@ -449,7 +483,7 @@ CONFIG_SLIP_MODE_SLIP6=y
# CONFIG_NET_RADIO is not set
#
-# Token Ring driver support
+# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
@@ -462,22 +496,23 @@ CONFIG_SLIP_MODE_SLIP6=y
# CONFIG_WAN is not set
#
-# PCMCIA network device support
+# ATA/IDE/MFM/RLL support
#
-# CONFIG_NET_PCMCIA is not set
+CONFIG_IDE=y
#
-# ATA/IDE/MFM/RLL support
+# IDE, ATA and ATAPI Block devices
#
-CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECS is not set
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
@@ -487,32 +522,44 @@ CONFIG_IDEDISK_MULTI_MODE=y
# IDE chipset support/bugfixes
#
# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_OFFBOARD=y
CONFIG_IDEDMA_PCI_AUTO=y
-CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y
+CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
-CONFIG_BLK_DEV_OFFBOARD=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
# CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_AEC6210_TUNING is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_CMD64X_RAID is not set
CONFIG_BLK_DEV_CY82C693=y
+# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_HPT366_FIP is not set
+# CONFIG_HPT366_MODE3 is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_PDC202XX=y
# CONFIG_PDC202XX_BURST is not set
# CONFIG_PDC202XX_MASTER is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
CONFIG_BLK_DEV_SL82C105=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
CONFIG_BLK_DEV_IDE_MODES=y
-# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
@@ -533,8 +580,12 @@ CONFIG_SOUND=m
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
# CONFIG_SOUND_AD1816 is not set
# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
# CONFIG_SOUND_CS4232 is not set
# CONFIG_SOUND_SSCAPE is not set
# CONFIG_SOUND_GUS is not set
@@ -545,9 +596,11 @@ CONFIG_SOUND_OSS=m
# CONFIG_SOUND_NM256 is not set
# CONFIG_SOUND_MAD16 is not set
# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
# CONFIG_SOUND_PSS is not set
# CONFIG_SOUND_SOFTOSS is not set
CONFIG_SOUND_SB=m
+# CONFIG_SOUND_AWE32_SYNTH is not set
# CONFIG_SOUND_WAVEFRONT is not set
# CONFIG_SOUND_MAUI is not set
# CONFIG_SOUND_VIA82CXXX is not set
@@ -555,24 +608,18 @@ CONFIG_SOUND_SB=m
# CONFIG_SOUND_OPL3SA1 is not set
# CONFIG_SOUND_OPL3SA2 is not set
# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
# CONFIG_SOUND_VIDC is not set
CONFIG_SOUND_WAVEARTIST=m
-CONFIG_WAVEARTIST_BASE=250
-CONFIG_WAVEARTIST_IRQ=12
-CONFIG_WAVEARTIST_DMA=3
-CONFIG_WAVEARTIST_DMA2=7
#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
-
-#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
CONFIG_ADFS_FS=y
+# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -581,12 +628,15 @@ CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
CONFIG_VFAT_FS=m
# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -612,7 +662,14 @@ CONFIG_LOCKD=y
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_ICS is not set
+CONFIG_ACORN_PARTITION_ADFS=y
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+# CONFIG_ACORN_PARTITION_RISCIX is not set
# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
@@ -620,13 +677,6 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_ACORN_PARTITION=y
-CONFIG_ACORN_PARTITION_ADFS=y
-# CONFIG_ACORN_PARTITION_ICS is not set
-# CONFIG_ACORN_PARTITION_POWERTEC is not set
-# CONFIG_ACORN_PARTITION_RISCIX is not set
CONFIG_NLS=y
#
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 0e16a45b6..113a00fa6 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -30,56 +30,42 @@ CFLAGS += $(shell if ! $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/nul
CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)
ifdef CONFIG_M386
-CFLAGS := $(CFLAGS) -DCPU=386
CFLAGS += $(shell if $(CC) -march=i386 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i386"; else echo "-m386"; fi)
-AFLAGS := $(AFLAGS) -DCPU=386
endif
ifdef CONFIG_M486
-CFLAGS := $(CFLAGS) -DCPU=486
CFLAGS += $(shell if $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i486"; else echo "-m486"; fi)
-AFLAGS := $(AFLAGS) -DCPU=486
endif
ifdef CONFIG_M586
-CFLAGS := $(CFLAGS) -DCPU=586
CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi)
-AFLAGS := $(AFLAGS) -DCPU=586
endif
ifdef CONFIG_M586TSC
-CFLAGS := $(CFLAGS) -DCPU=586
CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi)
-AFLAGS := $(AFLAGS) -DCPU=586
endif
ifdef CONFIG_M686
-CFLAGS := $(CFLAGS) -DCPU=686
CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi)
-AFLAGS := $(AFLAGS) -DCPU=686
endif
ifdef CONFIG_MK6
-CFLAGS := $(CFLAGS) -DCPU=586
CFLAGS += $(shell if $(CC) -march=k6 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=k6"; fi)
-AFLAGS := $(AFLAGS) -DCPU=586
endif
ifdef CONFIG_MK7
-CFLAGS := $(CFLAGS) -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations -DCPU=686
-CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi)
-AFLAGS := $(AFLAGS) -DCPU=686
+CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations
endif
HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
-SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib
+SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib
CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES)
LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a
ifdef CONFIG_MATH_EMULATION
-SUBDIRS := $(SUBDIRS) arch/i386/math-emu
-DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a
+SUBDIRS += arch/i386/math-emu
+DRIVERS += arch/i386/math-emu/math.a
endif
arch/i386/kernel: dummy
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index 8aac90800..055b3ea5b 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -145,7 +145,7 @@ static void gzip_release(void **ptr)
free_mem_ptr = (long) *ptr;
}
-static void scroll()
+static void scroll(void)
{
int i;
@@ -197,6 +197,7 @@ void* memset(void* s, int c, size_t n)
char *ss = (char*)s;
for (i=0;i<n;i++) ss[i] = c;
+ return s;
}
void* memcpy(void* __dest, __const void* __src,
@@ -206,13 +207,14 @@ void* memcpy(void* __dest, __const void* __src,
char *d = (char *)__dest, *s = (char *)__src;
for (i=0;i<__n;i++) d[i] = s[i];
+ return __dest;
}
/* ===========================================================================
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
-static int fill_inbuf()
+static int fill_inbuf(void)
{
if (insize != 0) {
error("ran out of input data\n");
@@ -228,7 +230,7 @@ static int fill_inbuf()
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
-static void flush_window_low()
+static void flush_window_low(void)
{
ulg c = crc; /* temporary variable */
unsigned n;
@@ -246,7 +248,7 @@ static void flush_window_low()
outcnt = 0;
}
-static void flush_window_high()
+static void flush_window_high(void)
{
ulg c = crc; /* temporary variable */
unsigned n;
@@ -262,7 +264,7 @@ static void flush_window_high()
outcnt = 0;
}
-static void flush_window()
+static void flush_window(void)
{
if (high_loaded) flush_window_high();
else flush_window_low();
@@ -286,7 +288,7 @@ struct {
short b;
} stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS };
-void setup_normal_output_buffer()
+void setup_normal_output_buffer(void)
{
#ifdef STANDARD_MEMORY_BIOS_CALL
if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 2a083ad09..36f1aafda 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -30,32 +30,44 @@ choice 'Processor family' \
if [ "$CONFIG_M386" != "y" ]; then
define_bool CONFIG_X86_WP_WORKS_OK y
define_bool CONFIG_X86_INVLPG y
+ define_bool CONFIG_X86_CMPXCHG y
define_bool CONFIG_X86_BSWAP y
define_bool CONFIG_X86_POPAD_OK y
fi
-if [ "$CONFIG_M686" = "y" -o "$CONFIG_M586TSC" = "y" ]; then
+if [ "$CONFIG_M386" = "y" -o "$CONFIG_M486" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_BYTES 16
+else
+ define_int CONFIG_X86_L1_CACHE_BYTES 32
+fi
+if [ "$CONFIG_M486" = "y" -o "$CONFIG_M586" = "y" ]; then
+ define_bool CONFIG_X86_USE_STRING_486 y
+ define_bool CONFIG_X86_ALIGNMENT_16 y
+fi
+if [ "$CONFIG_M586TSC" = "y" -o "$CONFIG_MK6" = "y" ]; then
+ define_bool CONFIG_X86_USE_STRING_486 y
+ define_bool CONFIG_X86_ALIGNMENT_16 y
define_bool CONFIG_X86_TSC y
fi
if [ "$CONFIG_M686" = "y" ]; then
+ define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
define_bool CONFIG_X86_PGE y
-fi
-if [ "$CONFIG_MK6" = "y" ]; then
- define_bool CONFIG_X86_TSC y
+ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
if [ "$CONFIG_MK7" = "y" ]; then
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
define_bool CONFIG_X86_USE_3DNOW y
define_bool CONFIG_X86_PGE y
+ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
choice 'High Memory Support' \
"off CONFIG_NOHIGHMEM \
- 4GB CONFIG_HIGHMEM4G \
- 64GB CONFIG_HIGHMEM64G" off
+ 4GB CONFIG_HIGHMEM4G \
+ 64GB CONFIG_HIGHMEM64G" off
if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
define_bool CONFIG_HIGHMEM y
fi
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 33f2d3cb1..15e23d91a 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -324,6 +324,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_ISA is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
# CONFIG_DE4X5 is not set
@@ -375,6 +376,7 @@ CONFIG_PCMCIA_PCNET=y
# CONFIG_PCMCIA_XIRC2PS is not set
# CONFIG_ARCNET_COM20020_CS is not set
# CONFIG_PCMCIA_3C575 is not set
+# CONFIG_PCMCIA_XIRTULIP is not set
CONFIG_NET_PCMCIA_RADIO=y
CONFIG_PCMCIA_RAYCS=y
# CONFIG_PCMCIA_NETWAVE is not set
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 56500e466..b488d97a8 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -174,9 +174,7 @@ ENTRY(lcall27)
jmp ret_from_sys_call
- ALIGN
- .globl ret_from_fork
-ret_from_fork:
+ENTRY(ret_from_fork)
pushl %ebx
call SYMBOL_NAME(schedule_tail)
addl $4, %esp
@@ -202,10 +200,7 @@ ENTRY(system_call)
jne tracesys
call *SYMBOL_NAME(sys_call_table)(,%eax,4)
movl %eax,EAX(%esp) # save the return value
- ALIGN
- .globl ret_from_sys_call
- .globl ret_from_intr
-ret_from_sys_call:
+ENTRY(ret_from_sys_call)
#ifdef __SMP__
movl processor(%ebx),%eax
shll $5,%eax
@@ -273,8 +268,7 @@ ret_from_exception:
#endif
jne handle_softirq
- ALIGN
-ret_from_intr:
+ENTRY(ret_from_intr)
GET_CURRENT(%ebx)
movl EFLAGS(%esp),%eax # mix EFLAGS and CS
movb CS(%esp),%al
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index b14f8caf3..61571ab59 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -292,12 +292,12 @@ handle_real_irq:
if (irq & 8) {
inb(0xA1); /* DUMMY - (do we need this?) */
outb(cached_A1,0xA1);
+ outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */
- outb(0x20,0xA0); /* 'generic EOI' to slave */
} else {
inb(0x21); /* DUMMY - (do we need this?) */
outb(cached_21,0x21);
- outb(0x20,0x20); /* 'generic EOI' to master */
+ outb(0x60+irq,0x20); /* 'Specific EOI' to master */
}
spin_unlock_irqrestore(&i8259A_lock, flags);
return;
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 02669540f..1d4445669 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -190,13 +190,13 @@ static int __init ioapic_pirq_setup(char *str)
pirq_entries[i] = -1;
pirqs_enabled = 1;
- printk("PIRQ redirection, working around broken MP-BIOS.\n");
+ printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n");
max = MAX_PIRQS;
if (ints[0] < MAX_PIRQS)
max = ints[0];
for (i = 0; i < max; i++) {
- printk("... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
+ printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
/*
* PIRQs are mapped upside down, usually.
*/
@@ -289,7 +289,7 @@ static int __init EISA_ELCR(unsigned int irq)
unsigned int port = 0x4d0 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1;
}
- printk("Broken MPtable reports ISA irq %d\n", irq);
+ printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq);
return 0;
}
@@ -338,7 +338,7 @@ static int __init MPBIOS_polarity(int idx)
}
default:
{
- printk("broken BIOS!!\n");
+ printk(KERN_WARNING "broken BIOS!!\n");
polarity = 1;
break;
}
@@ -352,7 +352,7 @@ static int __init MPBIOS_polarity(int idx)
}
case 2: /* reserved */
{
- printk("broken BIOS!!\n");
+ printk(KERN_WARNING "broken BIOS!!\n");
polarity = 1;
break;
}
@@ -363,7 +363,7 @@ static int __init MPBIOS_polarity(int idx)
}
default: /* invalid */
{
- printk("broken BIOS!!\n");
+ printk(KERN_WARNING "broken BIOS!!\n");
polarity = 1;
break;
}
@@ -402,7 +402,7 @@ static int __init MPBIOS_trigger(int idx)
}
default:
{
- printk("broken BIOS!!\n");
+ printk(KERN_WARNING "broken BIOS!!\n");
trigger = 1;
break;
}
@@ -416,7 +416,7 @@ static int __init MPBIOS_trigger(int idx)
}
case 2: /* reserved */
{
- printk("broken BIOS!!\n");
+ printk(KERN_WARNING "broken BIOS!!\n");
trigger = 1;
break;
}
@@ -427,7 +427,7 @@ static int __init MPBIOS_trigger(int idx)
}
default: /* invalid */
{
- printk("broken BIOS!!\n");
+ printk(KERN_WARNING "broken BIOS!!\n");
trigger = 0;
break;
}
@@ -454,7 +454,7 @@ static int __init pin_2_irq(int idx, int apic, int pin)
* Debugging check, we are in big trouble if this message pops up!
*/
if (mp_irqs[idx].mpc_dstirq != pin)
- printk("broken BIOS or MPTABLE parser, ayiee!!\n");
+ printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
switch (mp_bus_id_to_type[bus])
{
@@ -477,7 +477,7 @@ static int __init pin_2_irq(int idx, int apic, int pin)
}
default:
{
- printk("unknown bus type %d.\n",bus);
+ printk(KERN_ERR "unknown bus type %d.\n",bus);
irq = 0;
break;
}
@@ -489,10 +489,10 @@ static int __init pin_2_irq(int idx, int apic, int pin)
if ((pin >= 16) && (pin <= 23)) {
if (pirq_entries[pin-16] != -1) {
if (!pirq_entries[pin-16]) {
- printk("disabling PIRQ%d\n", pin-16);
+ printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16);
} else {
irq = pirq_entries[pin-16];
- printk("using PIRQ%d -> IRQ %d\n",
+ printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n",
pin-16, irq);
}
}
@@ -549,7 +549,7 @@ void __init setup_IO_APIC_irqs(void)
struct IO_APIC_route_entry entry;
int apic, pin, idx, irq, first_notcon = 1, vector;
- printk("init IO_APIC IRQs\n");
+ printk(KERN_DEBUG "init IO_APIC IRQs\n");
for (apic = 0; apic < nr_ioapics; apic++) {
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
@@ -567,7 +567,7 @@ void __init setup_IO_APIC_irqs(void)
idx = find_irq_entry(apic,pin,mp_INT);
if (idx == -1) {
if (first_notcon) {
- printk(" IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin);
+ printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin);
first_notcon = 0;
} else
printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin);
@@ -658,8 +658,8 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
void __init UNEXPECTED_IO_APIC(void)
{
- printk(" WARNING: unexpected IO-APIC, please mail\n");
- printk(" to linux-smp@vger.rutgers.edu\n");
+ printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
+ printk(KERN_WARNING " to linux-smp@vger.rutgers.edu\n");
}
void __init print_IO_APIC(void)
@@ -669,15 +669,16 @@ void __init print_IO_APIC(void)
struct IO_APIC_reg_01 reg_01;
struct IO_APIC_reg_02 reg_02;
- printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
+ printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
for (i = 0; i < nr_ioapics; i++)
- printk("number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
+ printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
+ mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
/*
* We are a bit conservative about what we expect. We have to
* know about every hardware change ASAP.
*/
- printk("testing the IO APIC.......................\n");
+ printk(KERN_INFO "testing the IO APIC.......................\n");
for (apic = 0; apic < nr_ioapics; apic++) {
@@ -686,14 +687,15 @@ void __init print_IO_APIC(void)
if (reg_01.version >= 0x10)
*(int *)&reg_02 = io_apic_read(apic, 2);
- printk("\nIO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
- printk(".... register #00: %08X\n", *(int *)&reg_00);
- printk("....... : physical APIC id: %02X\n", reg_00.ID);
+ printk("\n");
+ printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
+ printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)&reg_00);
+ printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.ID);
if (reg_00.__reserved_1 || reg_00.__reserved_2)
UNEXPECTED_IO_APIC();
- printk(".... register #01: %08X\n", *(int *)&reg_01);
- printk("....... : max redirection entries: %04X\n", reg_01.entries);
+ printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
+ printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.entries);
if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */
(reg_01.entries != 0x17) && /* typical ISA+PCI boards */
(reg_01.entries != 0x1b) && /* Compaq Proliant boards */
@@ -704,7 +706,7 @@ void __init print_IO_APIC(void)
)
UNEXPECTED_IO_APIC();
- printk("....... : IO APIC version: %04X\n", reg_01.version);
+ printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.version);
if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */
(reg_01.version != 0x10) && /* oldest IO-APICs */
(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
@@ -715,16 +717,16 @@ void __init print_IO_APIC(void)
UNEXPECTED_IO_APIC();
if (reg_01.version >= 0x10) {
- printk(".... register #02: %08X\n", *(int *)&reg_02);
- printk("....... : arbitration: %02X\n", reg_02.arbitration);
+ printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)&reg_02);
+ printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration);
if (reg_02.__reserved_1 || reg_02.__reserved_2)
UNEXPECTED_IO_APIC();
}
- printk(".... IRQ redirection table:\n");
+ printk(KERN_DEBUG ".... IRQ redirection table:\n");
- printk(" NR Log Phy ");
- printk("Mask Trig IRR Pol Stat Dest Deli Vect: \n");
+ printk(KERN_DEBUG " NR Log Phy ");
+ printk(KERN_DEBUG "Mask Trig IRR Pol Stat Dest Deli Vect: \n");
for (i = 0; i <= reg_01.entries; i++) {
struct IO_APIC_route_entry entry;
@@ -732,7 +734,7 @@ void __init print_IO_APIC(void)
*(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
*(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
- printk(" %02x %03X %02X ",
+ printk(KERN_DEBUG " %02x %03X %02X ",
i,
entry.dest.logical.logical_dest,
entry.dest.physical.physical_dest
@@ -765,7 +767,7 @@ void __init print_IO_APIC(void)
printk("\n");
}
- printk(".................................... done.\n");
+ printk(KERN_INFO ".................................... done.\n");
return;
}
@@ -775,7 +777,7 @@ static void print_APIC_bitfield (int base)
unsigned int v;
int i, j;
- printk("0123456789abcdef0123456789abcdef\n");
+ printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG);
for (i = 0; i < 8; i++) {
v = apic_read(base + i*0x10);
for (j = 0; j < 32; j++) {
@@ -792,40 +794,40 @@ void /*__init*/ print_local_APIC(void * dummy)
{
unsigned int v, ver, maxlvt;
- printk("\nprinting local APIC contents on CPU#%d/%d:\n",
+ printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
smp_processor_id(), hard_smp_processor_id());
v = apic_read(APIC_ID);
- printk("... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v));
+ printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v));
v = apic_read(APIC_LVR);
- printk("... APIC VERSION: %08x\n", v);
+ printk(KERN_INFO "... APIC VERSION: %08x\n", v);
ver = GET_APIC_VERSION(v);
maxlvt = get_maxlvt();
v = apic_read(APIC_TASKPRI);
- printk("... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
+ printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
if (APIC_INTEGRATED(ver)) { /* !82489DX */
v = apic_read(APIC_ARBPRI);
- printk("... APIC ARBPRI: %08x (%02x)\n", v,
+ printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
v & APIC_ARBPRI_MASK);
v = apic_read(APIC_PROCPRI);
- printk("... APIC PROCPRI: %08x\n", v);
+ printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
}
v = apic_read(APIC_EOI);
- printk("... APIC EOI: %08x\n", v);
+ printk(KERN_DEBUG "... APIC EOI: %08x\n", v);
v = apic_read(APIC_LDR);
- printk("... APIC LDR: %08x\n", v);
+ printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
v = apic_read(APIC_DFR);
- printk("... APIC DFR: %08x\n", v);
+ printk(KERN_DEBUG "... APIC DFR: %08x\n", v);
v = apic_read(APIC_SPIV);
- printk("... APIC SPIV: %08x\n", v);
+ printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
- printk("... APIC ISR field:\n");
+ printk(KERN_DEBUG "... APIC ISR field:\n");
print_APIC_bitfield(APIC_ISR);
- printk("... APIC TMR field:\n");
+ printk(KERN_DEBUG "... APIC TMR field:\n");
print_APIC_bitfield(APIC_TMR);
- printk("... APIC IRR field:\n");
+ printk(KERN_DEBUG "... APIC IRR field:\n");
print_APIC_bitfield(APIC_IRR);
if (APIC_INTEGRATED(ver)) { /* !82489DX */
@@ -837,37 +839,37 @@ void /*__init*/ print_local_APIC(void * dummy)
apic_write(APIC_ESR, 0);
}
v = apic_read(APIC_ESR);
- printk("... APIC ESR: %08x\n", v);
+ printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
}
v = apic_read(APIC_ICR);
- printk("... APIC ICR: %08x\n", v);
+ printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
v = apic_read(APIC_ICR2);
- printk("... APIC ICR2: %08x\n", v);
+ printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
v = apic_read(APIC_LVTT);
- printk("... APIC LVTT: %08x\n", v);
+ printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
if (maxlvt > 3) { /* PC is LVT#4. */
v = apic_read(APIC_LVTPC);
- printk("... APIC LVTPC: %08x\n", v);
+ printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);
}
v = apic_read(APIC_LVT0);
- printk("... APIC LVT0: %08x\n", v);
+ printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);
v = apic_read(APIC_LVT1);
- printk("... APIC LVT1: %08x\n", v);
+ printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);
if (maxlvt > 2) { /* ERR is LVT#3. */
v = apic_read(APIC_LVTERR);
- printk("... APIC LVTERR: %08x\n", v);
+ printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);
}
v = apic_read(APIC_TMICT);
- printk("... APIC TMICT: %08x\n", v);
+ printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);
v = apic_read(APIC_TMCCT);
- printk("... APIC TMCCT: %08x\n", v);
+ printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
v = apic_read(APIC_TDCR);
- printk("... APIC TDCR: %08x\n", v);
+ printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
printk("\n");
}
@@ -958,7 +960,7 @@ static void __init setup_ioapic_ids_from_mpc (void)
* Read the right value from the MPC table and
* write it into the ID register.
*/
- printk("...changing IO-APIC physical APIC ID to %d ...",
+ printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...",
mp_ioapics[apic].mpc_apicid);
/*
@@ -1061,7 +1063,7 @@ static int __init nmi_irq_works(void)
for (j = 0; j < smp_num_cpus; j++) {
cpu = cpu_logical_map(j);
if (atomic_read(&nmi_counter(cpu)) - atomic_read(&tmp[cpu].__nmi_counter) <= 3) {
- printk("CPU#%d NMI appears to be stuck.\n", cpu);
+ printk(KERN_WARNING "CPU#%d NMI appears to be stuck.\n", cpu);
return 0;
}
}
@@ -1270,7 +1272,7 @@ static void setup_nmi (void)
* is from Maciej W. Rozycki - so we do not have to EOI from
* the NMI handler or the timer interrupt.
*/
- printk("activating NMI Watchdog ...");
+ printk(KERN_INFO "activating NMI Watchdog ...");
smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1);
enable_NMI_through_LVT0(NULL);
@@ -1299,7 +1301,7 @@ static inline void check_timer(void)
pin1 = find_timer_pin(mp_INT);
pin2 = find_timer_pin(mp_ExtINT);
- printk("..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2);
+ printk(KERN_INFO "..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2);
/*
* Ok, does IRQ0 through the IOAPIC work?
@@ -1317,11 +1319,11 @@ static inline void check_timer(void)
}
if (pin1 != -1) {
- printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
+ printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
clear_IO_APIC_pin(0, pin1);
}
- printk("...trying to set up timer (IRQ0) through the 8259A ... ");
+ printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
if (pin2 != -1) {
printk("\n..... (found pin %d) ...", pin2);
/*
@@ -1345,11 +1347,11 @@ static inline void check_timer(void)
printk(" failed.\n");
if (nmi_watchdog) {
- printk("timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n");
+ printk(KERN_WARNING "timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n");
nmi_watchdog = 0;
}
- printk("...trying to set up timer as Virtual Wire IRQ...");
+ printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
disable_8259A_irq(0);
irq_desc[0].handler = &lapic_irq_type;
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index d9af88d82..c7c079194 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -597,10 +597,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
- *
- * Note that we go through the signals twice: once to check the signals that
- * the kernel can handle, and then we build all the user-level signal handling
- * stack-frames in one go after that.
*/
int do_signal(struct pt_regs *regs, sigset_t *oldset)
{
diff --git a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S
index 904f70f90..0d66abee0 100644
--- a/arch/i386/lib/checksum.S
+++ b/arch/i386/lib/checksum.S
@@ -25,6 +25,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/config.h>
#include <asm/errno.h>
/*
@@ -39,7 +40,7 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
.align 4
.globl csum_partial
-#if CPU!=686
+#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
/*
* Experiments with Ethernet and SLIP connections show that buff
@@ -114,7 +115,9 @@ csum_partial:
popl %esi
ret
-#else /* CPU==686 */
+#else
+
+/* Version for PentiumII/PPro */
csum_partial:
pushl %esi
@@ -210,7 +213,7 @@ csum_partial:
popl %esi
ret
-#endif /* CPU==686 */
+#endif
/*
unsigned int csum_partial_copy_generic (const char *src, char *dst,
@@ -243,7 +246,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
.align 4
.globl csum_partial_copy_generic
-#if CPU!=686
+#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
#define ARGBASE 16
#define FP 12
@@ -448,4 +451,4 @@ DST( movb %dl, (%edi) )
#undef ROUND
#undef ROUND1
-#endif /* CPU==i686 */
+#endif
diff --git a/arch/ia64/config.in b/arch/ia64/config.in
index e22e1dd01..b0d924d14 100644
--- a/arch/ia64/config.in
+++ b/arch/ia64/config.in
@@ -19,11 +19,11 @@ choice 'Kernel page size' \
if [ "$CONFIG_IA64_DIG" = "y" ]; then
bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC
- bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS n
- bool ' Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS y
- bool ' Enable Lion hacks' CONFIG_IA64_LION_HACKS n
- bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU n
- bool ' Get PCI IRQ routing from firmware/ACPI' CONFIG_IA64_IRQ_ACPI y
+ bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS
+ bool ' Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS
+ bool ' Enable Lion hacks' CONFIG_IA64_LION_HACKS
+ bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU
+ bool ' Get PCI IRQ routing from firmware/ACPI' CONFIG_IA64_IRQ_ACPI
fi
if [ "$CONFIG_IA64_GENERIC" = "y" ]; then
@@ -37,33 +37,32 @@ fi
define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore.
-bool 'SMP support' CONFIG_SMP n
-bool 'Performance monitor support' CONFIG_PERFMON n
+bool 'SMP support' CONFIG_SMP
+bool 'Performance monitor support' CONFIG_PERFMON
-bool 'Networking support' CONFIG_NET n
-bool 'System V IPC' CONFIG_SYSVIPC n
-bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT n
-bool 'Sysctl support' CONFIG_SYSCTL n
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-bool 'PCI support' CONFIG_PCI n
+bool 'PCI support' CONFIG_PCI
source drivers/pci/Config.in
source drivers/pcmcia/Config.in
mainmenu_option next_comment
comment 'Code maturity level options'
- bool 'Prompt for development and/or incomplete code/drivers' \
- CONFIG_EXPERIMENTAL n
+ bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
- bool 'Enable loadable module support' CONFIG_MODULES n
+ bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
- bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n
- bool 'Kernel module loader' CONFIG_KMOD n
+ bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
@@ -99,7 +98,7 @@ tristate 'SCSI support' CONFIG_SCSI
if [ "$CONFIG_SCSI" != "n" ]; then
source drivers/scsi/Config.in
- bool 'Simulated SCSI disk' CONFIG_SCSI_SIM n
+ bool 'Simulated SCSI disk' CONFIG_SCSI_SIM
fi
endmenu
@@ -107,7 +106,7 @@ if [ "$CONFIG_NET" = "y" ]; then
mainmenu_option next_comment
comment 'Network device support'
- bool 'Network device support' CONFIG_NETDEVICES n
+ bool 'Network device support' CONFIG_NETDEVICES
if [ "$CONFIG_NETDEVICES" = "y" ]; then
source drivers/net/Config.in
fi
@@ -128,7 +127,7 @@ endmenu
mainmenu_option next_comment
comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI n
+bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
source drivers/cdrom/Config.in
fi
@@ -145,11 +144,11 @@ source fs/nls/Config.in
if [ "$CONFIG_VT" = "y" ]; then
mainmenu_option next_comment
comment 'Console drivers'
- bool 'VGA text console' CONFIG_VGA_CONSOLE n
+ bool 'VGA text console' CONFIG_VGA_CONSOLE
+ source drivers/video/Config.in
if [ "$CONFIG_FB" = "y" ]; then
define_bool CONFIG_PCI_CONSOLE y
fi
- source drivers/video/Config.in
endmenu
fi
@@ -173,11 +172,11 @@ else
define_bool CONFIG_MATHEMU y
fi
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ n
-bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK n
-bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG n
-bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ n
-bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS n
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
+bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
+bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
+bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS
bool 'Built-in Kernel Debugger support' CONFIG_KDB
if [ "$CONFIG_KDB" = "y" ]; then
bool 'Compile the kernel with frame pointers' CONFIG_KDB_FRAMEPTR
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index f0e36f6b2..1618d5401 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -3,6 +3,35 @@
#
#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_IA64_GENERIC is not set
+CONFIG_IA64_HP_SIM=y
+# CONFIG_IA64_SGI_SN1_SIM is not set
+# CONFIG_IA64_DIG is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_SMP is not set
+# CONFIG_PERFMON is not set
+# CONFIG_NET is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+# CONFIG_BINFMT_ELF is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
@@ -13,53 +42,56 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MODULES is not set
#
-# General setup
+# Parallel port support
#
-CONFIG_IA64_SIM=y
-CONFIG_PCI=y
-# CONFIG_PCI_QUIRKS is not set
-CONFIG_PCI_OLD_PROC=y
-# CONFIG_NET is not set
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-# CONFIG_BINFMT_ELF is not set
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_BINFMT_JAVA is not set
-# CONFIG_BINFMT_EM86 is not set
# CONFIG_PARPORT is not set
#
-# Plug and Play support
+# Plug and Play configuration
#
# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
#
# Additional Block Devices
#
# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
#
# ATA/IDE/MFM/RLL support
#
CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
# CONFIG_BLK_DEV_IDECS is not set
@@ -78,24 +110,44 @@ CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_IDEPCI_SHARE_IRQ=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_IDEDMA_PCI_AUTO=y
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_CMD64X_RAID is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_HPT366_FIP is not set
+# CONFIG_HPT366_MODE3 is not set
CONFIG_BLK_DEV_PIIX=y
CONFIG_PIIX_TUNING=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_MASTER is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
CONFIG_BLK_DEV_IDE_MODES=y
-# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
#
# CONFIG_SCSI is not set
-# CONFIG_SCSI_G_NCR5380_PORT is not set
-# CONFIG_SCSI_G_NCR5380_MEM is not set
#
# Amateur Radio support
@@ -120,51 +172,91 @@ CONFIG_BLK_DEV_IDE_MODES=y
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
CONFIG_EFI_RTC=y
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
-# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
-# CONFIG_FT_NORMAL_DEBUG is not set
-# CONFIG_FT_FULL_DEBUG is not set
-# CONFIG_FT_NO_TRACE is not set
-# CONFIG_FT_NO_TRACE_AT_ALL is not set
-# CONFIG_FT_STD_FDC is not set
-# CONFIG_FT_MACH2 is not set
-# CONFIG_FT_PROBE_FC10 is not set
-# CONFIG_FT_ALT_FDC is not set
+# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
#
-# Filesystems
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# File systems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_EXT2_FS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_PROC_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_SMD_DISKLABEL is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_MAC_PARTITION is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
# CONFIG_NLS is not set
#
@@ -175,5 +267,11 @@ CONFIG_EFI_RTC=y
#
# Kernel hacking
#
+# CONFIG_IA32_SUPPORT is not set
# CONFIG_MATHEMU is not set
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_IA64_EARLY_PRINTK is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
+# CONFIG_IA64_PRINT_HAZARDS is not set
+# CONFIG_KDB is not set
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 6821efbc1..bffafa918 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -19,10 +19,6 @@ COMPILE_ARCH = $(shell uname -m)
# override top level makefile
AS += -m68020
LD += -m m68kelf
-ifneq ($(COMPILE_ARCH),$(ARCH))
- # prefix for cross-compiling binaries
- CROSS_COMPILE = m68k-linux-
-endif
ifndef CONFIG_SUN3
LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index 52b81739e..edcbeb98a 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -15,6 +15,7 @@ endmenu
mainmenu_option next_comment
comment 'Platform dependent setup'
+define_bool CONFIG_ISA n
bool 'Amiga support' CONFIG_AMIGA
bool 'Atari support' CONFIG_ATARI
if [ "$CONFIG_ATARI" = "y" ]; then
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
index e11c32b95..d7261f600 100644
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -1,6 +1,7 @@
#
# Automatically generated make config: don't edit
#
+CONFIG_UID16=y
#
# Code maturity level options
@@ -8,18 +9,19 @@
CONFIG_EXPERIMENTAL=y
#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
-
-#
-# Platform-dependent setup
+# Platform dependent setup
#
+# CONFIG_ISA is not set
CONFIG_AMIGA=y
# CONFIG_ATARI is not set
+# CONFIG_PCI is not set
# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_SUN3 is not set
+# CONFIG_Q40 is not set
#
# Processor type
@@ -28,42 +30,48 @@ CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
# CONFIG_M68060 is not set
+# CONFIG_M68KFPU_EMU is not set
# CONFIG_ADVANCED is not set
-# CONFIG_SINGLE_MEMORY_CHUNK is not set
-# CONFIG_RMW_INSNS is not set
#
# General setup
#
CONFIG_NET=y
CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_KCORE_ELF=y
# CONFIG_KCORE_AOUT is not set
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
CONFIG_ZORRO=y
-# CONFIG_AMIGA_GSP is not set
-# CONFIG_GSP_RESOLVER is not set
-# CONFIG_GSP_A2410 is not set
# CONFIG_AMIGA_PCMCIA is not set
# CONFIG_HEARTBEAT is not set
CONFIG_PROC_HARDWARE=y
+# CONFIG_PARPORT is not set
+# CONFIG_PRINTER is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
#
-# Block device driver configuration
+# Block devices
#
+# CONFIG_BLK_DEV_FD is not set
CONFIG_AMIGA_FLOPPY=y
-CONFIG_ATARI_FLOPPY=y
-# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_AMIGA_Z2RAM is not set
-# CONFIG_ATARI_ACSI is not set
-# CONFIG_ACSI_MULTI_LUN is not set
-# CONFIG_ATARI_SLM
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+
+#
+# Additional Block Devices
+#
# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_STRIPED is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
@@ -71,8 +79,9 @@ CONFIG_BLK_DEV_INITRD=y
# Networking options
#
CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
+# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -88,16 +97,17 @@ CONFIG_INET=y
#
# (it is safe to leave these untouched)
#
-# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
#
#
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
@@ -106,7 +116,6 @@ CONFIG_IP_NOSR=y
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
#
# QoS and/or fair queueing
@@ -117,6 +126,8 @@ CONFIG_IP_NOSR=y
# ATA/IDE/MFM/RLL support
#
# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
@@ -124,12 +135,15 @@ CONFIG_IP_NOSR=y
CONFIG_SCSI=y
#
-# SCSI support type (disk, tape, CDrom)
+# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
+CONFIG_ST_EXTRA_DEVS=2
CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
# CONFIG_CHR_DEV_SG is not set
#
@@ -143,6 +157,7 @@ CONFIG_SCSI_CONSTANTS=y
# SCSI low-level drivers
#
CONFIG_A3000_SCSI=y
+# CONFIG_A4000T_SCSI is not set
CONFIG_A2091_SCSI=y
CONFIG_GVP11_SCSI=y
# CONFIG_CYBERSTORM_SCSI is not set
@@ -150,13 +165,10 @@ CONFIG_GVP11_SCSI=y
# CONFIG_BLZ2060_SCSI is not set
# CONFIG_BLZ1230_SCSI is not set
# CONFIG_FASTLANE_SCSI is not set
-# CONFIG_A4000T_SCSI is not set
# CONFIG_A4091_SCSI is not set
# CONFIG_WARPENGINE_SCSI is not set
# CONFIG_BLZ603EPLUS_SCSI is not set
-CONFIG_ATARI_SCSI=y
-# CONFIG_ATARI_SCSI_TOSHIBA_DELAY is not set
-# CONFIG_ATARI_SCSI_RESET_BOOT is not set
+# CONFIG_OKTAGON_SCSI is not set
#
# Network device support
@@ -165,80 +177,150 @@ CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_SLIP is not set
# CONFIG_PPP is not set
+# CONFIG_EQUALIZER is not set
# CONFIG_ARIADNE is not set
# CONFIG_ARIADNE2 is not set
# CONFIG_A2065 is not set
# CONFIG_HYDRA is not set
-# CONFIG_APNE is not set
-# CONFIG_ATARILANCE is not set
-# CONFIG_ATARI_BIONET is not set
-# CONFIG_ATARI_PAMSNET is not set
#
-# Filesystems
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_AMIGAMOUSE=y
+CONFIG_BUSMOUSE=y
+CONFIG_AMIGA_BUILTIN_SERIAL=y
+# CONFIG_GVPIOEXT is not set
+# CONFIG_GVPIOEXT_LP is not set
+# CONFIG_GVPIOEXT_PLIP is not set
+# CONFIG_MULTIFACE_III_TTY is not set
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_USERIAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# Sound support
+#
+# CONFIG_SOUND is not set
+
+#
+# File systems
#
# CONFIG_QUOTA is not set
-CONFIG_MINIX_FS=y
-CONFIG_EXT2_FS=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
-# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
-# CONFIG_MSDOS_PARTITION is not set
-CONFIG_PROC_FS=y
-CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
-# CONFIG_SMB_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+CONFIG_MINIX_FS=y
+# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_CRAMFS is not set
#
-# Frame buffer devices
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_AMIGA_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Console drivers
+#
+CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
CONFIG_FB_AMIGA=y
CONFIG_FB_AMIGA_OCS=y
CONFIG_FB_AMIGA_ECS=y
CONFIG_FB_AMIGA_AGA=y
# CONFIG_FB_CYBER is not set
# CONFIG_FB_VIRGE is not set
-# CONFIG_FB_CVPPC is not set
# CONFIG_FB_RETINAZ3 is not set
-# CONFIG_FB_CLGEN is not set
-# CONFIG_FB_ATARI is not set
+# CONFIG_FB_FM2 is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
-
-CONFIG_NLS_CODEPAGE_437=y
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_M68K_PRINTER is not set
-CONFIG_AMIGAMOUSE=y
-CONFIG_ATARIMOUSE=y
-CONFIG_AMIGA_BUILTIN_SERIAL=y
-# CONFIG_GVPIOEXT is not set
-# CONFIG_GVPIOEXT_LP is not set
-# CONFIG_GVPIOEXT_PLIP is not set
-# CONFIG_MULTIFACE_III_TTY is not set
-# CONFIG_USERIAL is not set
-# CONFIG_WATCHDOG is not set
-# CONFIG_UMISC is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-# CONFIG_DMASOUND is not set
+CONFIG_FBCON_MFB=y
+CONFIG_FBCON_AFB=y
+CONFIG_FBCON_ILBM=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_PEARL_8x8=y
#
# Kernel hacking
#
-CONFIG_SCSI_CONSTANTS=y
+# CONFIG_MAGIC_SYSRQ is not set
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 14a62ac8f..7a400b3e0 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.45 2000/03/19 01:28:43 ralf Exp $
+# $Id: config.in,v 1.46 2000/03/26 22:59:01 ralf Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -38,15 +38,13 @@ fi
if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
"$CONFIG_OLIVETTI_M700" = "y" ]; then
define_bool CONFIG_ARC32 y
- define_bool CONFIG_ISA y
define_bool CONFIG_HAVE_IO_PORTS y
- define_bool CONFIG_MIPS_JAZZ y
define_bool CONFIG_FB y
define_bool CONFIG_FB_G364 y
+ define_bool CONFIG_MIPS_JAZZ y
fi
if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
define_bool CONFIG_ARC32 y
- define_bool CONFIG_ISA y
define_bool CONFIG_HAVE_IO_PORTS y
define_bool CONFIG_MIPS_JAZZ y
fi
@@ -55,14 +53,19 @@ if [ "$CONFIG_SGI_IP22" = "y" ]; then
fi
if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
define_bool CONFIG_ARC32 y
- define_bool CONFIG_ISA y
define_bool CONFIG_HAVE_IO_PORTS y
- define_bool CONFIG_PCI y
fi
if [ "$CONFIG_DDB5074" = "y" ]; then
- define_bool CONFIG_PCI y
define_bool CONFIG_HAVE_IO_PORTS y
fi
+
+if [ "$CONFIG_ISA" != "y" ]; then
+ define_bool CONFIG_ISA n
+fi
+
+if [ "$CONFIG_PCI" != "y" ]; then
+ define_bool CONFIG_PCI n
+fi
endmenu
mainmenu_option next_comment
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index d1cf64e51..7fd9442b6 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -20,6 +20,8 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
CONFIG_ARC32=y
+# CONFIG_ISA is not set
+# CONFIG_PCI is not set
#
# CPU selection
@@ -338,8 +340,19 @@ CONFIG_LOCKD=y
#
# Partition Types
#
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation
index 7bef250f8..64b06c4d8 100644
--- a/arch/mips/defconfig-decstation
+++ b/arch/mips/defconfig-decstation
@@ -19,6 +19,8 @@ CONFIG_DECSTATION=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_PCI is not set
#
# CPU selection
diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22
index d1cf64e51..7fd9442b6 100644
--- a/arch/mips/defconfig-ip22
+++ b/arch/mips/defconfig-ip22
@@ -20,6 +20,8 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
CONFIG_ARC32=y
+# CONFIG_ISA is not set
+# CONFIG_PCI is not set
#
# CPU selection
@@ -338,8 +340,19 @@ CONFIG_LOCKD=y
#
# Partition Types
#
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 47947bbf0..78b41c448 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -1,4 +1,4 @@
-/* $Id: irixelf.c,v 1.27 2000/03/19 01:28:43 ralf Exp $
+/* $Id: irixelf.c,v 1.28 2000/03/23 02:25:42 ralf Exp $
*
* irixelf.c: Code to load IRIX ELF executables which conform to
* the MIPS ABI.
@@ -231,15 +231,13 @@ unsigned long * create_irix_tables(char * p, int argc, int envc,
* an ELF header.
*/
static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
- struct dentry * interpreter_dentry,
+ struct file * interpreter,
unsigned int *interp_load_addr)
{
- struct file * file;
struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt;
unsigned int len;
unsigned int load_addr;
- int elf_exec_fileno;
int elf_bss;
int retval;
unsigned int last_bss;
@@ -259,8 +257,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
!elf_check_arch(interp_elf_ex->e_machine) ||
- (!interpreter_dentry->d_inode->i_fop ||
- !interpreter_dentry->d_inode->i_fop->mmap)) {
+ !interpreter->f_op->mmap) {
printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type);
return 0xffffffff;
}
@@ -291,23 +288,14 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
return 0xffffffff;
}
- retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
+ retval = kernel_read(interpreter, interp_elf_ex->e_phoff,
(char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
+ sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
#ifdef DEBUG_ELF
dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
#endif
- elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
- if (elf_exec_fileno < 0) {
- printk("Could not open IRIX interp inode.\n");
- kfree(elf_phdata);
- return 0xffffffff;
- }
-
- file = fget(elf_exec_fileno);
-
eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
if(eppnt->p_type == PT_LOAD) {
@@ -322,12 +310,12 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
#ifdef DEBUG_ELF
printk("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
- file, vaddr,
+ interpreter, vaddr,
(unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
(unsigned long) elf_prot, (unsigned long) elf_type,
(unsigned long) (eppnt->p_offset & 0xfffff000));
#endif
- error = do_mmap(file, vaddr,
+ error = do_mmap(interpreter, vaddr,
eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
elf_prot, elf_type,
eppnt->p_offset & 0xfffff000);
@@ -364,8 +352,6 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
}
/* Now use mmap to map the library into memory. */
- fput(file);
- sys_close(elf_exec_fileno);
if(error < 0 && error > -1024) {
#ifdef DEBUG_ELF
printk("got error %d\n", error);
@@ -408,9 +394,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
/* First of all, some simple consistency checks */
if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
- !elf_check_arch(ehp->e_machine) ||
- (!bprm->dentry->d_inode->i_fop ||
- !bprm->dentry->d_inode->i_fop->mmap)) {
+ !elf_check_arch(ehp->e_machine) || !bprm->file->f_op->mmap) {
return -ENOEXEC;
}
@@ -436,15 +420,14 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
/* Look for an IRIX ELF interpreter. */
static inline int look_for_irix_interpreter(char **name,
- struct dentry **interpreter_dentry,
+ struct file **interpreter,
struct elfhdr *interp_elf_ex,
struct elf_phdr *epp,
struct linux_binprm *bprm, int pnum)
{
- mm_segment_t old_fs;
int i;
int retval = -EINVAL;
- struct dentry *dentry = NULL;
+ struct file *file = NULL;
*name = NULL;
for(i = 0; i < pnum; i++, epp++) {
@@ -462,33 +445,27 @@ static inline int look_for_irix_interpreter(char **name,
return -ENOMEM;
strcpy(*name, IRIX_INTERP_PREFIX);
- retval = read_exec(bprm->dentry, epp->p_offset, (*name + 16),
- epp->p_filesz, 1);
+ retval = kernel_read(bprm->file, epp->p_offset, (*name + 16),
+ epp->p_filesz);
if (retval < 0)
goto out;
- old_fs = get_fs(); set_fs(get_ds());
- lock_kernel();
- dentry = namei(*name);
- unlock_kernel();
- set_fs(old_fs);
- if (IS_ERR(dentry)) {
- retval = PTR_ERR(dentry);
+ file = open_exec(*name);
+ if (IS_ERR(file)) {
+ retval = PTR_ERR(file);
goto out;
}
- retval = read_exec(dentry, 0, bprm->buf, 128, 1);
- if(retval < 0)
+ retval = kernel_read(file, 0, bprm->buf, 128);
+ if (retval < 0)
goto dput_and_out;
- *interp_elf_ex = *((struct elfhdr *) bprm->buf);
+ *interp_elf_ex = *(struct elfhdr *) bprm->buf;
}
- *interpreter_dentry = dentry;
+ *interpreter = file;
return 0;
dput_and_out:
- lock_kernel();
- dput(dentry);
- unlock_kernel();
+ fput(file);
out:
kfree(*name);
return retval;
@@ -549,7 +526,7 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu
}
static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
- struct dentry *identry, unsigned int *iladdr,
+ struct file *interp, unsigned int *iladdr,
int pnum, mm_segment_t old_fs,
unsigned int *eentry)
{
@@ -565,15 +542,13 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
return -1;
set_fs(old_fs);
- *eentry = load_irix_interp(ihp, identry, iladdr);
+ *eentry = load_irix_interp(ihp, interp, iladdr);
old_fs = get_fs();
set_fs(get_ds());
- lock_kernel();
- dput(identry);
- unlock_kernel();
+ fput(interp);
- if(*eentry == 0xffffffff)
+ if (*eentry == 0xffffffff)
return -1;
}
return 0;
@@ -610,14 +585,13 @@ void irix_map_prda_page (void)
static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct elfhdr elf_ex, interp_elf_ex;
- struct dentry *interpreter_dentry;
+ struct file *interpreter;
struct elf_phdr *elf_phdata, *elf_ihdr, *elf_ephdr;
unsigned int load_addr, elf_bss, elf_brk;
unsigned int elf_entry, interp_load_addr = 0;
unsigned int start_code, end_code, end_data, elf_stack;
- int elf_exec_fileno, retval, has_interp, has_ephdr, size, i;
+ int retval, has_interp, has_ephdr, size, i;
char *elf_interpreter;
- struct file *file;
mm_segment_t old_fs;
load_addr = 0;
@@ -643,8 +617,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out;
}
- retval = read_exec(bprm->dentry, elf_ex.e_phoff,
- (char *) elf_phdata, size, 1);
+ retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *)elf_phdata, size);
if (retval < 0)
goto out_free_ph;
@@ -671,10 +644,6 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_bss = 0;
elf_brk = 0;
- retval = open_dentry(bprm->dentry, O_RDONLY);
- if (retval < 0)
- goto out_free_ph;
- file = fget(elf_exec_fileno = retval);
elf_stack = 0xffffffff;
elf_interpreter = NULL;
@@ -683,7 +652,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
end_data = 0;
retval = look_for_irix_interpreter(&elf_interpreter,
- &interpreter_dentry,
+ &interpreter,
&interp_elf_ex, elf_phdata, bprm,
elf_ex.e_phnum);
if (retval)
@@ -727,13 +696,13 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
old_fs = get_fs();
set_fs(get_ds());
- map_executable(file, elf_phdata, elf_ex.e_phnum, &elf_stack,
+ map_executable(bprm->file, elf_phdata, elf_ex.e_phnum, &elf_stack,
&load_addr, &start_code, &elf_bss, &end_code,
&end_data, &elf_brk);
if(elf_interpreter) {
retval = map_interpreter(elf_phdata, &interp_elf_ex,
- interpreter_dentry, &interp_load_addr,
+ interpreter, &interp_load_addr,
elf_ex.e_phnum, old_fs, &elf_entry);
kfree(elf_interpreter);
if(retval) {
@@ -748,8 +717,6 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
set_fs(old_fs);
kfree(elf_phdata);
- fput(file);
- sys_close(elf_exec_fileno);
current->personality = PER_IRIX32;
put_exec_domain(current->exec_domain);
@@ -812,15 +779,11 @@ out:
return retval;
out_free_dentry:
- lock_kernel();
- dput(interpreter_dentry);
- unlock_kernel();
+ fput(interpreter);
out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);
out_free_file:
- fput(file);
- sys_close(elf_exec_fileno);
out_free_ph:
kfree (elf_phdata);
goto out;
@@ -833,31 +796,14 @@ static int load_irix_library(struct file *file)
{
struct elfhdr elf_ex;
struct elf_phdr *elf_phdata = NULL;
- struct dentry *dentry;
- struct inode *inode;
- unsigned int len;
- int elf_bss;
+ unsigned int len = 0;
+ int elf_bss = 0;
int retval;
unsigned int bss;
int error;
int i,j, k;
- len = 0;
- dentry = file->f_dentry;
- inode = dentry->d_inode;
- elf_bss = 0;
-
- /* Seek to the beginning of the file. */
- if (file->f_op->llseek) {
- if ((error = file->f_op->llseek(file, 0, 0)) != 0)
- return -ENOEXEC;
- } else
- file->f_pos = 0;
-
- set_fs(KERNEL_DS);
- error = file->f_op->read(file, (char *) &elf_ex, sizeof(elf_ex),
- &file->f_pos);
- set_fs(USER_DS);
+ error = kernel_read(file, 0, (char *) &elf_ex, sizeof(elf_ex));
if (error != sizeof(elf_ex))
return -ENOEXEC;
@@ -866,9 +812,7 @@ static int load_irix_library(struct file *file)
/* First of all, some simple consistency checks. */
if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- !elf_check_arch(elf_ex.e_machine) ||
- (!dentry->d_inode->i_fop ||
- !dentry->d_inode->i_fop->mmap))
+ !elf_check_arch(elf_ex.e_machine) || !file->f_op->mmap)
return -ENOEXEC;
/* Now read in all of the header information. */
@@ -880,8 +824,8 @@ static int load_irix_library(struct file *file)
if (elf_phdata == NULL)
return -ENOMEM;
- retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
+ retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata,
+ sizeof(struct elf_phdr) * elf_ex.e_phnum);
j = 0;
for(i=0; i<elf_ex.e_phnum; i++)
diff --git a/arch/mips/mm/loadmmu.c b/arch/mips/mm/loadmmu.c
index 01fadac31..6a1ad94ae 100644
--- a/arch/mips/mm/loadmmu.c
+++ b/arch/mips/mm/loadmmu.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: loadmmu.c,v 1.16 2000/03/07 15:45:28 ralf Exp $
+ * $Id: loadmmu.c,v 1.17 2000/03/13 10:33:05 raiko Exp $
*/
#include <linux/config.h>
#include <linux/init.h>
@@ -15,7 +15,6 @@
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/bootinfo.h>
-#include <asm/sgialib.h>
/* memory functions */
void (*_clear_page)(void * page);
diff --git a/arch/mips/mm/r2300.c b/arch/mips/mm/r2300.c
index cf871fb63..2e699b416 100644
--- a/arch/mips/mm/r2300.c
+++ b/arch/mips/mm/r2300.c
@@ -7,7 +7,7 @@
* Copyright (C) 1998, 2000 Harald Koerfgen
* Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
*
- * $Id: r2300.c,v 1.15 2000/02/24 00:12:40 ralf Exp $
+ * $Id: r2300.c,v 1.16 2000/03/13 10:33:05 raiko Exp $
*/
#include <linux/init.h>
#include <linux/kernel.h>
@@ -18,7 +18,6 @@
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <asm/system.h>
-#include <asm/sgialib.h>
#include <asm/isadep.h>
#include <asm/io.h>
#include <asm/wbflush.h>
diff --git a/arch/mips64/config.in b/arch/mips64/config.in
index 937b9b708..7f22687c8 100644
--- a/arch/mips64/config.in
+++ b/arch/mips64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.18 2000/03/26 23:46:56 ralf Exp $
+# $Id: config.in,v 1.19 2000/03/27 01:44:45 ralf Exp $
#
# For a description of the syntax of this configuration file,
# see the Configure script.
@@ -27,13 +27,12 @@ endmenu
#
unset CONFIG_ARC32
unset CONFIG_ARC64
+unset CONFIG_BINFMT_ELF32
+unset CONFIG_BOARD_SCACHE
unset CONFIG_BOOT_ELF32
unset CONFIG_BOOT_ELF64
-unset CONFIG_ARC32
-unset CONFIG_ARC64
-unset CONFIG_BOARD_SCACHE
unset CONFIG_COHERENT_IO
-unset CONFIG_BINFMT_ELF32
+unset CONFIG_ISA
unset CONFIG_PCI
if [ "$CONFIG_SGI_IP22" = "y" ]; then
@@ -51,6 +50,14 @@ if [ "$CONFIG_SGI_IP27" = "y" ]; then
define_bool CONFIG_QL_ISP_A64 y
fi
+if [ "$CONFIG_ISA" != "y" ]; then
+ define_bool CONFIG_ISA n
+fi
+
+if [ "$CONFIG_PCI" != "y" ]; then
+ define_bool CONFIG_PCI n
+fi
+
mainmenu_option next_comment
comment 'CPU selection'
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index 8838fed35..4f555127e 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -20,6 +20,7 @@ CONFIG_ARC64=y
CONFIG_COHERENT_IO=y
CONFIG_PCI=y
CONFIG_QL_ISP_A64=y
+# CONFIG_ISA is not set
#
# CPU selection
@@ -377,8 +378,16 @@ CONFIG_LOCKD=y
#
# Partition Types
#
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
CONFIG_KCORE_ELF=y
diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22
index 44b0b7234..c0973c4d0 100644
--- a/arch/mips64/defconfig-ip22
+++ b/arch/mips64/defconfig-ip22
@@ -16,6 +16,8 @@ CONFIG_BOOT_ELF32=y
CONFIG_ARC32=y
CONFIG_BOARD_SCACHE=y
CONFIG_ARC_MEMORY=y
+# CONFIG_ISA is not set
+# CONFIG_PCI is not set
#
# CPU selection
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index 8838fed35..4f555127e 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -20,6 +20,7 @@ CONFIG_ARC64=y
CONFIG_COHERENT_IO=y
CONFIG_PCI=y
CONFIG_QL_ISP_A64=y
+# CONFIG_ISA is not set
#
# CPU selection
@@ -377,8 +378,16 @@ CONFIG_LOCKD=y
#
# Partition Types
#
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
CONFIG_KCORE_ELF=y
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 38d9dc72e..e21140d9d 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -19,7 +19,7 @@ choice 'Processor Type' \
4xx CONFIG_4xx \
630/Power3(64-Bit) CONFIG_PPC64 \
82xx CONFIG_82xx \
- 8xx CONFIG_8xx" 6xx/7xx
+ 8xx CONFIG_8xx" 6xx
if [ "$CONFIG_4xx" = "y" ]; then
choice 'Machine Type' \
@@ -82,20 +82,18 @@ endmenu
mainmenu_option next_comment
comment 'General setup'
-if [ "$CONFIG_APUS" = "y" ]; then
- define_bool CONFIG_PCI n
-fi
-if [ "$CONFIG_OAK" = "y" ]; then
- define_bool CONFIG_PCI n
-fi
-if [ "$CONFIG_8xx" = "y" ]; then
- bool 'QSpan PCI' CONFIG_PCI
-fi
-if [ "$CONFIG_6xx" = "y" -a "$CONFIG_APUS" != "y" ]; then
- define_bool CONFIG_PCI y
-fi
-if [ "$CONFIG_PREP" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
- define_bool CONFIG_PCI y
+define_bool CONFIG_ISA n
+
+if [ "$CONFIG_APUS" = "y" -o "$CONFIG_4xx" = "y" -o \
+ "$CONFIG_82xx" = "y" ]; then
+ define_bool CONFIG_PCI n
+else
+ if [ "$CONFIG_6xx" = "y" -o CONFIG_PPC64 ]; then
+ define_bool CONFIG_PCI y
+ else
+ # CONFIG_8xx
+ bool 'QSpan PCI' CONFIG_PCI
+ fi
fi
bool 'Networking support' CONFIG_NET
diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig
index bcab91ec6..72d8f66ee 100644
--- a/arch/ppc/configs/common_defconfig
+++ b/arch/ppc/configs/common_defconfig
@@ -1,5 +1,5 @@
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
# CONFIG_UID16 is not set
@@ -33,6 +33,7 @@ CONFIG_KMOD=y
#
# General setup
#
+# CONFIG_PCI is not set
CONFIG_PCI=y
CONFIG_PCI=y
CONFIG_NET=y
@@ -56,7 +57,6 @@ CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
CONFIG_MAC_FLOPPY=y
CONFIG_MAC_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
CONFIG_ADB=y
CONFIG_ADB_CUDA=y
CONFIG_ADB_MACIO=y
@@ -73,49 +73,23 @@ CONFIG_BOOTX_TEXT=y
# Plug and Play configuration
#
# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-CONFIG_BLK_DEV_IDESCSI=y
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_IDEDMA_PCI is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
-CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_IDEDMA_PMAC_AUTO=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+
+#
+# Additional Block Devices
+#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_PARIDE is not set
-CONFIG_BLK_DEV_IDE_MODES=y
-# CONFIG_BLK_DEV_HD is not set
#
# Networking options
@@ -138,10 +112,18 @@ CONFIG_IP_MULTICAST=y
# CONFIG_IP_MROUTE is not set
CONFIG_IP_ALIAS=y
CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
+
+#
+#
+#
# CONFIG_IPX is not set
CONFIG_ATALK=m
# CONFIG_DECNET is not set
@@ -160,17 +142,71 @@ CONFIG_ATALK=m
# CONFIG_NET_SCHED is not set
#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_BLK_DEV_IDESCSI=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_IDEDMA_PMAC_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+CONFIG_BLK_DEV_IDE_MODES=y
+
+#
# SCSI support
#
CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
-CONFIG_ST_EXTRA_DEVS=2
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_SR_EXTRA_DEVS=2
CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
@@ -254,9 +290,7 @@ CONFIG_NETDEVICES=y
#
# Appletalk devices
#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
+# CONFIG_APPLETALK is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -449,17 +483,28 @@ CONFIG_NVRAM=y
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
# CONFIG_AGP is not set
#
# USB support
#
CONFIG_USB=y
+
+#
+# USB Controllers
+#
# CONFIG_USB_UHCI is not set
# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=y
+
+#
+# Miscellaneous USB options
+#
# CONFIG_USB_DEVICEFS is not set
+
+#
+# USB Devices
+#
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_SCANNER is not set
# CONFIG_USB_AUDIO is not set
@@ -470,11 +515,15 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_OV511 is not set
# CONFIG_USB_DC2XX is not set
# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_USS720 is not set
# CONFIG_USB_DABUSB is not set
# CONFIG_USB_PLUSB is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_DSBR is not set
+
+#
+# USB HID
+#
# CONFIG_USB_HID is not set
CONFIG_USB_KBD=y
CONFIG_USB_MOUSE=y
@@ -510,7 +559,6 @@ CONFIG_ISO9660_FS=y
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -524,7 +572,6 @@ CONFIG_EXT2_FS=y
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
@@ -596,8 +643,12 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
# CONFIG_SOUND_AD1816 is not set
# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_SSCAPE is not set
# CONFIG_SOUND_GUS is not set
@@ -608,11 +659,10 @@ CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_NM256 is not set
# CONFIG_SOUND_MAD16 is not set
# CONFIG_SOUND_PAS is not set
-# CONFIG_PAS_JOYSTICK is not set
# CONFIG_SOUND_PSS is not set
-# CONFIG_PSS_HAVE_BOOT is not set
# CONFIG_SOUND_SOFTOSS is not set
# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
# CONFIG_SOUND_WAVEFRONT is not set
# CONFIG_SOUND_MAUI is not set
# CONFIG_SOUND_VIA82CXXX is not set
@@ -620,11 +670,7 @@ CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_OPL3SA1 is not set
# CONFIG_SOUND_OPL3SA2 is not set
# CONFIG_SOUND_UART6850 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_AEDSP16 is not set
#
# Kernel hacking
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index 5b5288b30..1f5784701 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -1,5 +1,5 @@
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
# CONFIG_UID16 is not set
@@ -33,7 +33,7 @@ CONFIG_KMOD=y
#
# General setup
#
-CONFIG_PCI=y
+# CONFIG_ISA is not set
CONFIG_PCI=y
CONFIG_NET=y
CONFIG_SYSCTL=y
@@ -79,15 +79,19 @@ CONFIG_BOOTX_TEXT=y
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+
+#
+# Additional Block Devices
+#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_PARIDE is not set
#
# Networking options
@@ -110,10 +114,18 @@ CONFIG_IP_MULTICAST=y
# CONFIG_IP_MROUTE is not set
CONFIG_IP_ALIAS=y
CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
+
+#
+#
+#
# CONFIG_IPX is not set
CONFIG_ATALK=m
# CONFIG_DECNET is not set
@@ -135,48 +147,91 @@ CONFIG_ATALK=m
# ATA/IDE/MFM/RLL support
#
CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
CONFIG_BLK_DEV_IDE=y
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
# CONFIG_BLK_DEV_IDECS is not set
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
CONFIG_BLK_DEV_IDESCSI=y
+
+#
+# IDE chipset support/bugfixes
+#
# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
# CONFIG_BLK_DEV_IDEDMA_PCI is not set
# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
# CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_CMD64X_RAID is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_HPT366_FIP is not set
+# CONFIG_HPT366_MODE3 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_MASTER is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_BLK_DEV_IDEDMA_PMAC=y
CONFIG_IDEDMA_PMAC_AUTO=y
CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
CONFIG_BLK_DEV_IDE_MODES=y
-# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
#
CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
-CONFIG_ST_EXTRA_DEVS=2
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_SR_EXTRA_DEVS=2
CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
@@ -260,9 +315,7 @@ CONFIG_NETDEVICES=y
#
# Appletalk devices
#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
+# CONFIG_APPLETALK is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -462,10 +515,22 @@ CONFIG_NVRAM=y
# USB support
#
CONFIG_USB=y
+
+#
+# USB Controllers
+#
# CONFIG_USB_UHCI is not set
# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=y
+
+#
+# Miscellaneous USB options
+#
# CONFIG_USB_DEVICEFS is not set
+
+#
+# USB Devices
+#
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_SCANNER is not set
# CONFIG_USB_AUDIO is not set
@@ -475,12 +540,18 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_IBMCAM is not set
# CONFIG_USB_OV511 is not set
# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
# CONFIG_USB_STORAGE is not set
# CONFIG_USB_USS720 is not set
# CONFIG_USB_DABUSB is not set
# CONFIG_USB_PLUSB is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_DSBR is not set
+
+#
+# USB HID
+#
# CONFIG_USB_HID is not set
CONFIG_USB_KBD=y
CONFIG_USB_MOUSE=y
@@ -602,8 +673,12 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
# CONFIG_SOUND_AD1816 is not set
# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_SSCAPE is not set
# CONFIG_SOUND_GUS is not set
@@ -616,9 +691,9 @@ CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_PAS is not set
# CONFIG_PAS_JOYSTICK is not set
# CONFIG_SOUND_PSS is not set
-# CONFIG_PSS_HAVE_BOOT is not set
# CONFIG_SOUND_SOFTOSS is not set
# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
# CONFIG_SOUND_WAVEFRONT is not set
# CONFIG_SOUND_MAUI is not set
# CONFIG_SOUND_VIA82CXXX is not set
@@ -626,11 +701,7 @@ CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_OPL3SA1 is not set
# CONFIG_SOUND_OPL3SA2 is not set
# CONFIG_SOUND_UART6850 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_AEDSP16 is not set
#
# Kernel hacking
diff --git a/arch/sh/config.in b/arch/sh/config.in
index c711ee931..e3bfd113c 100644
--- a/arch/sh/config.in
+++ b/arch/sh/config.in
@@ -47,6 +47,8 @@ endmenu
mainmenu_option next_comment
comment 'General setup'
+define_bool CONFIG_ISA n
+
bool 'Networking support' CONFIG_NET
bool 'Directy Connected Compact Flash support' CONFIG_CF_ENABLER
diff --git a/arch/sh/defconfig b/arch/sh/defconfig
index a3f901220..fad2ab8b1 100644
--- a/arch/sh/defconfig
+++ b/arch/sh/defconfig
@@ -28,6 +28,7 @@ CONFIG_MEMORY_START=0c000000
#
# General setup
#
+# CONFIG_ISA is not set
# CONFIG_NET is not set
CONFIG_CF_ENABLER=y
# CONFIG_PCI is not set
@@ -39,12 +40,18 @@ CONFIG_KCORE_ELF=y
# CONFIG_KCORE_AOUT is not set
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
#
# Additional Block Devices
@@ -53,21 +60,25 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
#
# ATA/IDE/MFM/RLL support
#
CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
@@ -77,9 +88,11 @@ CONFIG_BLK_DEV_IDEDISK=y
# IDE chipset support/bugfixes
#
# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
@@ -101,13 +114,20 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_UNIX98_PTYS is not set
#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
@@ -115,6 +135,10 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index 6725e8cfe..2fe7a2c18 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.45 2000/01/29 01:08:48 anton Exp $
+# $Id: Makefile,v 1.46 2000/03/21 06:12:26 davem Exp $
# sparc/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index e67a43022..e77e72a76 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -36,6 +36,8 @@ bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
if [ "$CONFIG_SUN4" != "y" ]; then
bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI
source drivers/pci/Config.in
+else
+ define_bool CONFIG_PCI n
fi
tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index 868dd6851..585fa4a3b 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.42 2000/03/09 05:56:43 jj Exp $
+# $Id: Makefile,v 1.43 2000/03/21 06:12:28 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -18,6 +18,8 @@ NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >
NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
+export NEW_GCC
+
ifneq ($(NEW_GAS),y)
AS = sparc64-linux-as
LD = sparc64-linux-ld
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index b4d7e5da9..8f06e836b 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.104 2000/03/15 15:02:28 jj Exp $
+# $Id: config.in,v 1.105 2000/03/24 00:34:11 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -29,6 +29,7 @@ define_bool CONFIG_SUN_KEYBOARD y
define_bool CONFIG_SUN_CONSOLE y
define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y
+define_bool CONFIG_ISA n
bool 'PCI support' CONFIG_PCI
source drivers/pci/Config.in
@@ -230,6 +231,7 @@ if [ "$CONFIG_NET" = "y" ]; then
tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
tristate 'RealTek RTL-8139 support' CONFIG_8139TOO
tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
+ tristate 'VIA Rhine support' CONFIG_VIA_RHINE
tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100
tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
fi
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 2f1d42a19..4cfd9b565 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -24,6 +24,7 @@ CONFIG_SUN_KEYBOARD=y
CONFIG_SUN_CONSOLE=y
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
+# CONFIG_ISA is not set
CONFIG_PCI=y
CONFIG_PCI_NAMES=y
CONFIG_SUN_OPENPROMFS=m
@@ -218,7 +219,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
# CONFIG_IDEDMA_PCI_WIP is not set
# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
@@ -245,6 +245,7 @@ CONFIG_BLK_DEV_NS87415=y
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
CONFIG_BLK_DEV_IDE_MODES=y
#
@@ -336,6 +337,7 @@ CONFIG_TULIP=m
CONFIG_VORTEX=m
CONFIG_8139TOO=m
CONFIG_NE2K_PCI=m
+CONFIG_VIA_RHINE=m
CONFIG_EEPRO100=m
CONFIG_ADAPTEC_STARFIRE=m
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index f06ece682..124776f51 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.51 2000/02/08 05:11:31 jj Exp $
+# $Id: Makefile,v 1.52 2000/03/19 07:00:29 ecd Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -61,7 +61,7 @@ head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
#
binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
-ifneq ($(IS_EGCS),y)
+ifneq ($(NEW_GCC),y)
CMODEL_CFLAG := -mmedlow
else
CMODEL_CFLAG := -mcmodel=medlow
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index 3504533d1..c72f7272f 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -198,7 +198,6 @@ static u32 *create_aout32_tables(char * p, struct linux_binprm * bprm)
static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct exec ex;
- struct file * file;
int fd;
unsigned long error;
unsigned long fd_offset;
@@ -209,7 +208,7 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
@@ -245,21 +244,23 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
if (N_MAGIC(ex) == NMAGIC) {
+ loff_t pos = fd_offset;
/* Fuck me plenty... */
error = do_brk(N_TXTADDR(ex), ex.a_text);
- read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
- ex.a_text, 0);
+ bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
+ ex.a_text, &pos);
error = do_brk(N_DATADDR(ex), ex.a_data);
- read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
- ex.a_data, 0);
+ bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
+ ex.a_data, &pos);
goto beyond_if;
}
if (N_MAGIC(ex) == OMAGIC) {
+ loff_t pos = fd_offset;
do_brk(N_TXTADDR(ex) & PAGE_MASK,
ex.a_text+ex.a_data + PAGE_SIZE - 1);
- read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
- ex.a_text+ex.a_data, 0);
+ bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
+ ex.a_text+ex.a_data, &pos);
} else {
static unsigned long error_time;
if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
@@ -269,37 +270,36 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
error_time = jiffies;
}
- fd = open_dentry(bprm->dentry, O_RDONLY);
+ fd = get_unused_fd();
if (fd < 0)
return fd;
- file = fget(fd);
+ get_file(bprm->file);
+ fd_install(fd, bprm->file);
- if (!file->f_op || !file->f_op->mmap) {
- fput(file);
+ if (!bprm->file->f_op->mmap) {
+ loff_t pos = fd_offset;
sys_close(fd);
do_brk(0, ex.a_text+ex.a_data);
- read_exec(bprm->dentry, fd_offset,
- (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
+ bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
+ ex.a_text+ex.a_data, &pos);
goto beyond_if;
}
- error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
+ error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset);
if (error != N_TXTADDR(ex)) {
- fput(file);
sys_close(fd);
send_sig(SIGKILL, current, 0);
return error;
}
- error = do_mmap(file, N_DATADDR(ex), ex.a_data,
+ error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset + ex.a_text);
- fput(file);
sys_close(fd);
if (error != N_DATADDR(ex)) {
send_sig(SIGKILL, current, 0);
@@ -349,16 +349,12 @@ static int load_aout32_library(struct file *file)
unsigned long bss, start_addr, len;
unsigned long error;
int retval;
- loff_t offset = 0;
struct exec ex;
inode = file->f_dentry->d_inode;
retval = -ENOEXEC;
- /* N.B. Save current fs? */
- set_fs(KERNEL_DS);
- error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset);
- set_fs(USER_DS);
+ error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
if (error != sizeof(ex))
goto out;
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 0ba88adf6..254e2eb8a 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.83 2000/03/14 07:31:25 jj Exp $
+/* $Id: ioctl32.c,v 1.85 2000/03/23 05:25:41 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
@@ -1594,7 +1594,7 @@ static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
{
mm_segment_t old_fs = get_fs();
struct loop_info l;
- int err = 0;
+ int err = -EINVAL;
switch(cmd) {
case LOOP_SET_STATUS:
@@ -1604,11 +1604,13 @@ static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset,
8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
- if (err)
- return -EFAULT;
- set_fs (KERNEL_DS);
- err = sys_ioctl (fd, cmd, (unsigned long)&l);
- set_fs (old_fs);
+ if (err) {
+ err = -EFAULT;
+ } else {
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&l);
+ set_fs (old_fs);
+ }
break;
case LOOP_GET_STATUS:
set_fs (KERNEL_DS);
@@ -1621,10 +1623,19 @@ static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset,
(char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+ if (err)
+ err = -EFAULT;
}
break;
+ default: {
+ static int count = 0;
+ if (++count <= 20)
+ printk("%s: Unknown loop ioctl cmd, fd(%d) "
+ "cmd(%08x) arg(%08lx)\n",
+ __FUNCTION__, fd, cmd, arg);
}
- return err ? -EFAULT : 0;
+ }
+ return err;
}
extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
@@ -1803,6 +1814,8 @@ struct atm_iobuf32 {
#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
+#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
+#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
static struct {
unsigned int cmd32;
@@ -1821,7 +1834,9 @@ static struct {
{ ATM_SETESI32, ATM_SETESI },
{ ATM_SETESIF32, ATM_SETESIF },
{ ATM_GETSTAT32, ATM_GETSTAT },
- { ATM_GETSTATZ32, ATM_GETSTATZ }
+ { ATM_GETSTATZ32, ATM_GETSTATZ },
+ { ATM_GETLOOP32, ATM_GETLOOP },
+ { ATM_SETLOOP32, ATM_SETLOOP }
};
#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0]))
@@ -1941,8 +1956,6 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
unsigned int cmd = 0;
switch (cmd32) {
- case SUNI_GETLOOP:
- case SUNI_SETLOOP:
case SONET_GETSTAT:
case SONET_GETSTATZ:
case SONET_GETDIAG:
@@ -1954,7 +1967,6 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
return do_atmif_sioc(fd, cmd32, arg);
}
- if (cmd == 0) {
for (i = 0; i < NR_ATM_IOCTL; i++) {
if (cmd32 == atm_ioctl_map[i].cmd32) {
cmd = atm_ioctl_map[i].cmd;
@@ -1964,7 +1976,6 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
if (i == NR_ATM_IOCTL) {
return -EINVAL;
}
- }
switch (cmd) {
case ATM_GETNAMES:
@@ -1983,6 +1994,8 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
case ATM_SETESIF:
case ATM_GETSTAT:
case ATM_GETSTATZ:
+ case ATM_GETLOOP:
+ case ATM_SETLOOP:
return do_atmif_sioc(fd, cmd, arg);
}
@@ -3076,8 +3089,8 @@ HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl)
HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl)
HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl)
HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
-HANDLE_IOCTL(SUNI_GETLOOP, do_atm_ioctl)
-HANDLE_IOCTL(SUNI_SETLOOP, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 763acdc0f..d752f1a0d 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.139 2000/03/16 20:37:57 davem Exp $
+/* $Id: sys_sparc32.c,v 1.141 2000/03/24 01:31:30 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -3051,7 +3051,7 @@ static inline int
do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
{
struct linux_binprm bprm;
- struct dentry * dentry;
+ struct file * file;
int retval;
int i;
@@ -3059,28 +3059,24 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
lock_kernel();
- dentry = open_namei(filename);
+ file = open_exec(filename);
unlock_kernel();
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
return retval;
- bprm.dentry = dentry;
+ bprm.file = file;
bprm.filename = filename;
bprm.sh_bang = 0;
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count32(argv)) < 0) {
- lock_kernel();
- dput(dentry);
- unlock_kernel();
+ fput(file);
return bprm.argc;
}
if ((bprm.envc = count32(envp)) < 0) {
- lock_kernel();
- dput(dentry);
- unlock_kernel();
+ fput(file);
return bprm.envc;
}
@@ -3108,11 +3104,8 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
out:
/* Something went wrong, return the inode and free the argument pages*/
- if (bprm.dentry) {
- lock_kernel();
- dput(bprm.dentry);
- unlock_kernel();
- }
+ if (bprm.file)
+ fput(bprm.file);
for (i=0 ; i<MAX_ARG_PAGES ; i++)
if (bprm.page[i])
@@ -3634,7 +3627,7 @@ struct nfsctl_arg32 {
union nfsctl_res32 {
__u8 cr32_getfh[NFS_FHSIZE];
- u32 cr32_debug;
+ struct knfsd_fh cr32_getfs;
};
static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
@@ -3760,15 +3753,12 @@ static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32
return err;
}
+/* This really doesn't need translations, we are only passing
+ * back a union which contains opaque nfs file handle data.
+ */
static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
{
- int err;
-
- err = copy_to_user(&res32->cr32_getfh,
- &kres->cr_getfh,
- sizeof(res32->cr32_getfh));
- err |= __put_user(kres->cr_debug, &res32->cr32_debug);
- return err;
+ return copy_to_user(res32, kres, sizeof(*res32));
}
extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
diff --git a/arch/sparc64/lib/memcmp.S b/arch/sparc64/lib/memcmp.S
index 4c08d57c3..d34dc3d87 100644
--- a/arch/sparc64/lib/memcmp.S
+++ b/arch/sparc64/lib/memcmp.S
@@ -1,29 +1,28 @@
-/* $Id: memcmp.S,v 1.2 1997/04/01 03:43:18 davem Exp $
+/* $Id: memcmp.S,v 1.3 2000/03/23 07:51:08 davem Exp $
* Sparc64 optimized memcmp code.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
*/
.text
- .align 4
- .globl __memcmp, memcmp
+ .align 32
+ .globl __memcmp, memcmp
__memcmp:
memcmp:
- brlez,pn %o2, 2f
- sub %g0, %o2, %o3
- add %o0, %o2, %o0
- add %o1, %o2, %o1
- ldub [%o0 + %o3], %o4
-1:
- ldub [%o1 + %o3], %o5
- sub %o4, %o5, %o4
- brnz,pn %o4, 3f
- addcc %o3, 1, %o3
- bne,a,pt %xcc, 1b
- ldub [%o0 + %o3], %o4
-2:
- retl
- clr %o0
-3:
- retl
- mov %o4, %o0
+ cmp %o2, 0 ! IEU1 Group
+loop: be,pn %icc, ret_0 ! CTI
+ nop ! IEU0
+ ldub [%o0], %g5 ! LSU Group
+ ldub [%o1], %g3 ! LSU Group
+ sub %o2, 1, %o2 ! IEU0
+ add %o0, 1, %o0 ! IEU1
+ add %o1, 1, %o1 ! IEU0 Group
+ subcc %g5, %g3, %g3 ! IEU1 Group
+ be,pt %icc, loop ! CTI
+ cmp %o2, 0 ! IEU1 Group
+
+ret_n0: retl
+ mov %g3, %o0
+ret_0: retl
+ mov 0, %o0
diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile
index 481d7f328..b52bc245f 100644
--- a/drivers/acorn/block/Makefile
+++ b/drivers/acorn/block/Makefile
@@ -51,9 +51,6 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
include $(TOPDIR)/Rules.make
-.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
-
fd1772_mod.o: $(FLOPPY)
$(LD) -r -o $@ $(FLOPPY)
diff --git a/drivers/acorn/scsi/Makefile b/drivers/acorn/scsi/Makefile
index a2c94a0d5..35bc69a18 100644
--- a/drivers/acorn/scsi/Makefile
+++ b/drivers/acorn/scsi/Makefile
@@ -49,8 +49,5 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
include $(TOPDIR)/Rules.make
-.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
-
acornscsi_mod.o: acornscsi.o acornscsi-io.o
$(LD) $(LD_RFLAG) -r -o $@ acornscsi.o acornscsi-io.o
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index f126bd232..8dbf1364a 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -3,15 +3,15 @@
# Makefile for the Linux network (ATM) device drivers.
#
-L_TARGET := atm.a
-L_OBJS := atmdev_init.o
+O_TARGET := atm.o
+O_OBJS := atmdev_init.o
M_OBJS :=
MOD_LIST_NAME := ATM_MODULES
include ../../.config
ifeq ($(CONFIG_ATM_ENI),y)
-L_OBJS += eni.o
+O_OBJS += eni.o
NEED_SUNI_LX = suni.o
else
ifeq ($(CONFIG_ATM_ENI),m)
@@ -21,8 +21,8 @@ else
endif
ifeq ($(CONFIG_ATM_ZATM),y)
-L_OBJS += zatm.o
-LX_OBJS += uPD98402.o
+O_OBJS += zatm.o
+OX_OBJS += uPD98402.o
else
ifeq ($(CONFIG_ATM_ZATM),m)
M_OBJS += zatm.o
@@ -31,11 +31,11 @@ else
endif
ifeq ($(CONFIG_ATM_TNETA1570),y)
-L_OBJS += tneta1570.o suni.o
+O_OBJS += tneta1570.o suni.o
endif
ifeq ($(CONFIG_ATM_NICSTAR),y)
-L_OBJS += nicstar.o
+O_OBJS += nicstar.o
ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
NEED_SUNI_LX = suni.o
endif
@@ -55,7 +55,7 @@ else
endif
ifeq ($(CONFIG_ATM_HORIZON),y)
-L_OBJS += horizon.o
+O_OBJS += horizon.o
else
ifeq ($(CONFIG_ATM_HORIZON),m)
M_OBJS += horizon.o
@@ -63,7 +63,7 @@ else
endif
ifeq ($(CONFIG_ATM_AMBASSADOR),y)
-L_OBJS += ambassador.o
+O_OBJS += ambassador.o
else
ifeq ($(CONFIG_ATM_AMBASSADOR),m)
M_OBJS += ambassador.o
@@ -71,7 +71,7 @@ else
endif
ifeq ($(CONFIG_ATM_TCP),y)
-L_OBJS += atmtcp.o
+O_OBJS += atmtcp.o
else
ifeq ($(CONFIG_ATM_TCP),m)
M_OBJS += atmtcp.o
@@ -79,7 +79,7 @@ else
endif
ifeq ($(CONFIG_ATM_IA),y)
-L_OBJS += iphase.o
+O_OBJS += iphase.o
NEED_SUNI_LX = suni.o
else
ifeq ($(CONFIG_ATM_IA),m)
@@ -91,13 +91,13 @@ endif
ifeq ($(NEED_SUNI_LX),)
MX_OBJS += $(NEED_SUNI_MX)
else
- LX_OBJS += $(NEED_SUNI_LX)
+ OX_OBJS += $(NEED_SUNI_LX)
endif
ifeq ($(NEED_IDT77105_LX),)
MX_OBJS += $(NEED_IDT77105_MX)
else
- LX_OBJS += $(NEED_IDT77105_LX)
+ OX_OBJS += $(NEED_IDT77105_LX)
endif
ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
@@ -114,7 +114,7 @@ FORE200E_FW_OBJS += fore200e_sba_fw.o
endif
endif
ifeq ($(CONFIG_ATM_FORE200E),y)
-L_OBJS += fore200e.o $(FORE200E_FW_OBJS)
+O_OBJS += fore200e.o $(FORE200E_FW_OBJS)
else
ifeq ($(CONFIG_ATM_FORE200E),m)
M_OBJS += fore_200e.o
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 8ec9960c1..a71884db7 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -39,7 +40,7 @@
#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
#define description_string "Madge ATM Ambassador driver"
-#define version_string "1.2"
+#define version_string "1.2.4"
static inline void __init show_version (void) {
printk ("%s version %s\n", description_string, version_string);
@@ -97,8 +98,8 @@ static inline void __init show_version (void) {
The adapter is quite intelligent (fast) and has a simple interface
(few features). VPI is always zero, 1024 VCIs are supported. There
- is limited cell rate support. UBR channels can be kept and ABR
- (explicit rate, bu not EFCI) is supported. There is no CBR or VBR
+ is limited cell rate support. UBR channels can be capped and ABR
+ (explicit rate, but not EFCI) is supported. There is no CBR or VBR
support.
1. Driver <-> Adapter Communication
@@ -321,8 +322,29 @@ static unsigned int rxs_bs[NUM_RX_POOLS] = { 4080, 12240, 36720, 65535 };
static unsigned int rx_lats = 7;
static unsigned char pci_lat = 0;
+static const unsigned long onegigmask = -1 << 30;
+
/********** access to adapter **********/
+static inline void wr_plain (const amb_dev * dev, const u32 * addr, u32 data) {
+ PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x", addr, data);
+#ifdef AMB_MMIO
+ dev->membase[addr - (u32 *) 0] = data;
+#else
+ outl (data, dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
+#endif
+}
+
+static inline u32 rd_plain (const amb_dev * dev, const u32 * addr) {
+#ifdef AMB_MMIO
+ u32 data = dev->membase[addr - (u32 *) 0];
+#else
+ u32 data = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
+#endif
+ PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x", addr, data);
+ return data;
+}
+
static const amb_mem * const mem = 0;
static inline void wr_mem (const amb_dev * dev, const u32 * addr, u32 data) {
@@ -342,7 +364,7 @@ static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) {
u32 be = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
#endif
u32 data = be32_to_cpu (be);
- PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be);
+ PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be);
return data;
}
@@ -350,14 +372,18 @@ static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) {
static inline void dump_registers (const amb_dev * dev) {
#ifdef DEBUG_AMBASSADOR
- // u32 * i;
- // PRINTD (DBG_REGS, "mailboxes: ");
- // for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i)
- // PRINTD (DBG_REGS, "%08x ", rd_mem (dev, i));
- PRINTD (DBG_REGS, "doorb %08x", rd_mem (dev, (u32 *) 0x60));
- PRINTD (DBG_REGS, "irqev %08x", rd_mem (dev, (u32 *) 0x64));
- PRINTD (DBG_REGS, "irqen %08x", rd_mem (dev, (u32 *) 0x68));
- PRINTD (DBG_REGS, "reset %08x", rd_mem (dev, (u32 *) 0x6c));
+ if (debug & DBG_REGS) {
+ u32 * i;
+ PRINTD (DBG_REGS, "reading PLX control: ");
+ for (i = (u32 *) 0x00; i < (u32 *) 0x30; ++i)
+ rd_mem (dev, i);
+ PRINTD (DBG_REGS, "reading mailboxes: ");
+ for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i)
+ rd_mem (dev, i);
+ PRINTD (DBG_REGS, "reading doorb irqev irqen reset:");
+ for (i = (u32 *) 0x60; i < (u32 *) 0x70; ++i)
+ rd_mem (dev, i);
+ }
#else
(void) dev;
#endif
@@ -414,8 +440,8 @@ static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * sk
static inline int check_area (void * start, size_t length) {
// assumes length > 0
- const u32 fourmegmask = (-1)<<22;
- const u32 twofivesixmask = (-1)<<8;
+ const u32 fourmegmask = -1 << 22;
+ const u32 twofivesixmask = -1 << 8;
const u32 starthole = 0xE0000000;
u32 startaddress = virt_to_bus (start);
u32 lastaddress = startaddress+length-1;
@@ -435,7 +461,7 @@ static inline void amb_kfree_skb (struct sk_buff * skb) {
if (ATM_SKB(skb)->vcc->pop) {
ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb);
} else {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
}
@@ -448,7 +474,7 @@ static inline void tx_complete (amb_dev * dev, tx_out * tx) {
PRINTD (DBG_FLOW|DBG_TX, "tx_complete %p %p", dev, tx);
// VC layer stats
- ATM_SKB(skb)->vcc->stats->tx++;
+ atomic_inc(&ATM_SKB(skb)->vcc->stats->tx);
// free the descriptor
kfree (tx_descr);
@@ -489,7 +515,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
dump_skb ("<<<", vc, skb);
// VC layer stats
- atm_vcc->stats->rx++;
+ atomic_inc(&atm_vcc->stats->rx);
skb->stamp = xtime;
// end of our responsability
atm_vcc->push (atm_vcc, skb);
@@ -504,7 +530,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
} else {
PRINTK (KERN_INFO, "dropped over-size frame");
// should we count this?
- atm_vcc->stats->rx_drop++;
+ atomic_inc(&atm_vcc->stats->rx_drop);
}
} else {
@@ -524,7 +550,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
dev->stats.rx.unused++;
}
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
@@ -548,7 +574,8 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
// sometimes does 16-bit accesses (yuk yuk yuk)
static int command_do (amb_dev * dev, command * cmd) {
- volatile amb_cq * cq = &dev->cq;
+ amb_cq * cq = &dev->cq;
+ volatile amb_cq_ptrs * ptrs = &cq->ptrs;
command * my_slot;
unsigned long timeout;
@@ -562,18 +589,18 @@ static int command_do (amb_dev * dev, command * cmd) {
// if not full...
if (cq->pending < cq->maximum) {
// remember my slot for later
- my_slot = cq->in;
+ my_slot = ptrs->in;
PRINTD (DBG_CMD, "command in slot %p", my_slot);
dump_command (cmd);
// copy command in
- *cq->in = *cmd;
+ *ptrs->in = *cmd;
cq->pending++;
- cq->in = NEXTQ (cq->in, cq->start, cq->limit);
+ ptrs->in = NEXTQ (ptrs->in, ptrs->start, ptrs->limit);
// mail the command
- wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (cq->in));
+ wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (ptrs->in));
// prepare to wait for cq->pending milliseconds
// effectively one centisecond on i386
@@ -591,13 +618,13 @@ static int command_do (amb_dev * dev, command * cmd) {
}
// wait for my slot to be reached (all waiters are here or above, until...)
- while (cq->out != my_slot) {
- PRINTD (DBG_CMD, "wait: command slot (now at %p)", cq->out);
+ while (ptrs->out != my_slot) {
+ PRINTD (DBG_CMD, "wait: command slot (now at %p)", ptrs->out);
schedule();
}
// wait on my slot (... one gets to its slot, and... )
- while (cq->out->request != cpu_to_be32 (SRB_COMPLETE)) {
+ while (ptrs->out->request != cpu_to_be32 (SRB_COMPLETE)) {
PRINTD (DBG_CMD, "wait: command slot completion");
schedule();
}
@@ -607,12 +634,13 @@ static int command_do (amb_dev * dev, command * cmd) {
spin_lock (&cq->lock);
cq->pending--;
// copy command out
- *cmd = *cq->out;
- cq->out = NEXTQ (cq->out, cq->start, cq->limit);
+ *cmd = *ptrs->out;
+ ptrs->out = NEXTQ (ptrs->out, ptrs->start, ptrs->limit);
spin_unlock (&cq->lock);
return 0;
} else {
+ cq->filled++;
spin_unlock (&cq->lock);
return -EAGAIN;
}
@@ -796,7 +824,7 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority
return;
}
if (check_area (skb->data, skb->truesize)) {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
// cast needed as there is no %? for pointer differences
@@ -805,14 +833,14 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority
rx.handle = virt_to_bus (skb);
rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));
if (rx_give (dev, &rx, pool))
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
return;
}
-// top up all RX pools (also called as a bottom half)
+// top up all RX pools (can also be called as a bottom half)
static void fill_rx_pools (amb_dev * dev) {
unsigned char pool;
@@ -827,25 +855,23 @@ static void fill_rx_pools (amb_dev * dev) {
/********** enable host interrupts **********/
static inline void interrupts_on (amb_dev * dev) {
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- | AMB_INTERRUPT_BITS);
+ wr_plain (dev, &mem->interrupt_control,
+ rd_plain (dev, &mem->interrupt_control)
+ | AMB_INTERRUPT_BITS);
}
/********** disable host interrupts **********/
static inline void interrupts_off (amb_dev * dev) {
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- &~ AMB_INTERRUPT_BITS);
+ wr_plain (dev, &mem->interrupt_control,
+ rd_plain (dev, &mem->interrupt_control)
+ &~ AMB_INTERRUPT_BITS);
}
/********** interrupt handling **********/
static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs) {
amb_dev * dev = amb_devs;
- unsigned int irq_ok;
- unsigned int irq_ok_old;
(void) pt_regs;
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id);
@@ -860,50 +886,56 @@ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs)
break;
dev = dev->prev;
}
+ // impossible - unless we add the device to our list after both
+ // registering the IRQ handler for it and enabling interrupts, AND
+ // the card generates an IRQ at startup - should not happen again
if (!dev) {
- PRINTD (DBG_IRQ, "irq not for me: %d", irq);
+ PRINTD (DBG_IRQ, "irq for unknown device: %d", irq);
return;
}
+ // impossible - unless we have memory corruption of dev or kernel
if (irq != dev->irq) {
PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq);
return;
}
- // definitely for us
- irq_ok = 0;
- irq_ok_old = -1;
+ {
+ u32 interrupt = rd_plain (dev, &mem->interrupt);
- // perhaps disable interrupts? (disabled at PIC by Linux)
- // interrupts_off (dev);
+ // for us or someone else sharing the same interrupt
+ if (!interrupt) {
+ PRINTD (DBG_IRQ, "irq not for me: %d", irq);
+ return;
+ }
+
+ // definitely for us
+ PRINTD (DBG_IRQ, "FYI: interrupt was %08x", interrupt);
+ wr_plain (dev, &mem->interrupt, -1);
+ }
- while (irq_ok_old != irq_ok && irq_ok < 100) {
+ {
+ unsigned int irq_work = 0;
unsigned char pool;
- PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u",
- rd_mem (dev, &mem->interrupt), irq_ok);
- wr_mem (dev, &mem->interrupt, -1);
- irq_ok_old = irq_ok;
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
while (!rx_take (dev, pool))
- ++irq_ok;
+ ++irq_work;
while (!tx_take (dev))
- ++irq_ok;
- }
+ ++irq_work;
- if (irq_ok) {
-#if 0
- queue_task (&dev->bh, &tq_immediate);
- mark_bh (IMMEDIATE_BH);
+ if (irq_work) {
+#ifdef FILL_RX_POOLS_IN_BH
+ queue_task (&dev->bh, &tq_immediate);
+ mark_bh (IMMEDIATE_BH);
#else
- fill_rx_pools (dev);
+ fill_rx_pools (dev);
#endif
- PRINTD (DBG_IRQ, "work done: %u", irq_ok);
- } else {
- PRINTD (DBG_IRQ|DBG_WARN, "no work done");
+ PRINTD (DBG_IRQ, "work done: %u", irq_work);
+ } else {
+ PRINTD (DBG_IRQ|DBG_WARN, "no work done");
+ }
}
- // perhaps re-enable interrupts? (re-enabled at PIC by Linux)
- // interrupts_on (dev);
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id);
return;
}
@@ -913,6 +945,7 @@ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs)
#ifdef DEBUG_AMBASSADOR
static void dont_panic (amb_dev * dev) {
amb_cq * cq = &dev->cq;
+ volatile amb_cq_ptrs * ptrs = &cq->ptrs;
amb_txq * txq;
amb_rxq * rxq;
command * cmd;
@@ -926,10 +959,11 @@ static void dont_panic (amb_dev * dev) {
cli();
PRINTK (KERN_INFO, "don't panic - putting adapter into reset");
- wr_mem (dev, &mem->reset_control, rd_mem (dev, &mem->reset_control) | AMB_RESET);
+ wr_plain (dev, &mem->reset_control,
+ rd_plain (dev, &mem->reset_control) | AMB_RESET_BITS);
PRINTK (KERN_INFO, "marking all commands complete");
- for (cmd = cq->start; cmd < cq->limit; ++cmd)
+ for (cmd = ptrs->start; cmd < ptrs->limit; ++cmd)
cmd->request = cpu_to_be32 (SRB_COMPLETE);
PRINTK (KERN_INFO, "completing all TXs");
@@ -952,7 +986,7 @@ static void dont_panic (amb_dev * dev) {
if (rx == rxq->in.start)
rx = rxq->in.limit;
--rx;
- dev_kfree_skb (bus_to_virt (rx->handle));
+ dev_kfree_skb_any (bus_to_virt (rx->handle));
}
}
@@ -972,18 +1006,19 @@ static unsigned int make_rate (unsigned int rate, rounding r,
PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate);
- // rates in cells per second, ITU format (nasty 16bit fp)
+ // rates in cells per second, ITU format (nasty 16-bit floating-point)
// given 5-bit e and 9-bit m:
// rate = EITHER (1+m/2^9)*2^e OR 0
// bits = EITHER 1<<14 | e<<9 | m OR 0
// (bit 15 is "reserved", bit 14 "non-zero")
// smallest rate is 0 (special representation)
// largest rate is (1+511/512)*2^31 = 4290772992 (< 2^32-1)
+ // smallest non-zero rate is (1+0/512)*2^0 = 1 (> 0)
// simple algorithm:
// find position of top bit, this gives e
// remove top bit and shift (rounding if feeling clever) by 9-e
- // ucode bug: please don't set bit 14! 0 not representable
+ // ucode bug: please don't set bit 14! so 0 rate not representable
if (rate > 0xffc00000U) {
// larger than largest representable rate
@@ -1228,7 +1263,7 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
// we are not really "immediately before allocating the connection
// identifier in hardware", but it will just have to do!
- atm_vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&atm_vcc->flags);
if (txtp->traffic_class != ATM_NONE) {
command cmd;
@@ -1303,7 +1338,7 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
atm_vcc->vci = vci;
// indicate readiness
- atm_vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&atm_vcc->flags);
MOD_INC_USE_COUNT;
return 0;
@@ -1319,7 +1354,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
PRINTD (DBG_VCC|DBG_FLOW, "amb_close");
// indicate unreadiness
- atm_vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&atm_vcc->flags);
// disable TXing
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
@@ -1384,7 +1419,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
kfree (vcc);
// say the VPI/VCI is free again
- atm_vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
MOD_DEC_USE_COUNT;
}
@@ -1394,6 +1429,8 @@ static void amb_close (struct atm_vcc * atm_vcc) {
static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) {
unsigned short newdebug;
if (cmd == AMB_SETDEBUG) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
if (copy_from_user (&newdebug, arg, sizeof(newdebug))) {
// moan
return -EFAULT;
@@ -1402,6 +1439,8 @@ static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) {
return 0;
}
} else if (cmd == AMB_DONTPANIC) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
dont_panic (dev);
} else {
// moan
@@ -1453,7 +1492,7 @@ static int amb_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
}
if (check_area (skb->data, skb->len)) {
- atm_vcc->stats->tx_err++;
+ atomic_inc(&atm_vcc->stats->tx_err);
return -ENOMEM; // ?
}
@@ -1564,7 +1603,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
// at. However, I note that the ATM layer calls kfree_skb rather
// than dev_kfree_skb at this point so we are least covered as far
// as buffer locking goes. There may be bugs if pcap clones RX skbs.
-
+
PRINTD (DBG_FLOW|DBG_SKB, "amb_rx_free skb %p (atm_vcc %p, vcc %p)",
skb, atm_vcc, vcc);
@@ -1582,7 +1621,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
}
// just do what the ATM layer would have done
- kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
@@ -1733,12 +1772,12 @@ static int __init create_queues (amb_dev * dev, unsigned int cmds,
cq->high = 0;
cq->maximum = cmds - 1;
- cq->start = cmd;
- cq->in = cmd;
- cq->out = cmd;
- cq->limit = cmd + cmds;
+ cq->ptrs.start = cmd;
+ cq->ptrs.in = cmd;
+ cq->ptrs.out = cmd;
+ cq->ptrs.limit = cmd + cmds;
- memory = cq->limit;
+ memory = cq->ptrs.limit;
}
PRINTD (DBG_TX, "TX queue pair at %p", memory);
@@ -1810,7 +1849,7 @@ static int __init create_queues (amb_dev * dev, unsigned int cmds,
static void destroy_queues (amb_dev * dev) {
// all queues assumed empty
- void * memory = dev->cq.start;
+ void * memory = dev->cq.ptrs.start;
// includes txq.in, txq.out, rxq[].in and rxq[].out
PRINTD (DBG_FLOW, "destroy_queues %p", dev);
@@ -1823,9 +1862,8 @@ static void destroy_queues (amb_dev * dev) {
/********** basic loader commands and error handling **********/
-static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
- volatile loader_block * lb) {
-
+static int __init do_loader_command (volatile loader_block * lb,
+ const amb_dev * dev, loader_command cmd) {
// centisecond timeouts - guessing away here
unsigned int command_timeouts [] = {
[host_memory_test] = 15,
@@ -1939,8 +1977,9 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
lb->result = 0;
lb->command = cpu_to_be32 (cmd);
lb->valid = cpu_to_be32 (DMA_VALID);
+ // dump_registers (dev);
// dump_loader_block (lb);
- wr_mem (dev, &mem->doorbell, virt_to_bus (lb));
+ wr_mem (dev, &mem->doorbell, virt_to_bus (lb) & ~onegigmask);
timeout = command_timeouts[cmd] * HZ/100;
@@ -1957,7 +1996,7 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
if (cmd == adapter_start) {
// wait for start command to acknowledge...
timeout = HZ/10;
- while (rd_mem (dev, &mem->doorbell))
+ while (rd_plain (dev, &mem->doorbell))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -1975,27 +2014,27 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
/* loader: determine loader version */
-static int __init get_loader_version (const amb_dev * dev, u32 * version) {
- loader_block lb;
+static int __init get_loader_version (loader_block * lb,
+ const amb_dev * dev, u32 * version) {
int res;
PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version");
- res = do_loader_command (dev, get_version_number, &lb);
+ res = do_loader_command (lb, dev, get_version_number);
if (res)
return res;
if (version)
- *version = be32_to_cpu (lb.payload.version);
+ *version = be32_to_cpu (lb->payload.version);
return 0;
}
-/* loader: read or verify memory data blocks */
+/* loader: write memory data blocks */
-static int __init loader_write (const amb_dev * dev, const u32 * data,
+static int __init loader_write (loader_block * lb,
+ const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
- loader_block lb;
- transfer_block * tb = &lb.payload.transfer;
+ transfer_block * tb = &lb->payload.transfer;
PRINTD (DBG_FLOW|DBG_LOAD, "loader_write");
@@ -2005,14 +2044,16 @@ static int __init loader_write (const amb_dev * dev, const u32 * data,
tb->count = cpu_to_be32 (count);
for (i = 0; i < count; ++i)
tb->data[i] = cpu_to_be32 (data[i]);
- return do_loader_command (dev, write_adapter_memory, &lb);
+ return do_loader_command (lb, dev, write_adapter_memory);
}
-static int __init loader_verify (const amb_dev * dev, const u32 * data,
+/* loader: verify memory data blocks */
+
+static int __init loader_verify (loader_block * lb,
+ const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
- loader_block lb;
- transfer_block * tb = &lb.payload.transfer;
+ transfer_block * tb = &lb->payload.transfer;
int res;
PRINTD (DBG_FLOW|DBG_LOAD, "loader_verify");
@@ -2021,7 +2062,7 @@ static int __init loader_verify (const amb_dev * dev, const u32 * data,
return -EINVAL;
tb->address = cpu_to_be32 (address);
tb->count = cpu_to_be32 (count);
- res = do_loader_command (dev, read_adapter_memory, &lb);
+ res = do_loader_command (lb, dev, read_adapter_memory);
if (!res)
for (i = 0; i < count; ++i)
if (tb->data[i] != cpu_to_be32 (data[i])) {
@@ -2031,13 +2072,14 @@ static int __init loader_verify (const amb_dev * dev, const u32 * data,
return res;
}
-static int __init loader_start (const amb_dev * dev, u32 address) {
- loader_block lb;
-
+/* loader: start microcode */
+
+static int __init loader_start (loader_block * lb,
+ const amb_dev * dev, u32 address) {
PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");
- lb.payload.start = cpu_to_be32 (address);
- return do_loader_command (dev, adapter_start, &lb);
+ lb->payload.start = cpu_to_be32 (address);
+ return do_loader_command (lb, dev, adapter_start);
}
/********** reset card **********/
@@ -2047,19 +2089,21 @@ static int amb_reset (amb_dev * dev, int diags) {
PRINTD (DBG_FLOW|DBG_LOAD, "amb_reset");
- word = rd_mem (dev, &mem->reset_control);
-#if 0
- // clear all interrupts just in case
- wr_mem (dev, &mem->interrupt, -1);
-#endif
+ word = rd_plain (dev, &mem->reset_control);
// put card into reset state
- wr_mem (dev, &mem->reset_control, word | AMB_RESET);
+ wr_plain (dev, &mem->reset_control, word | AMB_RESET_BITS);
// wait a short while
udelay (10);
+#if 1
+ // put card into known good state
+ wr_plain (dev, &mem->interrupt_control, AMB_DOORBELL_BITS);
+ // clear all interrupts just in case
+ wr_plain (dev, &mem->interrupt, -1);
+#endif
// clear self-test done flag
- wr_mem (dev, &mem->mb.loader.ready, 0);
+ wr_plain (dev, &mem->mb.loader.ready, 0);
// take card out of reset state
- wr_mem (dev, &mem->reset_control, word &~ AMB_RESET);
+ wr_plain (dev, &mem->reset_control, word &~ AMB_RESET_BITS);
if (diags) {
unsigned long timeout;
@@ -2069,7 +2113,7 @@ static int amb_reset (amb_dev * dev, int diags) {
timeout = schedule_timeout (timeout);
// half second time-out
timeout = HZ/2;
- while (!rd_mem (dev, &mem->mb.loader.ready))
+ while (!rd_plain (dev, &mem->mb.loader.ready))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -2078,6 +2122,7 @@ static int amb_reset (amb_dev * dev, int diags) {
}
// get results of self-test
+ // XXX double check byte-order
word = rd_mem (dev, &mem->mb.loader.result);
if (word & SELF_TEST_FAILURE) {
void sf (const char * msg) {
@@ -2105,7 +2150,7 @@ static int amb_reset (amb_dev * dev, int diags) {
/********** transfer and start the microcode **********/
-static int __init ucode_init (amb_dev * dev) {
+static int __init ucode_init (loader_block * lb, amb_dev * dev) {
unsigned int i = 0;
unsigned int total = 0;
const u32 * pointer = ucode_data;
@@ -2125,10 +2170,10 @@ static int __init ucode_init (amb_dev * dev) {
else
words = MAX_TRANSFER_DATA;
total += words;
- res = loader_write (dev, pointer, address, words);
+ res = loader_write (lb, dev, pointer, address, words);
if (res)
return res;
- res = loader_verify (dev, pointer, address, words);
+ res = loader_verify (lb, dev, pointer, address, words);
if (res)
return res;
count -= words;
@@ -2138,7 +2183,7 @@ static int __init ucode_init (amb_dev * dev) {
i += 1;
}
if (*pointer == 0xdeadbeef) {
- return loader_start (dev, ucode_start);
+ return loader_start (lb, dev, ucode_start);
} else {
// cast needed as there is no %? for pointer differnces
PRINTD (DBG_LOAD|DBG_ERR,
@@ -2156,14 +2201,14 @@ static int __init amb_talk (amb_dev * dev) {
unsigned char pool;
unsigned long timeout;
- static inline u32 x (void * addr) {
+ u32 x (void * addr) {
return cpu_to_be32 (virt_to_bus (addr));
}
PRINTD (DBG_FLOW, "amb_talk %p", dev);
- a.command_start = x (dev->cq.start);
- a.command_end = x (dev->cq.limit);
+ a.command_start = x (dev->cq.ptrs.start);
+ a.command_end = x (dev->cq.ptrs.limit);
a.tx_start = x (dev->txq.in.start);
a.tx_end = x (dev->txq.in.limit);
a.txcom_start = x (dev->txq.out.start);
@@ -2192,7 +2237,7 @@ static int __init amb_talk (amb_dev * dev) {
timeout = schedule_timeout (timeout);
// give the adapter another half second?
timeout = HZ/2;
- while (rd_mem (dev, &mem->doorbell))
+ while (rd_plain (dev, &mem->doorbell))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -2259,38 +2304,55 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) {
}
static int __init amb_init (amb_dev * dev) {
- u32 version;
+ loader_block lb;
+
+ void fixup_plx_window (void) {
+ // fix up the PLX-mapped window base address to match the block
+ unsigned long blb;
+ u32 mapreg;
+ blb = virt_to_bus (&lb);
+ // the kernel stack had better not ever cross a 1Gb boundary!
+ mapreg = rd_plain (dev, &mem->stuff[10]);
+ mapreg &= ~onegigmask;
+ mapreg |= blb & onegigmask;
+ wr_plain (dev, &mem->stuff[10], mapreg);
+ return;
+ }
- /* enable adapter doorbell */
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- | AMB_DOORBELL_BITS);
+ u32 version;
if (amb_reset (dev, 1)) {
PRINTK (KERN_ERR, "card reset failed!");
- } else if (get_loader_version (dev, &version)) {
- PRINTK (KERN_INFO, "failed to get loader version");
} else {
- PRINTK (KERN_INFO, "loader version is %08x", version);
+ fixup_plx_window ();
- if (ucode_init (dev)) {
- PRINTK (KERN_ERR, "microcode failure");
- } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) {
- PRINTK (KERN_ERR, "failed to get memory for queues");
+ if (get_loader_version (&lb, dev, &version)) {
+ PRINTK (KERN_INFO, "failed to get loader version");
} else {
+ PRINTK (KERN_INFO, "loader version is %08x", version);
- if (amb_talk (dev)) {
- PRINTK (KERN_ERR, "adapter did not accept queues");
+ if (ucode_init (&lb, dev)) {
+ PRINTK (KERN_ERR, "microcode failure");
+ } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) {
+ PRINTK (KERN_ERR, "failed to get memory for queues");
} else {
- amb_ucode_version (dev);
- return 0;
- } /* amb_talk */
+ if (amb_talk (dev)) {
+ PRINTK (KERN_ERR, "adapter did not accept queues");
+ } else {
+
+ amb_ucode_version (dev);
+ return 0;
+
+ } /* amb_talk */
+
+ destroy_queues (dev);
+ } /* create_queues, ucode_init */
- destroy_queues (dev);
- } /* create_queues, ucode_init */
+ amb_reset (dev, 0);
+ } /* get_loader_version */
- } /* get_loader_version, amb_reset */
+ } /* amb_reset */
return -1;
}
@@ -2303,81 +2365,57 @@ static int __init amb_probe (void) {
amb_dev * dev;
// read resources from PCI configuration space
- u32 * membase = bus_to_virt
- (pci_dev->resource[0].start);
- u32 iobase = pci_dev->resource[1].start;
u8 irq = pci_dev->irq;
+ u32 * membase = bus_to_virt (pci_dev->resource[0].start);
+ u32 iobase = pci_dev->resource[1].start;
- // check IO region
- if (check_region (iobase, AMB_EXTENT)) {
- PRINTK (KERN_ERR, "IO range already in use!");
- return;
- }
-
- dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
- if (!dev) {
- // perhaps we should be nice: deregister all adapters and abort?
- PRINTK (KERN_ERR, "out of memory!");
- return;
- }
- memset (dev, 0, sizeof(amb_dev));
-
- // set up known dev items straight away
- dev->pci_dev = pci_dev;
-
- dev->iobase = iobase;
- dev->irq = irq;
- dev->membase = membase;
-
- // flags (currently only dead)
- dev->flags = 0;
-
- // Allocate cell rates (fibre)
- // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
- // to be really pedantic, this should be ATM_OC3c_PCR
- dev->tx_avail = ATM_OC3_PCR;
- dev->rx_avail = ATM_OC3_PCR;
-
-#if 0
- // initialise bottom half
- dev->bh.next = 0;
- dev->bh.sync = 0;
- dev->bh.routine = (void (*)(void *)) fill_rx_pools;
- dev->bh.data = dev;
-#endif
-
- // semaphore for txer/rxer modifications - we cannot use a
- // spinlock as the critical region needs to switch processes
- init_MUTEX (&dev->vcc_sf);
- // queue manipulation spinlocks; we want atomic reads and
- // writes to the queue descriptors (handles IRQ and SMP)
- // consider replacing "int pending" -> "atomic_t available"
- // => problem related to who gets to move queue pointers
- spin_lock_init (&dev->cq.lock);
- spin_lock_init (&dev->txq.lock);
- {
+ void setup_dev (void) {
unsigned char pool;
+ memset (dev, 0, sizeof(amb_dev));
+
+ // set up known dev items straight away
+ dev->pci_dev = pci_dev;
+
+ dev->iobase = iobase;
+ dev->irq = irq;
+ dev->membase = membase;
+
+ // flags (currently only dead)
+ dev->flags = 0;
+
+ // Allocate cell rates (fibre)
+ // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
+ // to be really pedantic, this should be ATM_OC3c_PCR
+ dev->tx_avail = ATM_OC3_PCR;
+ dev->rx_avail = ATM_OC3_PCR;
+
+#ifdef FILL_RX_POOLS_IN_BH
+ // initialise bottom half
+ dev->bh.next = 0;
+ dev->bh.sync = 0;
+ dev->bh.routine = (void (*)(void *)) fill_rx_pools;
+ dev->bh.data = dev;
+#endif
+
+ // semaphore for txer/rxer modifications - we cannot use a
+ // spinlock as the critical region needs to switch processes
+ init_MUTEX (&dev->vcc_sf);
+ // queue manipulation spinlocks; we want atomic reads and
+ // writes to the queue descriptors (handles IRQ and SMP)
+ // consider replacing "int pending" -> "atomic_t available"
+ // => problem related to who gets to move queue pointers
+ spin_lock_init (&dev->cq.lock);
+ spin_lock_init (&dev->txq.lock);
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
spin_lock_init (&dev->rxq[pool].lock);
}
- // grab (but share) IRQ and install handler
- if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) {
- PRINTK (KERN_ERR, "request IRQ failed!");
- // free_irq is at "endif"
- } else {
-
+ void setup_pci_dev (void) {
unsigned char lat;
- // reserve IO region
- request_region (iobase, AMB_EXTENT, DEV_LABEL);
-
- PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at IO %x, IRQ %u, MEM %p",
- iobase, irq, membase);
-
// enable bus master accesses
pci_set_master (pci_dev);
-
+
// frobnicate latency (upwards, usually)
pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
if (pci_lat) {
@@ -2389,43 +2427,78 @@ static int __init amb_probe (void) {
"increasing", lat, MIN_PCI_LATENCY);
pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY);
}
+ }
+
+ PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"
+ " IO %x, IRQ %u, MEM %p", iobase, irq, membase);
+
+ // check IO region
+ if (check_region (iobase, AMB_EXTENT)) {
+ PRINTK (KERN_ERR, "IO range already in use!");
+ return;
+ }
+
+ dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
+ if (!dev) {
+ // perhaps we should be nice: deregister all adapters and abort?
+ PRINTK (KERN_ERR, "out of memory!");
+ return;
+ }
+
+ setup_dev();
+
+ if (amb_init (dev)) {
+ PRINTK (KERN_ERR, "adapter initialisation failure");
+ } else {
+
+ setup_pci_dev();
- if (amb_init (dev)) {
- PRINTK (KERN_ERR, "adapter initialisation failure");
- } else if (!(dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, 0))) {
- PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+ // grab (but share) IRQ and install handler
+ if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) {
+ PRINTK (KERN_ERR, "request IRQ failed!");
+ // free_irq is at "endif"
} else {
- PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
- dev->atm_dev->number, dev, dev->atm_dev);
- dev->atm_dev->dev_data = (void *) dev;
+ // reserve IO region
+ request_region (iobase, AMB_EXTENT, DEV_LABEL);
- // register our address
- amb_esi (dev, dev->atm_dev->esi);
-
- // 0 bits for vpi, 10 bits for vci
- dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
- dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
-
- fill_rx_pools (dev);
-
- /* enable host interrupts */
- interrupts_on (dev);
-
- // update count and linked list
- ++devs;
- dev->prev = amb_devs;
- amb_devs = dev;
- // success
- return;
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
+ if (!dev->atm_dev) {
+ PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+ } else {
+
+ PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
+ dev->atm_dev->number, dev, dev->atm_dev);
+ dev->atm_dev->dev_data = (void *) dev;
+
+ // register our address
+ amb_esi (dev, dev->atm_dev->esi);
+
+ // 0 bits for vpi, 10 bits for vci
+ dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
+ dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
+
+ // update count and linked list
+ ++devs;
+ dev->prev = amb_devs;
+ amb_devs = dev;
+
+ // enable host interrupts
+ interrupts_on (dev);
+
+ // success
+ return;
+
+ // not currently reached
+ atm_dev_deregister (dev->atm_dev);
+ } /* atm_dev_register */
- // not currently reached
- atm_dev_deregister (dev->atm_dev);
- } /* atm_dev_register, amb_init */
+ release_region (iobase, AMB_EXTENT);
+ free_irq (irq, dev);
+ } /* request_region, request_irq */
- release_region (iobase, AMB_EXTENT);
- free_irq (irq, dev);
- } /* request_region, request_irq */
+ amb_reset (dev, 0);
+ } /* amb_init */
kfree (dev);
} /* kmalloc, end-of-fn */
@@ -2529,7 +2602,6 @@ int init_module (void) {
show_version();
- // check arguments
amb_check_args();
// get the juice
@@ -2566,8 +2638,8 @@ void cleanup_module (void) {
PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
// the drain should not be necessary
drain_rx_pools (dev);
- amb_reset (dev, 0);
interrupts_off (dev);
+ amb_reset (dev, 0);
destroy_queues (dev);
atm_dev_deregister (dev->atm_dev);
free_irq (dev->irq, dev);
@@ -2594,7 +2666,6 @@ int __init amb_detect (void) {
show_version();
- // check arguments
amb_check_args();
// get the juice
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index 93e458644..11ce866da 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -237,8 +237,6 @@
#define FP_155_RATE 0x24b1
#define FP_25_RATE 0x1f9d
-#define AMB_RESET 0x40
-
/* #define VERSION_NUMBER 0x01000000 // initial release */
/* #define VERSION_NUMBER 0x01010000 // fixed startup probs PLX MB0 not cleared */
/* #define VERSION_NUMBER 0x01020000 // changed SUNI reset timings; allowed r/w onchip */
@@ -333,9 +331,10 @@ typedef struct {
u32 reset_control;
} amb_mem;
-/* IRQ (card to host) and doorbell (host to card) enable bits */
-#define AMB_INTERRUPT_BITS 0x00030000
-#define AMB_DOORBELL_BITS 0x00000300
+/* RESET bit, IRQ (card to host) and doorbell (host to card) enable bits */
+#define AMB_RESET_BITS 0x40000000
+#define AMB_INTERRUPT_BITS 0x00000300
+#define AMB_DOORBELL_BITS 0x00030000
/* loader commands */
@@ -543,14 +542,19 @@ typedef enum {
( (current)+1 < (limit) ? (current)+1 : (start) )
typedef struct {
- spinlock_t lock;
- unsigned int pending;
- unsigned int high;
- unsigned int maximum; // size - 1 (q implementation)
command * start;
command * in;
command * out;
command * limit;
+} amb_cq_ptrs;
+
+typedef struct {
+ spinlock_t lock;
+ unsigned int pending;
+ unsigned int high;
+ unsigned int filled;
+ unsigned int maximum; // size - 1 (q implementation)
+ amb_cq_ptrs ptrs;
} amb_cq;
typedef struct {
diff --git a/drivers/atm/atmdev_init.c b/drivers/atm/atmdev_init.c
index 357cbdbe0..443831a82 100644
--- a/drivers/atm/atmdev_init.c
+++ b/drivers/atm/atmdev_init.c
@@ -39,7 +39,7 @@ int __init atmdev_init(void)
devs = 0;
#ifdef CONFIG_ATM_ENI
- devs += eni_detect();
+// devs += eni_detect();
#endif
#ifdef CONFIG_ATM_ZATM
devs += zatm_detect();
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
index cc13eb06f..64c25420e 100644
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -7,7 +7,9 @@
#include <linux/wait.h>
#include <linux/atmdev.h>
#include <linux/atm_tcp.h>
+#include <linux/bitops.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */
@@ -36,12 +38,14 @@ struct atmtcp_dev_data {
static int atmtcp_send_control(struct atm_vcc *vcc,int type,
- const struct atmtcp_control *msg,unsigned short flag)
+ const struct atmtcp_control *msg,int flag)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *out_vcc;
struct sk_buff *skb;
struct atmtcp_control *new_msg;
- unsigned short old_flags;
+ int old_test;
+ int error = 0;
out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
if (!out_vcc) return -EUNATCH;
@@ -60,16 +64,21 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type,
new_msg->type = type;
memset(&new_msg->vcc,0,sizeof(atm_kptr_t));
*(struct atm_vcc **) &new_msg->vcc = vcc;
- old_flags = vcc->flags;
+ old_test = test_bit(flag,&vcc->flags);
out_vcc->push(out_vcc,skb);
- while (!((vcc->flags ^ old_flags) & flag)) {
+ add_wait_queue(&vcc->sleep,&wait);
+ while (test_bit(flag,&vcc->flags) == old_test) {
mb();
out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
- if (!out_vcc) return -EUNATCH;
- sleep_on(&vcc->sleep);
-
+ if (!out_vcc) {
+ error = -EUNATCH;
+ break;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
}
- return 0;
+ remove_wait_queue(&vcc->sleep,&wait);
+ return error;
}
@@ -83,10 +92,10 @@ static int atmtcp_recv_control(const struct atmtcp_control *msg)
vcc->reply = msg->result;
switch (msg->type) {
case ATMTCP_CTRL_OPEN:
- vcc->flags ^= ATM_VF_READY;
+ change_bit(ATM_VF_READY,&vcc->flags);
break;
case ATMTCP_CTRL_CLOSE:
- vcc->flags ^= ATM_VF_ADDR;
+ change_bit(ATM_VF_ADDR,&vcc->flags);
break;
default:
printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n",
@@ -120,8 +129,8 @@ static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci)
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0;
msg.type = ATMTCP_CTRL_OPEN;
msg.qos = vcc->qos;
- vcc->flags |= ATM_VF_ADDR;
- vcc->flags &= ~ATM_VF_READY; /* just in case ... */
+ set_bit(ATM_VF_ADDR,&vcc->flags);
+ clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */
error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY);
if (error) return error;
return vcc->reply;
@@ -136,7 +145,7 @@ static void atmtcp_v_close(struct atm_vcc *vcc)
msg.addr.sap_family = AF_ATMPVC;
msg.addr.sap_addr.vpi = vcc->vpi;
msg.addr.sap_addr.vci = vcc->vci;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
(void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR);
}
@@ -168,13 +177,18 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
struct atmtcp_hdr *hdr;
int size;
+ if (vcc->qos.txtp.traffic_class == ATM_NONE) {
+ if (vcc->pop) vcc->pop(vcc,skb);
+ else dev_kfree_skb(skb);
+ return -EINVAL;
+ }
dev_data = PRIV(vcc->dev);
if (dev_data) out_vcc = dev_data->vcc;
if (!dev_data || !out_vcc) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
if (dev_data) return 0;
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
return -ENOLINK;
}
size = skb->len+sizeof(struct atmtcp_hdr);
@@ -182,7 +196,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (!new_skb) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
return -ENOBUFS;
}
hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr));
@@ -193,8 +207,8 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
out_vcc->push(out_vcc,new_skb);
- vcc->stats->tx++;
- out_vcc->stats->rx++;
+ atomic_inc(&vcc->stats->tx);
+ atomic_inc(&out_vcc->stats->rx);
return 0;
}
@@ -251,7 +265,7 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
out_vcc->qos.rxtp.traffic_class != ATM_NONE)
break;
if (!out_vcc) {
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
goto done;
}
skb_pull(skb,sizeof(struct atmtcp_hdr));
@@ -263,8 +277,8 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
new_skb->stamp = xtime;
memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
out_vcc->push(out_vcc,new_skb);
- vcc->stats->tx++;
- out_vcc->stats->rx++;
+ atomic_inc(&vcc->stats->tx);
+ atomic_inc(&out_vcc->stats->rx);
done:
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
@@ -305,7 +319,7 @@ static struct atm_dev atmtcp_control_dev = {
999, /* dummy device number */
NULL,NULL, /* pretend not to have any VCCs */
NULL,NULL, /* no data */
- 0, /* no flags */
+ { 0 }, /* no flags */
NULL, /* no local address */
{ 0 } /* no ESI, no statistics */
};
@@ -318,7 +332,7 @@ static int atmtcp_create(int itf,int persist,struct atm_dev **result)
dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
if (!dev_data) return -ENOMEM;
- dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,0);
+ dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
if (!dev) {
kfree(dev_data);
return itf == -1 ? -ENOMEM : -EBUSY;
@@ -352,7 +366,8 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf)
}
PRIV(dev)->vcc = vcc;
bind_vcc(vcc,&atmtcp_control_dev);
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
vcc->dev_data = dev;
(void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */
vcc->stats = &atmtcp_control_dev.stats.aal5;
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 081fcdfed..b3240d498 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -19,8 +19,10 @@
#include <linux/uio.h>
#include <linux/init.h>
#include <linux/atm_eni.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -526,7 +528,7 @@ static int rx_aal0(struct atm_vcc *vcc)
DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n",
vcc->dev->number);
length = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
else {
length = ATM_CELL_SIZE-1; /* no HEC */
@@ -581,7 +583,7 @@ static int rx_aal5(struct atm_vcc *vcc)
size);
}
eff = length = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
else {
size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);
@@ -598,7 +600,7 @@ static int rx_aal5(struct atm_vcc *vcc)
"(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n",
vcc->dev->number,vcc->vci,length,size << 2,descr);
length = eff = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
}
skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL;
@@ -663,6 +665,7 @@ static void poll_rx(struct atm_dev *dev)
if (rx_vcc(curr)) return;
eni_dev->fast = ENI_VCC(curr)->next;
ENI_VCC(curr)->next = ENI_VCC_NOS;
+ barrier();
ENI_VCC(curr)->servicing--;
}
while ((curr = eni_dev->slow)) {
@@ -670,6 +673,7 @@ static void poll_rx(struct atm_dev *dev)
if (rx_vcc(curr)) return;
eni_dev->slow = ENI_VCC(curr)->next;
ENI_VCC(curr)->next = ENI_VCC_NOS;
+ barrier();
ENI_VCC(curr)->servicing--;
}
}
@@ -768,7 +772,7 @@ rx_dequeued++;
vcc->push(vcc,skb);
pushed++;
}
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
wake_up(&eni_dev->rx_wait);
}
@@ -836,10 +840,10 @@ static int open_rx_second(struct atm_vcc *vcc)
static void close_rx(struct atm_vcc *vcc)
{
- unsigned long here,flags;
+ DECLARE_WAITQUEUE(wait,current);
+ unsigned long here;
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
- u32 tmp;
eni_vcc = ENI_VCC(vcc);
if (!eni_vcc->rx) return;
@@ -858,25 +862,41 @@ static void close_rx(struct atm_vcc *vcc)
/* wait for RX queue to drain */
DPRINTK("eni_close: waiting for RX ...\n");
EVENT("RX closing\n",0,0);
- save_flags(flags);
- cli();
- while (eni_vcc->rxing || eni_vcc->servicing) {
+ add_wait_queue(&eni_dev->rx_wait,&wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ barrier();
+ for (;;) {
+ /* transition service->rx: rxing++, servicing-- */
+ if (!eni_vcc->servicing) {
+ barrier();
+ if (!eni_vcc->rxing) break;
+ }
EVENT("drain PDUs (rx %ld, serv %ld)\n",eni_vcc->rxing,
eni_vcc->servicing);
printk(KERN_INFO "%d+%d RX left\n",eni_vcc->servicing,
eni_vcc->rxing);
- sleep_on(&eni_dev->rx_wait);
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
}
- while (eni_vcc->rx_pos != (tmp =
- readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ)>>
- MID_VCI_READ_SHIFT) {
+ for (;;) {
+ unsigned long flags;
+ int at_end;
+ u32 tmp;
+
+ spin_lock_irqsave(&eni_dev->lock,flags);
+ tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ;
+ at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT;
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
+ if (at_end) break;
EVENT("drain discard (host 0x%lx, nic 0x%lx)\n",
eni_vcc->rx_pos,tmp);
printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n",
eni_vcc->rx_pos,tmp);
- sleep_on(&eni_dev->rx_wait);
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
}
- restore_flags(flags);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&eni_dev->rx_wait,&wait);
}
eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2);
eni_vcc->rx = NULL;
@@ -1054,8 +1074,9 @@ static enum enq_res do_tx(struct sk_buff *skb)
* 1 DMA xfer & 2 DMA'ed bytes (protocol layering is for wimps :-)
*/
+ aal5 = vcc->qos.aal == ATM_AAL5;
/* check space in buffer */
- if (!(aal5 = vcc->qos.aal == ATM_AAL5))
+ if (!aal5)
size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE;
/* cell without HEC plus segmentation header (includes
four-byte cell header) */
@@ -1207,7 +1228,7 @@ static void dequeue_tx(struct atm_dev *dev)
PCI_DMA_TODEVICE);
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb_irq(skb);
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
wake_up(&eni_dev->tx_wait);
dma_complete++;
}
@@ -1366,34 +1387,40 @@ static int open_tx_second(struct atm_vcc *vcc)
static void close_tx(struct atm_vcc *vcc)
{
+ DECLARE_WAITQUEUE(wait,current);
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
- unsigned long flags;
eni_vcc = ENI_VCC(vcc);
if (!eni_vcc->tx) return;
eni_dev = ENI_DEV(vcc->dev);
/* wait for TX queue to drain */
DPRINTK("eni_close: waiting for TX ...\n");
- save_flags(flags);
- cli();
- while (skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing) {
+ add_wait_queue(&eni_dev->tx_wait,&wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ for (;;) {
+ unsigned long flags;
+ int txing;
+
+ spin_lock_irqsave(&eni_dev->lock,flags);
+ txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing;
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
+ if (!txing) break;
DPRINTK("%d TX left\n",eni_vcc->txing);
- sleep_on(&eni_dev->tx_wait);
- }
- /*
- * Looping a few times in here is probably far cheaper than keeping
- * track of TX completions all the time, so let's poll a bit ...
- */
- while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) !=
- eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
schedule();
- restore_flags(flags);
-#if 0
- if (skb_peek(&eni_vcc->tx->backlog))
- printk(KERN_CRIT DEV_LABEL "SKBs in BACKLOG !!!\n");
-#endif
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&eni_dev->tx_wait,&wait);
if (eni_vcc->tx != eni_dev->ubr) {
+ /*
+ * Looping a few times in here is probably far cheaper than
+ * keeping track of TX completions all the time, so let's poll
+ * a bit ...
+ */
+ while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) !=
+ eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
+ schedule();
eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2);
eni_vcc->tx->send = 0;
eni_dev->tx_bw += eni_vcc->tx->reserved;
@@ -1496,28 +1523,36 @@ static void eni_int(int irq,void *dev_id,struct pt_regs *regs)
if (reason & MID_RX_DMA_COMPLETE) {
EVENT("INT: RX DMA complete, starting dequeue_rx\n",
0,0);
+ spin_lock(&eni_dev->lock);
dequeue_rx(dev);
EVENT("dequeue_rx done, starting poll_rx\n",0,0);
poll_rx(dev);
+ spin_unlock(&eni_dev->lock);
EVENT("poll_rx done\n",0,0);
/* poll_tx ? */
}
if (reason & MID_SERVICE) {
EVENT("INT: service, starting get_service\n",0,0);
+ spin_lock(&eni_dev->lock);
get_service(dev);
EVENT("get_service done, starting poll_rx\n",0,0);
poll_rx(dev);
+ spin_unlock(&eni_dev->lock);
EVENT("poll_rx done\n",0,0);
}
if (reason & MID_TX_DMA_COMPLETE) {
EVENT("INT: TX DMA COMPLETE\n",0,0);
+ spin_lock(&eni_dev->lock);
dequeue_tx(dev);
+ spin_unlock(&eni_dev->lock);
}
if (reason & MID_TX_COMPLETE) {
EVENT("INT: TX COMPLETE\n",0,0);
tx_complete++;
- wake_up(&eni_dev->tx_wait);
+ spin_lock(&eni_dev->lock);
poll_tx(dev);
+ spin_unlock(&eni_dev->lock);
+ wake_up(&eni_dev->tx_wait);
/* poll_rx ? */
}
if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK |
@@ -1532,7 +1567,7 @@ tx_complete++;
/*--------------------------------- entries ---------------------------------*/
-static const char *media_name[] __initdata = {
+static const char *media_name[] __devinitdata = {
"MMF", "SMF", "MMF", "03?", /* 0- 3 */
"UTP", "05?", "06?", "07?", /* 4- 7 */
"TAXI","09?", "10?", "11?", /* 8-11 */
@@ -1556,7 +1591,7 @@ static const char *media_name[] __initdata = {
} })
-static int __init get_esi_asic(struct atm_dev *dev)
+static int __devinit get_esi_asic(struct atm_dev *dev)
{
struct eni_dev *eni_dev;
unsigned char tonga;
@@ -1648,7 +1683,7 @@ static int __init get_esi_asic(struct atm_dev *dev)
#undef GET_SEPROM
-static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base)
+static int __devinit get_esi_fpga(struct atm_dev *dev,unsigned long base)
{
unsigned long mac_base;
int i;
@@ -1659,7 +1694,7 @@ static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base)
}
-static int __init eni_init(struct atm_dev *dev)
+static int __devinit eni_do_init(struct atm_dev *dev)
{
struct midway_eprom *eprom;
struct eni_dev *eni_dev;
@@ -1748,7 +1783,7 @@ static int __init eni_init(struct atm_dev *dev)
}
-static int __init eni_start(struct atm_dev *dev)
+static int __devinit eni_start(struct atm_dev *dev)
{
struct eni_dev *eni_dev;
unsigned long buf,buffer_mem;
@@ -1788,6 +1823,7 @@ static int __init eni_start(struct atm_dev *dev)
DPRINTK("vci 0x%lx,rx 0x%lx, tx 0x%lx,srv 0x%lx,buf 0x%lx\n",
eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,
eni_dev->service,buf);
+ spin_lock_init(&eni_dev->lock);
/* initialize memory management */
buffer_mem = eni_dev->mem-(buf-eni_dev->ram);
eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2;
@@ -1830,14 +1866,14 @@ static void eni_close(struct atm_vcc *vcc)
{
DPRINTK(">eni_close\n");
if (!ENI_VCC(vcc)) return;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
close_rx(vcc);
close_tx(vcc);
DPRINTK("eni_close: done waiting\n");
/* deallocate memory */
kfree(ENI_VCC(vcc));
ENI_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
/*foo();*/
}
@@ -1855,8 +1891,8 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
for (walk = vcc->dev->vccs; walk;
walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) &&
- walk->vci == *vci &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags)
+ && walk->vci == *vci &&
walk->qos.txtp.traffic_class !=
ATM_NONE)
break;
@@ -1872,7 +1908,7 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
return -EADDRINUSE;
if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
for (walk = vcc->dev->vccs; walk; walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) && walk->vci == *vci &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
walk->qos.txtp.traffic_class != ATM_NONE)
return -EADDRINUSE;
return 0;
@@ -1887,19 +1923,19 @@ static int eni_open(struct atm_vcc *vcc,short vpi,int vci)
DPRINTK(">eni_open\n");
EVENT("eni_open\n",0,0);
- if (!(vcc->flags & ATM_VF_PARTIAL)) ENI_VCC(vcc) = NULL;
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL;
eni_dev = ENI_DEV(vcc->dev);
error = get_ci(vcc,&vpi,&vci);
if (error) return error;
vcc->vpi = vpi;
vcc->vci = vci;
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5)
return -EINVAL;
DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi,
vcc->vci);
- if (!(vcc->flags & ATM_VF_PARTIAL)) {
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL);
if (!eni_vcc) return -ENOMEM;
ENI_VCC(vcc) = eni_vcc;
@@ -1922,7 +1958,7 @@ static int eni_open(struct atm_vcc *vcc,short vpi,int vci)
eni_close(vcc);
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
/* should power down SUNI while !ref_count @@@ */
return 0;
}
@@ -1953,8 +1989,7 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs)
* Walk through the send buffer and patch the rate information in all
* segmentation buffer descriptors of this VCC.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eni_dev->lock,flags);
for (skb = eni_dev->tx_queue.next; skb !=
(struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) {
unsigned long dsc;
@@ -1965,7 +2000,7 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs)
(tx->prescaler << MID_SEG_PR_SHIFT) |
(tx->resolution << MID_SEG_RATE_SHIFT), dsc);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
return 0;
}
@@ -2049,14 +2084,13 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
}
submitted++;
ATM_SKB(skb)->vcc = vcc;
- save_flags(flags);
- cli(); /* brute force */
+ spin_lock_irqsave(&ENI_DEV(vcc->dev)->lock,flags); /* brute force */
if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) {
skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb);
ENI_VCC(vcc)->tx->backlog_len++;
backlogged++;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&ENI_DEV(vcc->dev)->lock,flags);
return 0;
}
@@ -2206,79 +2240,86 @@ static const struct atmdev_ops ops = {
};
-int __init eni_detect(void)
+static int __devinit eni_init_one(struct pci_dev *pci_dev,
+ const struct pci_device_id *ent)
{
struct atm_dev *dev;
struct eni_dev *eni_dev;
- int devs,type;
- struct sk_buff *skb;
+ int error = -ENOMEM;
- DPRINTK("eni_detect\n");
- if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
- printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
- sizeof(skb->cb),sizeof(struct eni_skb_prv));
- return 0;
- }
- eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),
- GFP_KERNEL);
+ DPRINTK("eni_init_one\n");
+ eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),GFP_KERNEL);
if (!eni_dev) return -ENOMEM;
- devs = 0;
- for (type = 0; type < 2; type++) {
- struct pci_dev *pci_dev;
-
- pci_dev = NULL;
- while ((pci_dev = pci_find_device(PCI_VENDOR_ID_EF,type ?
- PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA,
- pci_dev))) {
- if (!devs) {
- cpu_zeroes = pci_alloc_consistent(pci_dev,
- ENI_ZEROES_SIZE,&zeroes);
- if (!cpu_zeroes) {
- kfree(eni_dev);
- return -ENOMEM;
- }
- }
- dev = atm_dev_register(DEV_LABEL,&ops,-1,0);
- if (!dev) break;
- eni_dev->pci_dev = pci_dev;
- ENI_DEV(dev) = eni_dev;
- eni_dev->asic = type;
- if (eni_init(dev) || eni_start(dev)) {
- atm_dev_deregister(dev);
- break;
- }
- eni_dev->more = eni_boards;
- eni_boards = dev;
- devs++;
- eni_dev = (struct eni_dev *) kmalloc(sizeof(struct
- eni_dev),GFP_KERNEL);
- if (!eni_dev) break;
- }
- }
- if (!devs && cpu_zeroes) {
- pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,
- cpu_zeroes,zeroes);
- cpu_zeroes = NULL;
- }
+ if (!cpu_zeroes) {
+ cpu_zeroes = pci_alloc_consistent(pci_dev,ENI_ZEROES_SIZE,
+ &zeroes);
+ if (!cpu_zeroes) goto out1;
+ }
+ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
+ if (!dev) goto out2;
+ pci_dev->driver_data = dev;
+ eni_dev->pci_dev = pci_dev;
+ ENI_DEV(dev) = eni_dev;
+ eni_dev->asic = ent->driver_data;
+ error = eni_do_init(dev);
+ if (error) goto out3;
+ error = eni_start(dev);
+ if (error) goto out3;
+ eni_dev->more = eni_boards;
+ eni_boards = dev;
+ MOD_INC_USE_COUNT; /* @@@ we don't support unloading yet */
+ return 0;
+out3:
+ atm_dev_deregister(dev);
+out2:
+ pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,cpu_zeroes,zeroes);
+ cpu_zeroes = NULL;
+out1:
kfree(eni_dev);
- return devs;
+ return error;
}
-#ifdef MODULE
+static struct pci_device_id eni_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_FPGA, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 0 /* FPGA */ },
+ { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_ASIC, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 1 /* ASIC */ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci,eni_pci_tbl);
+
-int init_module(void)
+static void __devexit eni_remove_one(struct pci_dev *pci_dev)
{
- if (!eni_detect()) {
- printk(KERN_ERR DEV_LABEL ": no adapter found\n");
- return -ENXIO;
+ /* grrr */
+}
+
+
+static struct pci_driver eni_driver = {
+ name: DEV_LABEL,
+ id_table: eni_pci_tbl,
+ probe: eni_init_one,
+ remove: eni_remove_one,
+};
+
+
+static int __init eni_init(void)
+{
+ struct sk_buff *skb; /* dummy for sizeof */
+
+ if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
+ printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
+ sizeof(skb->cb),sizeof(struct eni_skb_prv));
+ return -EIO;
}
- MOD_INC_USE_COUNT;
- return 0;
+ if (pci_register_driver(&eni_driver) > 0) return 0;
+ pci_unregister_driver (&eni_driver);
+ return -ENODEV;
}
-void cleanup_module(void)
+static void __exit eni_cleanup(void)
{
/*
* Well, there's no way to get rid of the driver yet, so we don't
@@ -2286,4 +2327,6 @@ void cleanup_module(void)
*/
}
-#endif
+
+module_init(eni_init);
+module_exit(eni_cleanup);
diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h
index 76d0dd482..23ba60fb1 100644
--- a/drivers/atm/eni.h
+++ b/drivers/atm/eni.h
@@ -12,6 +12,7 @@
#include <linux/skbuff.h>
#include <linux/time.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include "midway.h"
@@ -65,6 +66,8 @@ struct eni_vcc {
};
struct eni_dev {
+ /*-------------------------------- spinlock */
+ spinlock_t lock; /* sync with interrupt */
/*-------------------------------- base pointers into Midway address
space */
unsigned long phy; /* PHY interface chip registers */
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 4c07f2e7f..96c022842 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -1,5 +1,5 @@
/*
- $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $
+ $Id: fore200e.c,v 1.2 2000/03/21 21:19:24 davem Exp $
A FORE Systems 200E-series driver for ATM on Linux.
Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000.
@@ -35,6 +35,7 @@
#include <linux/atmdev.h>
#include <linux/sonet.h>
#include <linux/atm_suni.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/segment.h>
@@ -43,6 +44,7 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#ifdef CONFIG_ATM_FORE200E_PCA
#include <linux/pci.h>
@@ -67,7 +69,7 @@
#define FORE200E_52BYTE_AAL0_SDU
#endif
-#define FORE200E_VERSION "0.2a"
+#define FORE200E_VERSION "0.2b"
#define FORE200E "fore200e: "
@@ -187,10 +189,10 @@ fore200e_kfree(void* chunk)
/* allocate and align a chunk of memory intended to hold the data behing exchanged
- between the driver and the adapter (using streaming DVMA on SBUS hosts) */
+ between the driver and the adapter (using streaming DVMA) */
static int
-fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment)
+fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment, int direction)
{
unsigned long offset = 0;
@@ -199,6 +201,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->alloc_size = size + alignment;
chunk->align_size = size;
+ chunk->direction = direction;
chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA);
if (chunk->alloc_addr == NULL)
@@ -209,7 +212,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->align_addr = chunk->alloc_addr + offset;
- chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size);
+ chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size, direction);
return 0;
}
@@ -220,7 +223,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
static void
fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{
- fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
+ fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction);
fore200e_kfree(chunk->alloc_addr);
}
@@ -463,34 +466,32 @@ static void fore200e_pca_write(u32 val, volatile u32* addr)
static u32
-fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL);
+ u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, direction);
- DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n",
- virt_addr, size, dma_addr);
+ DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n",
+ virt_addr, size, direction, dma_addr);
return dma_addr;
}
static void
-fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size,
- PCI_DMA_BIDIRECTIONAL);
+ pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
static void
-fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size,
- PCI_DMA_BIDIRECTIONAL);
+ pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
@@ -511,10 +512,8 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int
chunk->align_addr = chunk->alloc_addr;
#else
- if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0)
+ if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0)
return -ENOMEM;
-
- chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size);
#endif
return 0;
@@ -532,8 +531,6 @@ fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
chunk->alloc_addr,
chunk->dma_addr);
#else
- fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
-
fore200e_chunk_free(fore200e, chunk);
#endif
}
@@ -685,7 +682,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
opcode.opcode = OPCODE_GET_PROM;
opcode.pad = 0;
- prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data));
+ prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE);
fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr);
@@ -697,7 +694,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data));
+ fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name);
@@ -748,31 +745,32 @@ fore200e_sba_write(u32 val, volatile u32* addr)
static u32
-fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size);
+ u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction);
- DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr);
+ DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
+ virt_addr, size, direction, dma_addr);
return dma_addr;
}
static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction);
- sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size);
+ sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
static void
-fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size);
+ sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
@@ -1002,7 +1000,8 @@ fore200e_irq_tx(struct fore200e* fore200e)
kfree(entry->data);
/* remove DMA mapping */
- fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+ FORE200E_DMA_TODEVICE);
/* notify tx completion */
if (entry->vcc->pop)
@@ -1012,9 +1011,9 @@ fore200e_irq_tx(struct fore200e* fore200e)
/* check error condition */
if (*entry->status & STATUS_ERROR)
- entry->vcc->stats->tx_err++;
+ atomic_inc(&entry->vcc->stats->tx_err);
else
- entry->vcc->stats->tx++;
+ atomic_inc(&entry->vcc->stats->tx);
*entry->status = STATUS_FREE;
@@ -1127,7 +1126,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
if (skb == NULL) {
printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
return;
}
@@ -1146,7 +1145,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
/* ensure DMA synchronisation */
- fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length);
+ fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE);
memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length);
}
@@ -1169,7 +1168,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
}
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
@@ -1404,7 +1403,7 @@ fore200e_open(struct atm_vcc *vcc, short vpi, int vci)
if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
return 0;
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
vcc->itf = vcc->dev->number;
DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
@@ -1467,7 +1466,7 @@ fore200e_open(struct atm_vcc *vcc, short vpi, int vci)
fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536;
fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0;
- vcc->flags |= ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
return 0;
}
@@ -1552,11 +1551,14 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if(--retry > 0)
goto retry_here;
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
fore200e->name, fore200e->cp_queues->heartbeat);
-
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
return -EIO;
}
}
@@ -1584,6 +1586,10 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (entry->data == NULL) {
spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
return -ENOMEM;
}
@@ -1591,11 +1597,11 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (skb_len < tx_len)
memset(entry->data + skb_len, 0x00, tx_len - skb_len);
- tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len);
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE);
}
else {
entry->data = NULL;
- tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len);
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE);
}
tpd->tsd[ 0 ].length = tx_len;
@@ -1606,7 +1612,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
spin_unlock_irqrestore(&fore200e->tx_lock, flags);
/* ensure DMA synchronisation */
- fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n",
vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
@@ -1661,27 +1667,29 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10);
- fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+ FORE200E_DMA_TODEVICE);
- if (ok == 0) {
- printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
-
- entry->vcc->stats->tx_err++;
- return -EIO;
- }
- entry->vcc->stats->tx++;
-
- DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
-
/* free tmp copy of misaligned data */
if (entry->data)
kfree(entry->data);
-
+
/* notify tx completion */
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
+
+ if (ok == 0) {
+ printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
+
+ atomic_inc(&entry->vcc->stats->tx_err);
+ return -EIO;
+ }
+ atomic_inc(&entry->vcc->stats->tx);
+
+ DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
+
}
#endif
@@ -1704,7 +1712,7 @@ fore200e_getstats(struct fore200e* fore200e)
return -ENOMEM;
}
- stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats));
+ stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
@@ -1721,7 +1729,7 @@ fore200e_getstats(struct fore200e* fore200e)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats));
+ fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get statistics from device %s\n", fore200e->name);
@@ -1766,7 +1774,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
int ok;
u32 oc3_regs_dma_addr;
- oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs));
+ oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
@@ -1785,7 +1793,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
*entry->status = STATUS_FREE;
- fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs));
+ fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name);
@@ -1842,16 +1850,16 @@ fore200e_setloop(struct fore200e* fore200e, int loop_mode)
switch (loop_mode) {
- case SUNI_LM_NONE:
+ case ATM_LM_NONE:
mct_value = 0;
mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE;
break;
- case SUNI_LM_DIAG:
+ case ATM_LM_LOC_PHY:
mct_value = mct_mask = SUNI_MCT_DLE;
break;
- case SUNI_LM_LOOP:
+ case ATM_LM_RMT_PHY:
mct_value = mct_mask = SUNI_MCT_LLE;
break;
@@ -1921,12 +1929,16 @@ fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg)
case SONET_GETDIAG:
return put_user(0, (int*)arg) ? -EFAULT : 0;
-
- case SUNI_SETLOOP:
+
+ case ATM_SETLOOP:
return fore200e_setloop(fore200e, (int)(unsigned long)arg);
- case SUNI_GETLOOP:
+ case ATM_GETLOOP:
return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0;
+
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ?
+ -EFAULT : 0;
}
return -ENOSYS; /* not implemented */
@@ -1967,7 +1979,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
/* update rate control parameters */
fore200e_rate_ctrl(qos, &fore200e_vcc->rate);
- vcc->flags |= ATM_VF_HASQOS;
+ set_bit(ATM_VF_HASQOS,&vcc->flags);
return 0;
}
@@ -2051,7 +2063,8 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
/* allocate the receive buffer body */
if (fore200e_chunk_alloc(fore200e,
- &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) {
+ &buffer[ i ].data, size, fore200e->bus->buffer_alignment,
+ FORE200E_DMA_FROMDEVICE) < 0) {
while (i > 0)
fore200e_chunk_free(fore200e, &buffer[ --i ].data);
@@ -2485,7 +2498,8 @@ fore200e_register(struct fore200e* fore200e)
DPRINTK(2, "device %s being registered\n", fore200e->name);
- atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0);
+ atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1,
+ NULL);
if (atm_dev == NULL) {
printk(FORE200E "unable to register device %s\n", fore200e->name);
return -ENODEV;
@@ -2690,17 +2704,29 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
static const char* oc3_mode[] = {
"normal operation",
"diagnostic loopback",
- "line loopback"
+ "line loopback",
+ "unknown"
};
u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release);
u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release);
u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision);
u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type));
+ u32 oc3_index;
if (media_index < 0 || media_index > 4)
media_index = 5;
+ switch(fore200e->loop_mode) {
+ case ATM_LM_NONE: oc3_index = 0;
+ break;
+ case ATM_LM_LOC_PHY: oc3_index = 1;
+ break;
+ case ATM_LM_RMT_PHY: oc3_index = 2;
+ break;
+ default: oc3_index = 3;
+ }
+
return sprintf(page,
" firmware release:\t\t%d.%d.%d\n"
" monitor release:\t\t%d.%d\n"
@@ -2711,7 +2737,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
mon960_release >> 16, mon960_release << 16 >> 16,
media_name[ media_index ],
oc3_revision,
- oc3_mode[ fore200e->loop_mode ]);
+ oc3_mode[ oc3_index ]);
}
if (!left--) {
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index eea20162b..f29fbde97 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -2,6 +2,7 @@
#define _FORE200E_H
#ifdef __KERNEL__
+#include <linux/config.h>
/* rx buffer sizes */
@@ -559,6 +560,7 @@ typedef struct chunk {
void* alloc_addr; /* base address of allocated chunk */
void* align_addr; /* base address of aligned chunk */
u32 dma_addr; /* DMA address of aligned chunk */
+ int direction; /* direction of DMA mapping */
u32 alloc_size; /* length of allocated chunk */
u32 align_size; /* length of aligned chunk */
} chunk_t;
@@ -796,9 +798,9 @@ typedef struct fore200e_bus {
const unsigned int* fw_size; /* address of firmware data size */
u32 (*read)(volatile u32*);
void (*write)(u32, volatile u32*);
- u32 (*dma_map)(struct fore200e*, void*, int);
- void (*dma_unmap)(struct fore200e*, u32, int);
- void (*dma_sync)(struct fore200e*, u32, int);
+ u32 (*dma_map)(struct fore200e*, void*, int, int);
+ void (*dma_unmap)(struct fore200e*, u32, int, int);
+ void (*dma_sync)(struct fore200e*, u32, int, int);
int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
void (*dma_chunk_free)(struct fore200e*, struct chunk*);
struct fore200e* (*detect)(const struct fore200e_bus*, int);
@@ -814,6 +816,31 @@ typedef struct fore200e_bus {
} fore200e_bus_t;
+#if defined(CONFIG_ATM_FORE200E_SBA)
+# if defined(CONFIG_ATM_FORE200E_PCA)
+# if (PCI_DMA_BIDIRECTIONAL == SBUS_DMA_BIDIRECTIONAL) && \
+ (PCI_DMA_TODEVICE == SBUS_DMA_TODEVICE) && \
+ (PCI_DMA_FROMDEVICE == SBUS_DMA_FROMDEVICE)
+# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE
+# else
+ /* in that case, we'll need to add an extra indirection, e.g.
+ fore200e->bus->dma_direction[ fore200e_dma_direction ] */
+# error PCI and SBUS DMA direction flags differ!
+# endif
+# else
+# define FORE200E_DMA_BIDIRECTIONAL SBA_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE SBA_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE SBA_DMA_FROMDEVICE
+# endif
+#else
+# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE
+#endif
+
+
/* per-device data */
typedef struct fore200e {
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 0a412667e..f0dff7011 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -42,6 +42,7 @@
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -50,7 +51,7 @@
#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
#define description_string "Madge ATM Horizon [Ultra] driver"
-#define version_string "1.2"
+#define version_string "1.2.1"
static inline void __init show_version (void) {
printk ("%s version %s\n", description_string, version_string);
@@ -246,7 +247,7 @@ static inline void __init show_version (void) {
Atomic test and set tx_busy until we succeed; we should implement
some sort of timeout so that tx_busy will never be stuck at true.
- If no TX channel is setup for this VC we wait for an idle one (if
+ If no TX channel is set up for this VC we wait for an idle one (if
necessary) and set it up.
At this point we have a TX channel ready for use. We wait for enough
@@ -276,7 +277,7 @@ static inline void __init show_version (void) {
available handler is locked out over the same period.
Data available on the card triggers an interrupt. If the data is not
- suitable for out existing RX channels or we cannot allocate a buffer
+ suitable for our existing RX channels or we cannot allocate a buffer
it is flushed. Otherwise an RX receive is scheduled. Multiple RX
transfers may be scheduled for the same frame.
@@ -321,7 +322,7 @@ static inline void __init show_version (void) {
and the frame continues to be received.
The solution is to make sure any received frames are flushed when
- ready. This is currently done just before the solution to 3.
+ ready. This is currently done just before the solution to 2.
4. PCI bus (original Horizon only, fixed in Ultra)
@@ -608,7 +609,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r,
u32 pre;
// local fn to build the timer bits
- inline int set_cr (void) {
+ int set_cr (void) {
// paranoia
if (div > CR_MAXD || (!pre) || pre > 1<<CR_MAXPEXP) {
PRINTD (DBG_QOS, "set_cr internal failure: d=%u p=%u",
@@ -813,7 +814,7 @@ static inline void hrz_kfree_skb (struct sk_buff * skb) {
if (ATM_SKB(skb)->vcc->pop) {
ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb);
} else {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
}
@@ -961,12 +962,11 @@ static void hrz_close_rx (hrz_dev * dev, u16 vc) {
static void rx_schedule (hrz_dev * dev, int irq) {
unsigned int rx_bytes;
- int pio_instead;
+ int pio_instead = 0;
#ifndef TAILRECURSIONWORKS
- do {
+ pio_instead = 1;
+ while (pio_instead) {
#endif
- pio_instead = 0;
-
// bytes waiting for RX transfer
rx_bytes = dev->rx_bytes;
@@ -1047,7 +1047,7 @@ static void rx_schedule (hrz_dev * dev, int irq) {
{
struct atm_vcc * vcc = ATM_SKB(skb)->vcc;
// VC layer stats
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
skb->stamp = xtime;
// end of our responsability
vcc->push (vcc, skb);
@@ -1078,12 +1078,12 @@ static void rx_schedule (hrz_dev * dev, int irq) {
#ifdef TAILRECURSIONWORKS
// and we all bless optimised tail calls
if (pio_instead)
- rx_schedule (dev, 0);
+ return rx_schedule (dev, 0);
return;
#else
// grrrrrrr!
irq = 0;
- } while (pio_instead);
+ }
return;
#endif
}
@@ -1130,11 +1130,11 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
int append_desc = 0;
- int pio_instead;
+ int pio_instead = 0;
#ifndef TAILRECURSIONWORKS
- do {
+ pio_instead = 1;
+ while (pio_instead) {
#endif
- pio_instead = 0;
// bytes in current region waiting for TX transfer
tx_bytes = dev->tx_bytes;
@@ -1201,7 +1201,7 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
dev->tx_iovec = 0;
// VC layer stats
- ATM_SKB(skb)->vcc->stats->tx++;
+ atomic_inc(&ATM_SKB(skb)->vcc->stats->tx);
// free the skb
hrz_kfree_skb (skb);
@@ -1236,12 +1236,12 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
#ifdef TAILRECURSIONWORKS
// and we all bless optimised tail calls
if (pio_instead)
- tx_schedule (dev, 0);
+ return tx_schedule (dev, 0);
return;
#else
// grrrrrrr!
irq = 0;
- } while (pio_instead);
+ }
return;
#endif
}
@@ -1340,37 +1340,33 @@ static inline void rx_data_av_handler (hrz_dev * dev) {
if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) {
if (rx_len <= atm_vcc->qos.rxtp.max_sdu) {
- struct sk_buff *skb = atm_alloc_charge(atm_vcc,rx_len,GFP_ATOMIC);
-
- // If everyone has to call atm_pdu2... why isn't it part of
- // atm_charge? B'cos some people already have skb->truesize!
- // WA: well. even if they think they do, they might not ... :-)
-
- if (skb) {
- // remember this so we can push it later
- dev->rx_skb = skb;
- // remember this so we can flush it later
- dev->rx_channel = rx_channel;
-
- // prepare socket buffer
- skb_put (skb, rx_len);
- ATM_SKB(skb)->vcc = atm_vcc;
-
- // simple transfer
- // dev->rx_regions = 0;
- // dev->rx_iovec = 0;
- dev->rx_bytes = rx_len;
- dev->rx_addr = skb->data;
- PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)",
- skb->data, rx_len);
-
- // do the business
- rx_schedule (dev, 0);
- return;
-
- } else {
- PRINTD (DBG_INFO, "failed to get skb");
- }
+
+ struct sk_buff * skb = atm_alloc_charge (atm_vcc, rx_len, GFP_ATOMIC);
+ if (skb) {
+ // remember this so we can push it later
+ dev->rx_skb = skb;
+ // remember this so we can flush it later
+ dev->rx_channel = rx_channel;
+
+ // prepare socket buffer
+ skb_put (skb, rx_len);
+ ATM_SKB(skb)->vcc = atm_vcc;
+
+ // simple transfer
+ // dev->rx_regions = 0;
+ // dev->rx_iovec = 0;
+ dev->rx_bytes = rx_len;
+ dev->rx_addr = skb->data;
+ PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)",
+ skb->data, rx_len);
+
+ // do the business
+ rx_schedule (dev, 0);
+ return;
+
+ } else {
+ PRINTD (DBG_SKB|DBG_WARN, "failed to get skb");
+ }
} else {
PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel);
@@ -1662,6 +1658,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
if (!channel) {
PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel");
+ hrz_kfree_skb (skb);
return -EIO;
}
@@ -1699,9 +1696,11 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
#endif
// wait until TX is free and grab lock
- if (tx_hold (dev))
+ if (tx_hold (dev)) {
+ hrz_kfree_skb (skb);
return -ERESTARTSYS;
-
+ }
+
// Wait for enough space to be available in transmit buffer memory.
// should be number of cells needed + 2 (according to hardware docs)
@@ -1722,6 +1721,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d",
free_buffers, buffers_required);
tx_release (dev);
+ hrz_kfree_skb (skb);
return -ERESTARTSYS;
}
}
@@ -1820,12 +1820,12 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
u32 ctrl = rd_regl (dev, CONTROL_0_REG);
- inline void WRITE_IT_WAIT (void) {
+ void WRITE_IT_WAIT (void) {
wr_regl (dev, CONTROL_0_REG, ctrl);
udelay (5);
}
- inline void CLOCK_IT (void) {
+ void CLOCK_IT (void) {
// DI must be valid around rising SK edge
ctrl &= ~SEEPROM_SK;
WRITE_IT_WAIT();
@@ -2530,7 +2530,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
// this is "immediately before allocating the connection identifier
// in hardware" - so long as the next call does not fail :)
- atm_vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&atm_vcc->flags);
// any errors here are very serious and should never occur
@@ -2554,7 +2554,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
atm_vcc->dev_data = (void *) vccp;
// indicate readiness
- atm_vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&atm_vcc->flags);
MOD_INC_USE_COUNT;
return 0;
@@ -2569,7 +2569,7 @@ static void hrz_close (struct atm_vcc * atm_vcc) {
PRINTD (DBG_VCC|DBG_FLOW, "hrz_close");
// indicate unreadiness
- atm_vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&atm_vcc->flags);
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
unsigned int i;
@@ -2611,7 +2611,7 @@ static void hrz_close (struct atm_vcc * atm_vcc) {
// free our structure
kfree (vcc);
// say the VPI/VCI is free again
- atm_vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
MOD_DEC_USE_COUNT;
}
@@ -2758,13 +2758,13 @@ static int __init hrz_probe (void) {
devs = 0;
pci_dev = NULL;
while ((pci_dev = pci_find_device
- (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev)
- )) {
+ (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev)
+ )) {
hrz_dev * dev;
// adapter slot free, read resources from PCI configuration space
u32 iobase = pci_dev->resource[0].start;
- u32 * membase = bus_to_virt(pci_dev->resource[1].start);
+ u32 * membase = bus_to_virt (pci_dev->resource[1].start);
u8 irq = pci_dev->irq;
// check IO region
@@ -2795,7 +2795,7 @@ static int __init hrz_probe (void) {
PRINTD (DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p",
iobase, irq, membase);
- dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0);
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, NULL);
if (!(dev->atm_dev)) {
PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
} else {
diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h
index be5e5c726..6655bdc1c 100644
--- a/drivers/atm/horizon.h
+++ b/drivers/atm/horizon.h
@@ -31,10 +31,8 @@
#define DRIVER_ATM_HORIZON_H
#include <linux/config.h>
-
#include <linux/version.h>
-
#ifdef CONFIG_ATM_HORIZON_DEBUG
#define DEBUG_HORIZON
#endif
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 3d305858a..31503ed1e 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -157,36 +157,54 @@ static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ int diag;
+
+ diag = GET(DIAG) & ~IDT77105_DIAG_LCMASK;
+ switch (mode) {
+ case ATM_LM_NONE:
+ break;
+ case ATM_LM_LOC_ATM:
+ diag |= IDT77105_DIAG_LC_PHY_LOOPBACK;
+ break;
+ case ATM_LM_RMT_ATM:
+ diag |= IDT77105_DIAG_LC_LINE_LOOPBACK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(diag,DIAG);
+ printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", dev->type,
+ dev->number,
+ (mode == ATM_LM_NONE ? "NONE" :
+ (mode == ATM_LM_LOC_ATM ? "DIAG (local)" :
+ (mode == IDT77105_DIAG_LC_LINE_LOOPBACK ? "LOOP (remote)" :
+ "unknown")))
+ );
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number);
switch (cmd) {
case IDT77105_GETSTATZ:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ /* fall through */
case IDT77105_GETSTAT:
return fetch_stats(dev,(struct idt77105_stats *) arg,
cmd == IDT77105_GETSTATZ);
- case IDT77105_SETLOOP:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if ((int) arg < 0 || (int) arg > IDT77105_LM_LOOP)
- return -EINVAL;
- PUT((GET(DIAG) & ~IDT77105_DIAG_LCMASK) |
- ((int) arg == IDT77105_LM_NONE ? IDT77105_DIAG_LC_NORMAL : 0) |
- ((int) arg == IDT77105_LM_DIAG ? IDT77105_DIAG_LC_PHY_LOOPBACK : 0) |
- ((int) arg == IDT77105_LM_LOOP ? IDT77105_DIAG_LC_LINE_LOOPBACK : 0),
- DIAG);
- printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n",
- dev->type, dev->number,
- ((int) arg == IDT77105_LM_NONE ? "NONE" :
- ((int) arg == IDT77105_LM_DIAG ? "DIAG (local)" :
- ((int) arg == IDT77105_LM_LOOP ? "LOOP (remote)" :
- "unknown")))
- );
- PRIV(dev)->loop_mode = (int) arg;
- return 0;
- case IDT77105_GETLOOP:
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
- -EFAULT : sizeof(int);
+ -EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_ATM | ATM_LM_RMT_ATM,
+ (int *) arg) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
@@ -266,13 +284,13 @@ static int idt77105_start(struct atm_dev *dev)
/* initialise loop mode from hardware */
switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) {
case IDT77105_DIAG_LC_NORMAL:
- PRIV(dev)->loop_mode = IDT77105_LM_NONE;
+ PRIV(dev)->loop_mode = ATM_LM_NONE;
break;
case IDT77105_DIAG_LC_PHY_LOOPBACK:
- PRIV(dev)->loop_mode = IDT77105_LM_DIAG;
+ PRIV(dev)->loop_mode = ATM_LM_LOC_ATM;
break;
case IDT77105_DIAG_LC_LINE_LOOPBACK:
- PRIV(dev)->loop_mode = IDT77105_LM_LOOP;
+ PRIV(dev)->loop_mode = ATM_LM_RMT_ATM;
break;
}
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 84bdda6d6..cd1714a53 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -59,6 +59,7 @@
#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -68,7 +69,7 @@
#include "suni.h"
#define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
struct suni_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
+ struct k_sonet_stats sonet_stats; /* link diagnostics */
unsigned char loop_mode; /* loopback mode */
struct atm_dev *dev; /* device back-pointer */
struct suni_priv *next; /* next SUNI */
@@ -625,12 +626,12 @@ static int ia_que_tx (IADEV *iadev) {
num_desc = ia_avail_descs(iadev);
while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) {
if (!(vcc = ATM_SKB(skb)->vcc)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
printk("ia_que_tx: Null vcc\n");
break;
}
- if ((vcc->flags & ATM_VF_READY) == 0 ) {
- dev_kfree_skb(skb);
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) {
+ dev_kfree_skb_any(skb);
printk("Free the SKB on closed vci %d \n", vcc->vci);
break;
}
@@ -658,14 +659,14 @@ void ia_tx_poll (IADEV *iadev) {
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("ia_tx_poll: vcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
iavcc = INPH_IA_VCC(vcc);
if (!iavcc) {
printk("ia_tx_poll: iavcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
@@ -682,7 +683,7 @@ void ia_tx_poll (IADEV *iadev) {
(long)skb1);)
}
else
- dev_kfree_skb(skb1);
+ dev_kfree_skb_any(skb1);
skb1 = skb_dequeue(&iavcc->txing_skb);
}
if (!skb1) {
@@ -696,7 +697,7 @@ void ia_tx_poll (IADEV *iadev) {
IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);)
}
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
kfree(rtne);
}
ia_que_tx(iadev);
@@ -1128,7 +1129,7 @@ static int rx_pkt(struct atm_dev *dev)
status = (u_short) (buf_desc_ptr->desc_mode);
if (status & (RX_CER | RX_PTE | RX_OFL))
{
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
IF_ERR(printk("IA: bad packet, dropping it");)
if (status & RX_CER) {
IF_ERR(printk(" cause: packet CRC error\n");)
@@ -1152,7 +1153,7 @@ static int rx_pkt(struct atm_dev *dev)
len = dma_addr - buf_addr;
if (len > iadev->rx_buf_sz) {
printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
free_desc(dev, desc);
return 0;
}
@@ -1166,7 +1167,7 @@ static int rx_pkt(struct atm_dev *dev)
if (!skb)
{
IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");)
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
atm_return(vcc, atm_pdu2truesize(len));
free_desc(dev, desc);
return 0;
@@ -1297,7 +1298,7 @@ static void rx_dle_intr(struct atm_dev *dev)
if (!skb->len)
{
printk("rx_dle_intr: skb len 0\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
else
{
@@ -1308,15 +1309,15 @@ static void rx_dle_intr(struct atm_dev *dev)
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("IA: null vcc\n");
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
goto INCR_DLE;
}
ia_vcc = INPH_IA_VCC(vcc);
if (ia_vcc == NULL)
{
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
#if LINUX_VERSION_CODE >= 0x20312
atm_return(vcc, atm_guess_pdu2truesize(skb->len));
#else
@@ -1331,8 +1332,8 @@ static void rx_dle_intr(struct atm_dev *dev)
if ((length > iadev->rx_buf_sz) || (length >
(skb->len - sizeof(struct cpcs_trailer))))
{
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)",
length, skb->len);)
#if LINUX_VERSION_CODE >= 0x20312
@@ -1351,7 +1352,7 @@ static void rx_dle_intr(struct atm_dev *dev)
IF_RX(printk("rx_dle_intr: skb push");)
vcc->push(vcc,skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
iadev->rx_pkt_cnt++;
}
INCR_DLE:
@@ -1710,13 +1711,13 @@ static void tx_dle_intr(struct atm_dev *dev)
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("tx_dle_intr: vcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
iavcc = INPH_IA_VCC(vcc);
if (!iavcc) {
printk("tx_dle_intr: iavcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
if (vcc->qos.txtp.pcr >= iadev->rate_limit) {
@@ -1725,7 +1726,7 @@ static void tx_dle_intr(struct atm_dev *dev)
vcc->pop(vcc, skb);
}
else {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
else { /* Hold the rate-limited skb for flow control */
@@ -2601,7 +2602,7 @@ static void ia_close(struct atm_vcc *vcc)
IF_EVENT(printk("ia_close: ia_vcc->vc_desc_cnt = %d vci = %d\n",
ia_vcc->vc_desc_cnt,vcc->vci);)
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
skb_queue_head_init (&tmp_tx_backlog);
skb_queue_head_init (&tmp_vcc_backlog);
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
@@ -2611,7 +2612,7 @@ static void ia_close(struct atm_vcc *vcc)
while((skb = skb_dequeue(&iadev->tx_backlog))) {
if (ATM_SKB(skb)->vcc == vcc){
if (vcc->pop) vcc->pop(vcc, skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
}
else
skb_queue_tail(&tmp_tx_backlog, skb);
@@ -2669,7 +2670,7 @@ static void ia_close(struct atm_vcc *vcc)
kfree(INPH_IA_VCC(vcc));
ia_vcc = NULL;
INPH_IA_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return;
}
@@ -2678,7 +2679,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
IADEV *iadev;
struct ia_vcc *ia_vcc;
int error;
- if (!(vcc->flags & ATM_VF_PARTIAL))
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
{
IF_EVENT(printk("ia: not partially allocated resources\n");)
INPH_IA_VCC(vcc) = NULL;
@@ -2695,7 +2696,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
{
IF_EVENT(printk("iphase open: unspec part\n");)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
}
if (vcc->qos.aal != ATM_AAL5)
return -EINVAL;
@@ -2721,7 +2722,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
#ifndef MODULE
{
@@ -2749,7 +2750,7 @@ static int ia_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags)
static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
{
- PIA_CMDBUF ia_cmds;
+ IA_CMDBUF ia_cmds;
IADEV *iadev;
int i, board;
u16 *tmps;
@@ -2757,34 +2758,37 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
if (cmd != IA_CMD) {
if (!dev->phy->ioctl) return -EINVAL;
return dev->phy->ioctl(dev,cmd,arg);
- }
- ia_cmds = (PIA_CMDBUF)arg;
- board = ia_cmds->status;
+ }
+ if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT;
+ board = ia_cmds.status;
if ((board < 0) || (board > iadev_count))
board = 0;
iadev = ia_dev[board];
- switch (ia_cmds->cmd) {
+ switch (ia_cmds.cmd) {
case MEMDUMP:
{
- switch (ia_cmds->sub_cmd) {
+ switch (ia_cmds.sub_cmd) {
case MEMDUMP_DEV:
- memcpy((char*)ia_cmds->buf, (char*)iadev,
- sizeof(IADEV));
- ia_cmds->status = 0;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (copy_to_user(ia_cmds.buf, iadev, sizeof(IADEV)))
+ return -EFAULT;
+ ia_cmds.status = 0;
break;
case MEMDUMP_SEGREG:
- tmps = (u16 *)ia_cmds->buf;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ tmps = (u16 *)ia_cmds.buf;
for(i=0; i<0x80; i+=2, tmps++)
- *tmps = *(u16*)(iadev->seg_reg+i);
- ia_cmds->status = 0;
- ia_cmds->len = 0x80;
+ if(put_user(*(u16*)(iadev->seg_reg+i), tmps)) return -EFAULT;
+ ia_cmds.status = 0;
+ ia_cmds.len = 0x80;
break;
case MEMDUMP_REASSREG:
- tmps = (u16 *)ia_cmds->buf;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ tmps = (u16 *)ia_cmds.buf;
for(i=0; i<0x80; i+=2, tmps++)
- *tmps = *(u16*)(iadev->reass_reg+i);
- ia_cmds->status = 0;
- ia_cmds->len = 0x80;
+ if(put_user(*(u16*)(iadev->reass_reg+i), tmps)) return -EFAULT;
+ ia_cmds.status = 0;
+ ia_cmds.len = 0x80;
break;
case MEMDUMP_FFL:
{
@@ -2792,6 +2796,7 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
ffredn_t *ffL = &regs_local.ffredn;
rfredn_t *rfL = &regs_local.rfredn;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
/* Copy real rfred registers into the local copy */
for (i=0; i<(sizeof (rfredn_t))/4; i++)
((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff;
@@ -2799,63 +2804,67 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
for (i=0; i<(sizeof (ffredn_t))/4; i++)
((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff;
- memcpy((char*)ia_cmds->buf,(char*)&regs_local,sizeof(ia_regs_t));
+ if (copy_to_user(ia_cmds.buf, &regs_local,sizeof(ia_regs_t)))
+ return -EFAULT;
printk("Board %d registers dumped\n", board);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
}
break;
case READ_REG:
{
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
desc_dbg(iadev);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
}
break;
case 0x6:
{
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
printk("skb = 0x%lx\n", (long)skb_peek(&iadev->tx_backlog));
printk("rtn_q: 0x%lx\n",(long)ia_deque_rtn_q(&iadev->tx_return_q));
}
break;
case 0x8:
{
- struct sonet_stats *stats;
+ struct k_sonet_stats *stats;
stats = &PRIV(_ia_dev[board])->sonet_stats;
- printk("section_bip: %d\n", stats->section_bip);
- printk("line_bip : %d\n", stats->line_bip);
- printk("path_bip : %d\n", stats->path_bip);
- printk("line_febe : %d\n", stats->line_febe);
- printk("path_febe : %d\n", stats->path_febe);
- printk("corr_hcs : %d\n", stats->corr_hcs);
- printk("uncorr_hcs : %d\n", stats->uncorr_hcs);
- printk("tx_cells : %d\n", stats->tx_cells);
- printk("rx_cells : %d\n", stats->rx_cells);
+ printk("section_bip: %d\n", atomic_read(&stats->section_bip));
+ printk("line_bip : %d\n", atomic_read(&stats->line_bip));
+ printk("path_bip : %d\n", atomic_read(&stats->path_bip));
+ printk("line_febe : %d\n", atomic_read(&stats->line_febe));
+ printk("path_febe : %d\n", atomic_read(&stats->path_febe));
+ printk("corr_hcs : %d\n", atomic_read(&stats->corr_hcs));
+ printk("uncorr_hcs : %d\n", atomic_read(&stats->uncorr_hcs));
+ printk("tx_cells : %d\n", atomic_read(&stats->tx_cells));
+ printk("rx_cells : %d\n", atomic_read(&stats->rx_cells));
}
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
case 0x9:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
for (i = 1; i <= iadev->num_rx_desc; i++)
free_desc(_ia_dev[board], i);
writew( ~(RX_FREEQ_EMPT | RX_EXCP_RCVD),
iadev->reass_reg+REASS_MASK_REG);
iadev->rxing = 1;
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
case 0xb:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
IaFrontEndIntr(iadev);
break;
case 0xa:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
{
- ia_cmds->status = 0;
- IADebugFlag = ia_cmds->maddr;
+ ia_cmds.status = 0;
+ IADebugFlag = ia_cmds.maddr;
printk("New debug option loaded\n");
}
break;
default:
- memcpy((char*)ia_cmds->buf, (char*)ia_cmds->maddr, ia_cmds->len);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
}
}
@@ -2896,7 +2905,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (!iavcc->txing) {
printk("discard packet on closed VC\n");
if (vcc->pop) vcc->pop(vcc, skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
}
if (skb->len > iadev->tx_buf_sz - 8) {
@@ -2904,7 +2913,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
if ((u32)skb->data & 3) {
@@ -2912,7 +2921,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
/* Get a descriptor number from our free descriptor queue
@@ -2929,11 +2938,11 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if ((desc == 0) || (desc > iadev->num_tx_desc))
{
IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);)
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0; /* return SUCCESS */
}
@@ -3038,14 +3047,14 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
ATM_DESC(skb) = vcc->vci;
skb_queue_tail(&iadev->tx_dma_q, skb);
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
iadev->tx_pkt_cnt++;
/* Increment transaction counter */
writel(2, iadev->dma+IPHASE5575_TX_COUNTER);
#if 0
/* add flow control logic */
- if (vcc->stats->tx % 20 == 0) {
+ if (atomic_read(&vcc->stats->tx) % 20 == 0) {
if (iavcc->vc_desc_cnt > 10) {
vcc->tx_quota = vcc->tx_quota * 3 / 4;
printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota );
@@ -3074,12 +3083,12 @@ static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
if (!skb)
printk(KERN_CRIT "null skb in ia_send\n");
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
return -EINVAL;
}
spin_lock_irqsave(&iadev->tx_lock, flags);
- if ((vcc->flags & ATM_VF_READY) == 0){
- dev_kfree_skb(skb);
+ if (!test_bit(ATM_VF_READY,&vcc->flags)){
+ dev_kfree_skb_any(skb);
spin_unlock_irqrestore(&iadev->tx_lock, flags);
return -EINVAL;
}
@@ -3197,7 +3206,7 @@ __initfunc(int ia_detect(void))
IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn),
PCI_FUNC(iadev->pci->devfn));)
- dev = atm_dev_register(DEV_LABEL, &ops, -1, 0);
+ dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
if (!dev) break;
IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n",
dev->number);)
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 3e4930fdd..767fd75fb 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -37,8 +37,10 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "nicstar.h"
#include "nicstarmac.h"
#ifdef CONFIG_ATM_NICSTAR_USE_SUNI
@@ -284,7 +286,7 @@ void cleanup_module(void)
card = cards[i];
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == IDT_25_PCR) {
+ if (card->max_pcr == ATM_25_PCR) {
idt77105_stop(card->atmdev);
}
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
@@ -311,7 +313,7 @@ void cleanup_module(void)
PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
{
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
j++;
}
PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
@@ -319,14 +321,14 @@ void cleanup_module(void)
PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);
while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
{
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
j++;
}
PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- kfree_skb(lb);
+ dev_kfree_skb_any(lb);
while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- kfree_skb(sb);
+ dev_kfree_skb_any(sb);
free_scq(card->scq0, NULL);
for (j = 0; j < NS_FRSCD_NUM; j++)
{
@@ -547,7 +549,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
switch(data) {
case 0x00000009:
printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
- card->max_pcr = IDT_25_PCR;
+ card->max_pcr = ATM_25_PCR;
while(CMD_BUSY(card));
writel(0x00000008, card->membase + DR0);
writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
@@ -857,7 +859,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
card->efbie = 1;
/* Register device */
- card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL);
+ card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
if (card->atmdev == NULL)
{
printk("nicstar%d: can't register device.\n", i);
@@ -891,7 +893,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == IDT_25_PCR) {
+ if (card->max_pcr == ATM_25_PCR) {
idt77105_init(card->atmdev);
/* Note that for the IDT77105 PHY we don't need the awful
* module count hack that the SUNI needs because we can
@@ -936,26 +938,26 @@ static void ns_init_card_error(ns_dev *card, int error)
{
struct sk_buff *iovb;
while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
if (error >= 15)
{
struct sk_buff *sb;
while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- kfree_skb(sb);
+ dev_kfree_skb_any(sb);
free_scq(card->scq0, NULL);
}
if (error >= 14)
{
struct sk_buff *lb;
while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- kfree_skb(lb);
+ dev_kfree_skb_any(lb);
}
if (error >= 13)
{
struct sk_buff *hb;
while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
if (error >= 12)
{
@@ -1039,7 +1041,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
if (vcc->pop != NULL)
vcc->pop(vcc, scq->skb[i]);
else
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
}
else /* vcc must be != NULL */
@@ -1048,7 +1050,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
{
printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
for (i = 0; i < scq->num_entries; i++)
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
else
for (i = 0; i < scq->num_entries; i++)
@@ -1058,7 +1060,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
if (vcc->pop != NULL)
vcc->pop(vcc, scq->skb[i]);
else
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
}
}
@@ -1130,9 +1132,9 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
if (card->sbfqc >= card->sbnr.max)
{
skb_unlink((struct sk_buff *) handle1);
- kfree_skb((struct sk_buff *) handle1);
+ dev_kfree_skb_any((struct sk_buff *) handle1);
skb_unlink((struct sk_buff *) handle2);
- kfree_skb((struct sk_buff *) handle2);
+ dev_kfree_skb_any((struct sk_buff *) handle2);
return;
}
else
@@ -1143,9 +1145,9 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
if (card->lbfqc >= card->lbnr.max)
{
skb_unlink((struct sk_buff *) handle1);
- kfree_skb((struct sk_buff *) handle1);
+ dev_kfree_skb_any((struct sk_buff *) handle1);
skb_unlink((struct sk_buff *) handle2);
- kfree_skb((struct sk_buff *) handle2);
+ dev_kfree_skb_any((struct sk_buff *) handle2);
return;
}
else
@@ -1420,16 +1422,16 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
return -EINVAL;
}
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
/* NOTE: You are not allowed to modify an open connection's QOS. To change
that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
needed to do that. */
- if (!(vcc->flags & ATM_VF_PARTIAL))
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
{
scq_info *scq;
- vcc->flags |= ATM_VF_PARTIAL;
+ set_bit(ATM_VF_PARTIAL,&vcc->flags);
if (vcc->qos.txtp.traffic_class == ATM_CBR)
{
/* Check requested cell rate and availability of SCD */
@@ -1438,7 +1440,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
{
PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
@@ -1461,7 +1464,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
{
PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
}
@@ -1469,14 +1473,16 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
if (n == 0)
{
printk("nicstar%d: selected bandwidth < granularity.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
if (n > (card->tst_free_entries - NS_TST_RESERVED))
{
PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
else
@@ -1495,7 +1501,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
{
PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index);
card->tst_free_entries += n;
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EBUSY;
}
@@ -1507,7 +1514,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
card->scd2vc[frscdi] = NULL;
card->tst_free_entries += n;
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -ENOMEM;
}
vc->scq = scq;
@@ -1553,7 +1561,7 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
MOD_INC_USE_COUNT;
return 0;
}
@@ -1572,7 +1580,7 @@ static void ns_close(struct atm_vcc *vcc)
PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
(int) vcc->vpi, vcc->vci);
- vcc->flags &= ~(ATM_VF_READY);
+ clear_bit(ATM_VF_READY,&vcc->flags);
if (vcc->qos.rxtp.traffic_class != ATM_NONE)
{
@@ -1681,7 +1689,8 @@ static void ns_close(struct atm_vcc *vcc)
}
vcc->dev_data = NULL;
- vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
MOD_DEC_USE_COUNT;
#ifdef RX_DEBUG
@@ -1778,32 +1787,32 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
if ((vc = (vc_map *) vcc->dev_data) == NULL)
{
printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (!vc->tx)
{
printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
{
printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (ATM_SKB(skb)->iovcnt != 0)
{
printk("nicstar%d: No scatter-gather yet.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
@@ -1847,11 +1856,11 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (push_scqe(card, vc, scq, &scqe, skb) != 0)
{
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EIO;
}
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
return 0;
}
@@ -2071,7 +2080,7 @@ static void drain_scq(ns_dev *card, scq_info *scq, int pos)
if (vcc->pop != NULL)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
scq->skb[i] = NULL;
}
if (++i == scq->num_entries)
@@ -2155,15 +2164,15 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
{
printk("nicstar%d: Can't allocate buffers for aal0.\n",
card->index);
- vcc->stats->rx_drop += i;
+ atomic_add(i,&vcc->stats->rx_drop);
break;
}
if (!atm_charge(vcc, sb->truesize))
{
RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",
card->index);
- vcc->stats->rx_drop += i - 1; /* already increased by 1 */
- kfree_skb(sb);
+ atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */
+ dev_kfree_skb_any(sb);
break;
}
/* Rebuild the header */
@@ -2177,7 +2186,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
cell += ATM_CELL_PAYLOAD;
}
@@ -2196,7 +2205,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
if (iovb == NULL)
{
printk("nicstar%d: Out of iovec buffers.\n", card->index);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
recycle_rx_buf(card, skb);
return;
}
@@ -2223,7 +2232,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
{
printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
ATM_SKB(iovb)->iovcnt = 0;
iovb->len = 0;
@@ -2242,7 +2251,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk("nicstar%d: Expected a small buffer, and this is not one.\n",
card->index);
which_list(card, skb);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_rx_buf(card, skb);
vc->rx_iov = NULL;
recycle_iov_buf(card, iovb);
@@ -2256,7 +2265,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk("nicstar%d: Expected a large buffer, and this is not one.\n",
card->index);
which_list(card, skb);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2280,7 +2289,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk(" - PDU size mismatch.\n");
else
printk(".\n");
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2308,7 +2317,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
}
else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */
@@ -2335,7 +2344,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
push_rxbufs(card, BUF_LG, (u32) skb,
@@ -2361,7 +2370,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
@@ -2384,7 +2393,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
if (hb == NULL)
{
printk("nicstar%d: Out of huge buffers.\n", card->index);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2431,7 +2440,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
card->hbpool.count++;
}
else
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
else
{
@@ -2467,7 +2476,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
#endif /* NS_USE_DESTRUCTORS */
hb->stamp = xtime;
vcc->push(vcc, hb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
}
@@ -2556,7 +2565,7 @@ static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
@@ -2578,7 +2587,7 @@ static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
}
@@ -2593,7 +2602,7 @@ static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
card->iovpool.count++;
}
else
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
@@ -2700,7 +2709,7 @@ static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
/* Dump 25.6 Mbps PHY registers */
/* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
here just in case it's needed for debugging. */
- if (card->max_pcr == IDT_25_PCR && !left--)
+ if (card->max_pcr == ATM_25_PCR && !left--)
{
u32 phy_regs[4];
u32 i;
@@ -2787,7 +2796,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
return -EFAULT;
case NS_SETBUFLEV:
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl)))
return -EFAULT;
@@ -2836,7 +2845,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
return 0;
case NS_ADJBUFLEV:
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
btype = (int) arg; /* an int is the same size as a pointer */
switch (btype)
@@ -2882,7 +2891,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
printk("nicstar%d: huge buffer count inconsistent.\n",
card->index);
else
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
while (card->hbpool.count < card->hbnr.init)
@@ -2912,7 +2921,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
printk("nicstar%d: iovec buffer count inconsistent.\n",
card->index);
else
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
while (card->iovpool.count < card->iovnr.init)
diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
index 61b89efe0..4e90650c0 100644
--- a/drivers/atm/nicstar.h
+++ b/drivers/atm/nicstar.h
@@ -100,8 +100,6 @@
#define NS_IOREMAP_SIZE 4096
-#define IDT_25_PCR ((25600000 / 8 - 8000) / 54)
-
#define BUF_SM 0x00000000 /* These two are used for push_rxbufs() */
#define BUF_LG 0x00000001 /* CMD, Write_FreeBufQ, LBUF bit */
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index 7335bbb32..0de6e8ead 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -1,4 +1,4 @@
-/* drivers/atm/suni.c - PMC SUNI (PHY) driver */
+/* drivers/atm/suni.c - PMC PM5346 SUNI (PHY) driver */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
@@ -18,6 +18,7 @@
#include <asm/system.h>
#include <asm/param.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "suni.h"
@@ -30,8 +31,8 @@
struct suni_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
- unsigned char loop_mode; /* loopback mode */
+ struct k_sonet_stats sonet_stats; /* link diagnostics */
+ int loop_mode; /* loopback mode */
struct atm_dev *dev; /* device back-pointer */
struct suni_priv *next; /* next SUNI */
};
@@ -46,69 +47,62 @@ struct suni_priv {
static struct timer_list poll_timer;
-static int start_timer = 1;
static struct suni_priv *sunis = NULL;
+static spinlock_t sunis_lock = SPIN_LOCK_UNLOCKED;
-static void suni_hz(unsigned long dummy)
+#define ADD_LIMITED(s,v) \
+ atomic_add((v),&stats->s); \
+ if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX);
+
+
+static void suni_hz(unsigned long from_timer)
{
struct suni_priv *walk;
struct atm_dev *dev;
- struct sonet_stats *stats;
+ struct k_sonet_stats *stats;
for (walk = sunis; walk; walk = walk->next) {
dev = walk->dev;
stats = &walk->sonet_stats;
PUT(0,MRI); /* latch counters */
udelay(1);
- stats->section_bip += (GET(RSOP_SBL) & 0xff) |
- ((GET(RSOP_SBM) & 0xff) << 8);
- if (stats->section_bip < 0) stats->section_bip = LONG_MAX;
- stats->line_bip += (GET(RLOP_LBL) & 0xff) |
+ ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) |
+ ((GET(RSOP_SBM) & 0xff) << 8));
+ ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) |
((GET(RLOP_LB) & 0xff) << 8) |
- ((GET(RLOP_LBM) & 0xf) << 16);
- if (stats->line_bip < 0) stats->line_bip = LONG_MAX;
- stats->path_bip += (GET(RPOP_PBL) & 0xff) |
- ((GET(RPOP_PBM) & 0xff) << 8);
- if (stats->path_bip < 0) stats->path_bip = LONG_MAX;
- stats->line_febe += (GET(RLOP_LFL) & 0xff) |
+ ((GET(RLOP_LBM) & 0xf) << 16));
+ ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) |
+ ((GET(RPOP_PBM) & 0xff) << 8));
+ ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) |
((GET(RLOP_LF) & 0xff) << 8) |
- ((GET(RLOP_LFM) & 0xf) << 16);
- if (stats->line_febe < 0) stats->line_febe = LONG_MAX;
- stats->path_febe += (GET(RPOP_PFL) & 0xff) |
- ((GET(RPOP_PFM) & 0xff) << 8);
- if (stats->path_febe < 0) stats->path_febe = LONG_MAX;
- stats->corr_hcs += GET(RACP_CHEC) & 0xff;
- if (stats->corr_hcs < 0) stats->corr_hcs = LONG_MAX;
- stats->uncorr_hcs += GET(RACP_UHEC) & 0xff;
- if (stats->uncorr_hcs < 0) stats->uncorr_hcs = LONG_MAX;
- stats->rx_cells += (GET(RACP_RCCL) & 0xff) |
+ ((GET(RLOP_LFM) & 0xf) << 16));
+ ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) |
+ ((GET(RPOP_PFM) & 0xff) << 8));
+ ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff);
+ ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff);
+ ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) |
((GET(RACP_RCC) & 0xff) << 8) |
- ((GET(RACP_RCCM) & 7) << 16);
- if (stats->rx_cells < 0) stats->rx_cells = LONG_MAX;
- stats->tx_cells += (GET(TACP_TCCL) & 0xff) |
+ ((GET(RACP_RCCM) & 7) << 16));
+ ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) |
((GET(TACP_TCC) & 0xff) << 8) |
- ((GET(TACP_TCCM) & 7) << 16);
- if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX;
+ ((GET(TACP_TCCM) & 7) << 16));
}
- if (!start_timer) mod_timer(&poll_timer,jiffies+HZ);
+ if (from_timer) mod_timer(&poll_timer,jiffies+HZ);
}
+#undef ADD_LIMITED
+
+
static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
{
- unsigned long flags;
- int error;
-
- error = 0;
- save_flags(flags);
- cli();
- if (arg)
- error = copy_to_user(arg,&PRIV(dev)->sonet_stats,
- sizeof(struct sonet_stats));
- if (zero && !error)
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
- restore_flags(flags);
+ struct sonet_stats tmp;
+ int error = 0;
+
+ sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
+ if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
return error ? -EFAULT : 0;
}
@@ -158,6 +152,29 @@ static int get_diag(struct atm_dev *dev,void *arg)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ unsigned char control;
+
+ control = GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE);
+ switch (mode) {
+ case ATM_LM_NONE:
+ break;
+ case ATM_LM_LOC_PHY:
+ control |= SUNI_MCT_DLE;
+ break;
+ case ATM_LM_RMT_PHY:
+ control |= SUNI_MCT_LLE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(control,MCT);
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
+
static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
switch (cmd) {
@@ -172,7 +189,6 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
case SONET_GETDIAG:
return get_diag(dev,arg);
case SONET_SETFRAMING:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
if (arg != SONET_FRAME_SONET) return -EINVAL;
return 0;
case SONET_GETFRAMING:
@@ -180,23 +196,14 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
-EFAULT : 0;
case SONET_GETFRSENSE:
return -EINVAL;
- case SUNI_SETLOOP:
- {
- int int_arg = (int) (long) arg;
-
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (int_arg < 0 || int_arg > SUNI_LM_LOOP)
- return -EINVAL;
- PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE))
- | (int_arg == SUNI_LM_DIAG ? SUNI_MCT_DLE :
- 0) | (int_arg == SUNI_LM_LOOP ?
- SUNI_MCT_LLE : 0),MCT);
- PRIV(dev)->loop_mode = int_arg;
- return 0;
- }
- case SUNI_GETLOOP:
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
-EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY,
+ (int *) arg) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
@@ -221,33 +228,31 @@ static void suni_int(struct atm_dev *dev)
static int suni_start(struct atm_dev *dev)
{
unsigned long flags;
+ int first;
if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
return -ENOMEM;
PRIV(dev)->dev = dev;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&sunis_lock,flags);
+ first = !sunis;
PRIV(dev)->next = sunis;
sunis = PRIV(dev);
- restore_flags(flags);
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
+ spin_unlock_irqrestore(&sunis_lock,flags);
+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE);
/* interrupt on loss of signal */
poll_los(dev); /* ... and clear SUNI interrupts */
if (dev->signal == ATM_PHY_SIG_LOST)
printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
dev->number);
- PRIV(dev)->loop_mode = SUNI_LM_NONE;
+ PRIV(dev)->loop_mode = ATM_LM_NONE;
suni_hz(0); /* clear SUNI counters */
(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
- cli();
- if (!start_timer) restore_flags(flags);
- else {
- start_timer = 0;
- restore_flags(flags);
+ if (first) {
init_timer(&poll_timer);
poll_timer.expires = jiffies+HZ;
poll_timer.function = suni_hz;
+ poll_timer.data = 1;
#if 0
printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
(unsigned long) poll_timer.next);
@@ -258,10 +263,28 @@ printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
}
+static int suni_stop(struct atm_dev *dev)
+{
+ struct suni_priv **walk;
+ unsigned long flags;
+
+ /* let SAR driver worry about stopping interrupts */
+ spin_lock_irqsave(&sunis_lock,flags);
+ for (walk = &sunis; *walk != PRIV(dev);
+ walk = &PRIV((*walk)->dev)->next);
+ *walk = PRIV((*walk)->dev)->next;
+ if (!sunis) del_timer_sync(&poll_timer);
+ spin_unlock_irqrestore(&sunis_lock,flags);
+ kfree(PRIV(dev));
+ return 0;
+}
+
+
static const struct atmphy_ops suni_ops = {
- suni_start,
- suni_ioctl,
- suni_int
+ start: suni_start,
+ ioctl: suni_ioctl,
+ interrupt: suni_int,
+ stop: suni_stop,
};
diff --git a/drivers/atm/suni.h b/drivers/atm/suni.h
index f72cdc7be..ae6d39abb 100644
--- a/drivers/atm/suni.h
+++ b/drivers/atm/suni.h
@@ -1,6 +1,6 @@
-/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */
+/* drivers/atm/suni.h - PMC PM5346 SUNI (PHY) declarations */
-/* Written 1995,1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef DRIVER_ATM_SUNI_H
diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c
index 36fd70b17..7c5f57579 100644
--- a/drivers/atm/uPD98402.c
+++ b/drivers/atm/uPD98402.c
@@ -11,6 +11,7 @@
#include <linux/sonet.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "uPD98402.h"
@@ -23,8 +24,9 @@
struct uPD98402_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
+ struct k_sonet_stats sonet_stats;/* link diagnostics */
unsigned char framing; /* SONET/SDH framing */
+ int loop_mode; /* loopback mode */
};
@@ -36,23 +38,18 @@ struct uPD98402_priv {
static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
{
- unsigned long flags;
- int error;
+ struct sonet_stats tmp;
+ int error = 0;
- error = 0;
- save_flags(flags);
- cli();
- PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT);
- if (arg)
- error = copy_to_user(arg,&PRIV(dev)->sonet_stats,
- sizeof(struct sonet_stats));
+ atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs);
+ sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
if (zero && !error) {
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
- PRIV(dev)->sonet_stats.corr_hcs = -1;
- PRIV(dev)->sonet_stats.tx_cells = -1;
- PRIV(dev)->sonet_stats.rx_cells = -1;
+ /* unused fields are reported as -1, but we must not "adjust"
+ them */
+ tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0;
+ sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
}
- restore_flags(flags);
return error ? -EFAULT : 0;
}
@@ -102,6 +99,39 @@ static int get_sense(struct atm_dev *dev,u8 *arg)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ unsigned char mode_reg;
+
+ mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP |
+ uPD98402_MDR_RPLP);
+ switch (__ATM_LM_XTLOC(mode)) {
+ case __ATM_LM_NONE:
+ break;
+ case __ATM_LM_PHY:
+ mode_reg |= uPD98402_MDR_TPLP;
+ break;
+ case __ATM_LM_ATM:
+ mode_reg |= uPD98402_MDR_ALP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (__ATM_LM_XTRMT(mode)) {
+ case __ATM_LM_NONE:
+ break;
+ case __ATM_LM_PHY:
+ mode_reg |= uPD98402_MDR_RPLP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(mode_reg,MDR);
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
+
static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
switch (cmd) {
@@ -117,35 +147,42 @@ static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
-EFAULT : 0;
case SONET_GETFRSENSE:
return get_sense(dev,arg);
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
+ return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
+ -EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM |
+ ATM_LM_RMT_PHY,(int *) arg) ? -EFAULT : 0;
default:
- return -ENOIOCTLCMD;
+ return -ENOIOCTLCMD;
}
}
+#define ADD_LIMITED(s,v) \
+ { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \
+ if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \
+ atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); }
+
+
static void stat_event(struct atm_dev *dev)
{
unsigned char events;
events = GET(PCR);
- if (events & uPD98402_PFM_PFEB)
- if ((PRIV(dev)->sonet_stats.path_febe += GET(PFECB)) < 0)
- PRIV(dev)->sonet_stats.path_febe = LONG_MAX;
- if (events & uPD98402_PFM_LFEB)
- if ((PRIV(dev)->sonet_stats.line_febe += GET(LECCT)) < 0)
- PRIV(dev)->sonet_stats.line_febe = LONG_MAX;
- if (events & uPD98402_PFM_B3E)
- if ((PRIV(dev)->sonet_stats.path_bip += GET(B3ECT)) < 0)
- PRIV(dev)->sonet_stats.path_bip = LONG_MAX;
- if (events & uPD98402_PFM_B2E)
- if ((PRIV(dev)->sonet_stats.line_bip += GET(B2ECT)) < 0)
- PRIV(dev)->sonet_stats.line_bip = LONG_MAX;
- if (events & uPD98402_PFM_B1E)
- if ((PRIV(dev)->sonet_stats.section_bip += GET(B1ECT)) < 0)
- PRIV(dev)->sonet_stats.section_bip = LONG_MAX;
+ if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB);
+ if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT);
+ if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT);
+ if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT);
+ if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT);
}
+#undef ADD_LIMITED
+
+
static void uPD98402_int(struct atm_dev *dev)
{
static unsigned long silence = 0;
@@ -158,7 +195,8 @@ static void uPD98402_int(struct atm_dev *dev)
if (reason & uPD98402_INT_PFM) stat_event(dev);
if (reason & uPD98402_INT_PCO) {
(void) GET(PCOCR); /* clear interrupt cause */
- PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT);
+ atomic_add(GET(HECCT),
+ &PRIV(dev)->sonet_stats.uncorr_hcs);
}
if ((reason & uPD98402_INT_RFO) &&
(time_after(jiffies, silence) || silence == 0)) {
@@ -172,10 +210,10 @@ static void uPD98402_int(struct atm_dev *dev)
static int uPD98402_start(struct atm_dev *dev)
{
-DPRINTK("phy_start\n");
+ DPRINTK("phy_start\n");
if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
return -ENOMEM;
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
(void) GET(PCR); /* clear performance events */
PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */
(void) GET(PCOCR); /* clear overflows */
@@ -184,15 +222,26 @@ DPRINTK("phy_start\n");
PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO |
uPD98402_INT_LOS),PIMR); /* enable them */
(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
+ atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1);
+ atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1);
+ atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1);
return 0;
}
+static int uPD98402_stop(struct atm_dev *dev)
+{
+ /* let SAR driver worry about stopping interrupts */
+ kfree(PRIV(dev));
+ return 0;
+}
+
static const struct atmphy_ops uPD98402_ops = {
- uPD98402_start,
- uPD98402_ioctl, /* no ioctl yet */
- uPD98402_int
+ start: uPD98402_start,
+ ioctl: uPD98402_ioctl,
+ interrupt: uPD98402_int,
+ stop: uPD98402_stop,
};
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 26c8c9d90..1b68f5529 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -21,10 +21,12 @@
#include <linux/init.h>
#include <linux/atm_zatm.h>
#include <linux/capability.h>
+#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/string.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include "uPD98401.h"
@@ -637,7 +639,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
}
if (!size) {
dev_kfree_skb_irq(skb);
- if (vcc) vcc->stats->rx_err++;
+ if (vcc) atomic_inc(&vcc->stats->rx_err);
continue;
}
if (!atm_charge(vcc,skb->truesize)) {
@@ -647,7 +649,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
skb->len = size;
ATM_SKB(skb)->vcc = vcc;
vcc->push(vcc,skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
zout(pos & 0xffff,MTA(mbx));
#if 0 /* probably a stupid idea */
@@ -914,7 +916,7 @@ if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP |
skb_queue_head(&zatm_vcc->backlog,skb);
break;
}
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
wake_up(&zatm_vcc->tx_wait);
}
@@ -1537,7 +1539,7 @@ static void zatm_close(struct atm_vcc *vcc)
{
DPRINTK(">zatm_close\n");
if (!ZATM_VCC(vcc)) return;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
close_rx(vcc);
EVENT("close_tx\n",0,0);
close_tx(vcc);
@@ -1545,7 +1547,7 @@ static void zatm_close(struct atm_vcc *vcc)
/* deallocate memory */
kfree(ZATM_VCC(vcc));
ZATM_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
}
@@ -1557,20 +1559,20 @@ static int zatm_open(struct atm_vcc *vcc,short vpi,int vci)
DPRINTK(">zatm_open\n");
zatm_dev = ZATM_DEV(vcc->dev);
- if (!(vcc->flags & ATM_VF_PARTIAL)) ZATM_VCC(vcc) = NULL;
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL;
error = atm_find_ci(vcc,&vpi,&vci);
if (error) return error;
vcc->vpi = vpi;
vcc->vci = vci;
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */
DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi,
vcc->vci);
- if (!(vcc->flags & ATM_VF_PARTIAL)) {
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
zatm_vcc = kmalloc(sizeof(struct zatm_vcc),GFP_KERNEL);
if (!zatm_vcc) {
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -ENOMEM;
}
ZATM_VCC(vcc) = zatm_vcc;
@@ -1593,7 +1595,7 @@ static int zatm_open(struct atm_vcc *vcc,short vpi,int vci)
zatm_close(vcc);
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
return 0;
}
@@ -1733,7 +1735,7 @@ static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb)
int error;
EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0);
- if (!ZATM_VCC(vcc)->tx_chan || !(vcc->flags & ATM_VF_READY)) {
+ if (!ZATM_VCC(vcc)->tx_chan || !test_bit(ATM_VF_READY,&vcc->flags)) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
return -EINVAL;
@@ -1809,7 +1811,7 @@ int __init zatm_detect(void)
while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?
PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,
pci_dev))) {
- dev = atm_dev_register(DEV_LABEL,&ops,-1,0);
+ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
if (!dev) break;
zatm_dev->pci_dev = pci_dev;
ZATM_DEV(dev) = zatm_dev;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 3209aa46b..668cb5096 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -190,7 +190,7 @@ static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos,
page = grab_cache_page(mapping, index);
if (!page)
goto fail;
- if (aops->prepare_write(page, offset, offset+size))
+ if (aops->prepare_write(file, page, offset, offset+size))
goto unlock;
kaddr = (char*)page_address(page);
if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV))
diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c
index beb4f1364..0986ff7df 100644
--- a/drivers/block/lvm.c
+++ b/drivers/block/lvm.c
@@ -2527,6 +2527,15 @@ void __init
*
* Is this the real thing?
*
+ * No, it's bollocks. md.c tries to do a bit different thing that might
+ * _somewhat_ work eons ago. Neither does any good these days. mount() couldn't
+ * care less for icache (it cares only for ->s_root->d_count and if we want
+ * loopback mounts even that will stop). BTW, with the form used here mount()
+ * would have to scan the _whole_ icache to detect the attempt - how on the
+ * Earth could it guess the i_ino of your dummy inode? Official line on the
+ * exclusion between mount()/swapon()/open()/etc. is Just Don't Do It(tm).
+ * If you can convince Linus that it's worth changing - fine, then you'll need
+ * to do blkdev_get()/blkdev_put(). Until then...
*/
struct inode *lvm_get_inode(int dev)
{
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 171b3b659..dd8a83764 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -1098,7 +1098,7 @@ static int md_import_device (kdev_t newdev, int on_disk)
}
memset(rdev, 0, sizeof(*rdev));
- if (!fs_may_mount(newdev)) {
+ if (get_super(newdev)) {
printk("md: can not import %s, has active inodes!\n",
partition_name(newdev));
err = -EBUSY;
@@ -1722,7 +1722,7 @@ static int do_md_stop (mddev_t * mddev, int ro)
int err = 0, resync_interrupted = 0;
kdev_t dev = mddev_to_kdev(mddev);
- if (!ro && !fs_may_mount (dev)) {
+ if (!ro && get_super(dev)) {
printk (STILL_MOUNTED, mdidx(mddev));
OUT(-EBUSY);
}
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
index f05196389..9c4cabbbf 100644
--- a/drivers/block/paride/paride.c
+++ b/drivers/block/paride/paride.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/config.h>
+#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -336,6 +337,9 @@ int pi_init(PIA *pi, int autoprobe, int port, int mode,
s = protocol; e = s+1;
+ if (!protocols[0])
+ request_module ("paride_protocol");
+
if (autoprobe) {
s = 0;
e = MAX_PROTOS;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index 27ea344b9..8f8580cf5 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -1483,6 +1483,6 @@ __setup("cm206=", cm206_setup);
#endif /* !MODULE */
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -D__SMP__ -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c"
* End:
*/
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index 2a8da5960..9d86479dc 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -37,8 +37,10 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
+#include <linux/spinlock.h>
static int acq_is_open=0;
+static spinlock_t acq_lock;
/*
* You must set these - there is no sane way to probe for this board.
@@ -117,8 +119,12 @@ static int acq_open(struct inode *inode, struct file *file)
switch(MINOR(inode->i_rdev))
{
case WATCHDOG_MINOR:
+ spin_lock(&acq_lock);
if(acq_is_open)
+ {
+ spin_unlock(&acq_lock);
return -EBUSY;
+ }
MOD_INC_USE_COUNT;
/*
* Activate
@@ -126,6 +132,7 @@ static int acq_open(struct inode *inode, struct file *file)
acq_is_open=1;
inb_p(WDT_START);
+ spin_unlock(&acq_lock);
return 0;
default:
return -ENODEV;
@@ -136,10 +143,12 @@ static int acq_close(struct inode *inode, struct file *file)
{
if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
{
+ spin_lock(&acq_lock);
#ifndef CONFIG_WATCHDOG_NOWAYOUT
inb_p(WDT_STOP);
#endif
acq_is_open=0;
+ spin_unlock(&acq_lock);
}
MOD_DEC_USE_COUNT;
return 0;
@@ -211,6 +220,7 @@ int __init acq_init(void)
{
printk("WDT driver for Acquire single board computer initialising.\n");
+ spin_lock_init(&acq_lock);
misc_register(&acq_miscdev);
request_region(WDT_STOP, 1, "Acquire WDT");
request_region(WDT_START, 1, "Acquire WDT");
diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c
index 823ec88ea..0cdfc264a 100644
--- a/drivers/char/amigamouse.c
+++ b/drivers/char/amigamouse.c
@@ -162,6 +162,10 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
+ /* Lock module first - request_irq might sleep */
+
+ MOD_INC_USE_COUNT;
+
/*
* use VBL to poll mouse deltas
*/
@@ -169,10 +173,10 @@ static int open_mouse(struct inode * inode, struct file * file)
if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
"Amiga mouse", mouse_interrupt)) {
printk(KERN_INFO "Installing Amiga mouse failed.\n");
+ MOD_DEC_USE_COUNT;
return -EIO;
}
- MOD_INC_USE_COUNT;
#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
#endif
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 969a75331..7ede5fdc6 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -2259,6 +2259,6 @@ void cleanup_module(void)
/*
Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c amiserial.c"
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c amiserial.c"
End:
*/
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index f6304943a..65be2102f 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -14,7 +14,7 @@
/* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */
/* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */
/* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */
-/* adresses de base des cartes, IOCTL 6 plus complet */
+/* adresses de base des cartes, IOCTL 6 plus complet */
/* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */
/* de code autre que le texte V2.6.1 en V2.8.0 */
/*****************************************************************************/
@@ -37,108 +37,102 @@
#undef DEBUG
#define DEVPRIO PZERO+8
#define FALSE 0
-#define TRUE ~FALSE
-#define MAX_BOARD 8 /* maximum of pc board possible */
+#define TRUE ~FALSE
+#define MAX_BOARD 8 /* maximum of pc board possible */
#define MAX_ISA_BOARD 4
#define LEN_RAM_IO 0x800
#define AC_MINOR 157
#ifndef PCI_VENDOR_ID_APPLICOM
-#define PCI_VENDOR_ID_APPLICOM 0x1389
+#define PCI_VENDOR_ID_APPLICOM 0x1389
#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
#define MAX_PCI_DEVICE_NUM 3
#endif
-static char *applicom_pci_devnames[]={
- "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"};
+static char *applicom_pci_devnames[] = {
+ "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"
+};
MODULE_AUTHOR("David Woodhouse & Applicom International");
MODULE_DESCRIPTION("Driver for Applicom Profibus card");
MODULE_PARM(irq, "i");
MODULE_PARM_DESC(irq, "IRQ of the Applicom board");
-MODULE_PARM(mem,"i");
+MODULE_PARM(mem, "i");
MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board");
MODULE_SUPPORTED_DEVICE("ac");
struct applicom_board {
- unsigned long PhysIO;
- unsigned long RamIO;
+ unsigned long PhysIO;
+ unsigned long RamIO;
#if LINUX_VERSION_CODE > 0x20300
- wait_queue_head_t FlagSleepSend;
+ wait_queue_head_t FlagSleepSend;
#else
- struct wait_queue *FlagSleepSend;
+ struct wait_queue *FlagSleepSend;
#endif
- long irq;
+ long irq;
} apbs[MAX_BOARD];
-static unsigned int irq=0; /* interrupt number IRQ */
-static unsigned long mem=0; /* physical segment of board */
+static unsigned int irq = 0; /* interrupt number IRQ */
+static unsigned long mem = 0; /* physical segment of board */
-static unsigned int numboards; /* number of installed boards */
+static unsigned int numboards; /* number of installed boards */
static volatile unsigned char Dummy;
#if LINUX_VERSION_CODE > 0x20300
-static DECLARE_WAIT_QUEUE_HEAD (FlagSleepRec);
+static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec);
#else
static struct wait_queue *FlagSleepRec;
#endif
-static unsigned int WriteErrorCount; /* number of write error */
-static unsigned int ReadErrorCount; /* number of read error */
-static unsigned int DeviceErrorCount; /* number of device error */
+static unsigned int WriteErrorCount; /* number of write error */
+static unsigned int ReadErrorCount; /* number of read error */
+static unsigned int DeviceErrorCount; /* number of device error */
static loff_t ac_llseek(struct file *file, loff_t offset, int origin);
static int ac_open(struct inode *inode, struct file *filp);
-static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr);
-static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos);
+static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr);
+static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int ac_release(struct inode *inode, struct file *file);
static void ac_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-struct file_operations ac_fops={
- llseek: ac_llseek,
- read: ac_read,
- write: ac_write,
- ioctl: ac_ioctl,
- open: ac_open,
- release: ac_release,
+struct file_operations ac_fops = {
+ llseek:ac_llseek,
+ read:ac_read,
+ write:ac_write,
+ ioctl:ac_ioctl,
+ open:ac_open,
+ release:ac_release,
};
-struct miscdevice ac_miscdev={
- AC_MINOR,
- "ac",
- &ac_fops
+struct miscdevice ac_miscdev = {
+ AC_MINOR,
+ "ac",
+ &ac_fops
};
-int ac_register_board(unsigned long physloc, unsigned long loc,
- unsigned char boardno)
+int ac_register_board(unsigned long physloc, unsigned long loc, unsigned char boardno)
{
volatile unsigned char byte_reset_it;
- if((readb(loc + CONF_END_TEST) != 0x00) ||
- (readb(loc + CONF_END_TEST + 1) != 0x55) ||
- (readb(loc + CONF_END_TEST + 2) != 0xAA) ||
- (readb(loc + CONF_END_TEST + 3) != 0xFF))
- return 0;
+ if ((readb(loc + CONF_END_TEST) != 0x00) || (readb(loc + CONF_END_TEST + 1) != 0x55) || (readb(loc + CONF_END_TEST + 2) != 0xAA) || (readb(loc + CONF_END_TEST + 3) != 0xFF))
+ return 0;
if (!boardno)
- boardno = readb(loc + NUMCARD_OWNER_TO_PC);
+ boardno = readb(loc + NUMCARD_OWNER_TO_PC);
- if (!boardno && boardno > MAX_BOARD)
- {
- printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",boardno, physloc, MAX_BOARD);
- return 0;
- }
+ if (!boardno && boardno > MAX_BOARD) {
+ printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", boardno, physloc, MAX_BOARD);
+ return 0;
+ }
- if (apbs[boardno-1].RamIO)
- {
- printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n",
- boardno, physloc, boardno, apbs[boardno-1].PhysIO);
- return 0;
- }
+ if (apbs[boardno - 1].RamIO) {
+ printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", boardno, physloc, boardno, apbs[boardno - 1].PhysIO);
+ return 0;
+ }
boardno--;
@@ -152,7 +146,7 @@ int ac_register_board(unsigned long physloc, unsigned long loc,
byte_reset_it = readb(loc + RAM_IT_TO_PC);
numboards++;
- return boardno+1;
+ return boardno + 1;
}
#ifdef MODULE
@@ -164,22 +158,21 @@ void cleanup_module(void)
int i;
misc_deregister(&ac_miscdev);
- for (i=0; i< MAX_BOARD; i++)
- {
- if (!apbs[i].RamIO)
- continue;
- iounmap((void *)apbs[i].RamIO);
- if (apbs[i].irq)
- free_irq(apbs[i].irq,&ac_open);
- }
- // printk("Removing Applicom module\n");
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+ iounmap((void *) apbs[i].RamIO);
+ if (apbs[i].irq)
+ free_irq(apbs[i].irq, &ac_open);
+ }
+ // printk("Removing Applicom module\n");
}
-#endif /* MODULE */
+#endif /* MODULE */
int __init applicom_init(void)
{
- int i, numisa=0;
+ int i, numisa = 0;
struct pci_dev *dev = NULL;
void *RamIO;
int boardno;
@@ -190,157 +183,137 @@ int __init applicom_init(void)
#endif
printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $\n");
-
+
/* No mem and irq given - check for a PCI card */
-
- while ( (dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev)))
- {
- // mem = dev->base_address[0];
- // irq = dev->irq;
-
- RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
-
- if (!RamIO) {
- printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev));
- return -EIO;
- }
-
- printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n",
- applicom_pci_devnames[dev->device-1], PCI_BASE_ADDRESS(dev),
- dev->irq);
-
- if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev),
- (unsigned long)RamIO,0)))
- {
- printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
- iounmap(RamIO);
- continue;
- }
-
- if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open))
- {
- printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
- iounmap(RamIO);
- apbs[boardno-1].RamIO = 0;
- continue;
- }
-
- /* Enable interrupts. */
-
- writeb(0x40, apbs[boardno-1].RamIO + RAM_IT_FROM_PC);
-
- apbs[boardno-1].irq = dev->irq;
- }
-
+
+ while ((dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev))) {
+ // mem = dev->base_address[0];
+ // irq = dev->irq;
+
+ RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
+
+ if (!RamIO) {
+ printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev));
+ return -EIO;
+ }
+
+ printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n", applicom_pci_devnames[dev->device - 1], PCI_BASE_ADDRESS(dev), dev->irq);
+
+ if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev), (unsigned long) RamIO, 0))) {
+ printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
+ iounmap(RamIO);
+ continue;
+ }
+
+ if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) {
+ printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
+ iounmap(RamIO);
+ apbs[boardno - 1].RamIO = 0;
+ continue;
+ }
+
+ /* Enable interrupts. */
+
+ writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC);
+
+ apbs[boardno - 1].irq = dev->irq;
+ }
+
/* Finished with PCI cards. If none registered,
* and there was no mem/irq specified, exit */
- if (!mem || !irq)
- {
- if (numboards)
- goto fin;
- else
- {
- printk(KERN_INFO "ac.o: No PCI boards found.\n");
- printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n");
- return -ENXIO;
- }
- }
-
+ if (!mem || !irq) {
+ if (numboards)
+ goto fin;
+ else {
+ printk(KERN_INFO "ac.o: No PCI boards found.\n");
+ printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n");
+ return -ENXIO;
+ }
+ }
+
/* Now try the specified ISA cards */
- RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
+ RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
if (!RamIO) {
- printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n",mem);
+ printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem);
+ }
+
+ for (i = 0; i < MAX_ISA_BOARD; i++) {
+ RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
+
+ if (!RamIO) {
+ printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1);
+ continue;
+ }
+
+ if (!(boardno = ac_register_board((unsigned long) mem + (LEN_RAM_IO * i), (unsigned long) RamIO, i + 1))) {
+ iounmap(RamIO);
+ continue;
+ }
+
+ printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO * i), irq);
+
+ if (!numisa) {
+ if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open)) {
+ printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq);
+ iounmap((void *) RamIO);
+ apbs[boardno - 1].RamIO = 0;
+ }
+ apbs[boardno - 1].irq = irq;
+ } else
+ apbs[boardno - 1].irq = 0;
+
+ numisa++;
}
-
- for (i=0; i< MAX_ISA_BOARD; i++)
- {
- RamIO = ioremap(mem+ (LEN_RAM_IO*i), LEN_RAM_IO);
-
- if (!RamIO) {
- printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n",i+1);
- continue;
- }
-
- if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i),
- (unsigned long)RamIO,i+1))) {
- iounmap(RamIO);
- continue;
- }
-
- printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq);
-
- if (!numisa)
- {
- if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open))
- {
- printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq);
- iounmap((void *)RamIO);
- apbs[boardno-1].RamIO = 0;
- }
- apbs[boardno-1].irq=irq;
- }
- else
- apbs[boardno-1].irq=0;
-
- numisa++;
- }
if (!numisa)
- printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem);
+ printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n", mem);
#if LINUX_VERSION_CODE > 0x20300
init_waitqueue_head(&FlagSleepRec);
#else
- FlagSleepRec = NULL;
+ FlagSleepRec = NULL;
#endif
- WriteErrorCount = 0;
- ReadErrorCount = 0;
+ WriteErrorCount = 0;
+ ReadErrorCount = 0;
DeviceErrorCount = 0;
-fin:
- if (numboards)
- {
- misc_register (&ac_miscdev);
- for (i=0; i<MAX_BOARD; i++)
- {
- int serial;
- char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
+ fin:
+ if (numboards) {
+ misc_register(&ac_miscdev);
+ for (i = 0; i < MAX_BOARD; i++) {
+ int serial;
+ char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
- if (!apbs[i].RamIO)
- continue;
-
- for(serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
- boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
- boardname[serial]=0;
-
+ if (!apbs[i].RamIO)
+ continue;
- printk("Applicom board %d: %s, PROM V%d.%d",
- i+1, boardname,
- (int)(readb(apbs[i].RamIO + VERS) >> 4),
- (int)(readb(apbs[i].RamIO + VERS) & 0xF));
+ for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
+ boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
+ boardname[serial] = 0;
+
+
+ printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d", i + 1, boardname, (int) (readb(apbs[i].RamIO + VERS) >> 4), (int) (readb(apbs[i].RamIO + VERS) & 0xF));
+
+ serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2));
+
+ if (serial != 0)
+ printk(" S/N %d\n", serial);
+ else
+ printk("\n");
+ }
+ return 0;
+ }
- serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
-
- if (serial != 0)
- printk (" S/N %d\n", serial);
- else
- printk("\n");
- }
- return 0;
- }
-
else
- return -ENXIO;
+ return -ENXIO;
}
#ifndef MODULE
-__initcall (applicom_init);
+__initcall(applicom_init);
#endif
static loff_t ac_llseek(struct file *file, loff_t offset, int origin)
@@ -361,477 +334,455 @@ static int ac_release(struct inode *inode, struct file *file)
}
-static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos)
+static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
{
- unsigned int NumCard; /* Board number 1 -> 8 */
- unsigned int IndexCard; /* Index board number 0 -> 7 */
- unsigned char TicCard; /* Board TIC to send */
- unsigned long flags; /* Current priority */
- struct st_ram_io st_loc;
- struct mailbox tmpmailbox;
-
- if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
- printk("Hmmm. write() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
- return -EINVAL;
- }
-
- if(copy_from_user (&st_loc, buf, sizeof(struct st_ram_io))) {
- return -EFAULT;
- }
- if(copy_from_user (&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) {
- return -EFAULT;
- }
-
- NumCard = st_loc.num_card; /* board number to send */
- TicCard = st_loc.tic_des_from_pc; /* tic number to send */
- IndexCard = NumCard -1;
- if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)
- { /* User board number not OK */
- // printk("Write to invalid Applicom board %d\n", NumCard);
- return -EINVAL; /* Return error code user buffer */
- }
-
+ unsigned int NumCard; /* Board number 1 -> 8 */
+ unsigned int IndexCard; /* Index board number 0 -> 7 */
+ unsigned char TicCard; /* Board TIC to send */
+ unsigned long flags; /* Current priority */
+ struct st_ram_io st_loc;
+ struct mailbox tmpmailbox;
+
+ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+ printk("Hmmm. write() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) {
+ return -EFAULT;
+ }
+ if (copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) {
+ return -EFAULT;
+ }
+
+ NumCard = st_loc.num_card; /* board number to send */
+ TicCard = st_loc.tic_des_from_pc; /* tic number to send */
+ IndexCard = NumCard - 1;
+ if ((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) { /* User board number not OK */
+ // printk("Write to invalid Applicom board %d\n", NumCard);
+ return -EINVAL; /* Return error code user buffer */
+ }
#ifdef DEBUG
- {
- int c;
-
- printk("Write to applicom card #%d. struct st_ram_io follows:",NumCard);
-
-
-
- for (c=0; c< sizeof(struct st_ram_io);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct st_ram_io); c++)
- {
- printk(" %2.2X",((unsigned char *)&st_loc)[c]);
- }
- }
+ {
+ int c;
+
+ printk("Write to applicom card #%d. struct st_ram_io follows:", NumCard);
+
+
+
+ for (c = 0; c < sizeof(struct st_ram_io);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
+ printk(" %2.2X", ((unsigned char *) &st_loc)[c]);
+ }
+ }
+
+ printk("\nstruct mailbox follows:");
+
+ for (c = 0; c < sizeof(struct mailbox);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
+ printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]);
+ }
+ }
+
+ printk("\n");
+ }
- printk("\nstruct mailbox follows:");
-
- for (c=0; c< sizeof(struct mailbox);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&tmpmailbox)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct mailbox); c++)
- {
- printk(" %2.2X",((unsigned char *)&tmpmailbox)[c]);
- }
- }
-
- printk("\n");
- }
-
#endif
- save_flags (flags);
- cli(); /* disable interrupt */
-
- if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) /* Test octet ready correct */
- {
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags(flags);
- printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n",
- IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
- DeviceErrorCount++;
- return -EIO;
- }
- while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0)
- {
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags(flags);
- interruptible_sleep_on (&apbs[IndexCard].FlagSleepSend);
- if (signal_pending(current))
- return -EINTR;
- save_flags(flags);
- cli();
- }
- writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
-
- // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox));
- {
- unsigned char *from = (unsigned char *)&tmpmailbox;
- unsigned long to = (unsigned long)apbs[IndexCard].RamIO + RAM_FROM_PC;
- int c;
-
- for (c=0; c<sizeof(struct mailbox) ; c++)
- writeb(*(from++), to++);
- }
- writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC);
- writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC);
- writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC);
- writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
- writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
- writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags (flags);
- return 0;
+ save_flags(flags);
+ cli(); /* disable interrupt */
+
+ if (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { /* Test octet ready correct */
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n", IndexCard, (int) readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
+ DeviceErrorCount++;
+ return -EIO;
+ }
+ while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) {
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ /*
+ * FIXME: Race on wakeup. Race on re-entering write
+ * in another thread.
+ */
+ interruptible_sleep_on(&apbs[IndexCard].FlagSleepSend);
+ if (signal_pending(current))
+ return -EINTR;
+ save_flags(flags);
+ cli();
+ }
+ writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+
+ // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox));
+ {
+ unsigned char *from = (unsigned char *) &tmpmailbox;
+ unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC;
+ int c;
+
+ for (c = 0; c < sizeof(struct mailbox); c++)
+ writeb(*(from++), to++);
+ }
+ writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC);
+ writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC);
+ writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC);
+ writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
+ writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ return 0;
}
-static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr)
+static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr)
{
- unsigned int NumCard; /* board number 1 -> 8 */
- unsigned int IndexCard; /* index board number 0 -> 7 */
- unsigned long flags;
- unsigned int i;
- unsigned char tmp=0;
- struct st_ram_io st_loc;
- struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */
-
-
- if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
- printk("Hmmm. read() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
- return -EINVAL;
- }
-
- save_flags(flags);
- cli();
-
- i = 0;
-
- while (tmp != 2)
- {
- for (i=0; i < MAX_BOARD; i++)
- {
- if (!apbs[i].RamIO)
- continue;
-
- tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
-
- if (tmp == 2)
- break;
-
- if (tmp > 2) /* Test octet ready correct */
- {
- Dummy = readb(apbs[i].RamIO + VERS);
- restore_flags(flags);
- printk("APPLICOM driver read error board %d, DataToPcReady = %d\n",
- i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
- DeviceErrorCount++;
- return -EIO;
- }
- Dummy = readb(apbs[i].RamIO + VERS);
+ unsigned int NumCard; /* board number 1 -> 8 */
+ unsigned int IndexCard; /* index board number 0 -> 7 */
+ unsigned long flags;
+ unsigned int i;
+ unsigned char tmp = 0;
+ struct st_ram_io st_loc;
+ struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */
+
+
+ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+ printk("Hmmm. read() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ return -EINVAL;
+ }
+ save_flags(flags);
+ cli();
+
+ i = 0;
+
+ while (tmp != 2) {
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+
+ tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
+
+ if (tmp == 2)
+ break;
+
+ if (tmp > 2) { /* Test octet ready correct */
+ Dummy = readb(apbs[i].RamIO + VERS);
+ restore_flags(flags);
+ printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", i, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY));
+ DeviceErrorCount++;
+ return -EIO;
+ }
+ Dummy = readb(apbs[i].RamIO + VERS);
+
+ }
+ if (tmp != 2) {
+ /*
+ * FIXME: race on wakeup. O_NDELAY not implemented
+ * Parallel read threads race.
+ */
+ restore_flags(flags);
+ interruptible_sleep_on(&FlagSleepRec);
+ if (signal_pending(current))
+ return -EINTR;
+ save_flags(flags);
+ cli();
+ }
}
- if (tmp != 2)
+
+ IndexCard = i;
+ NumCard = i + 1;
+ st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
+ st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+
+
+ // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox));
{
- restore_flags(flags);
- interruptible_sleep_on (&FlagSleepRec);
- if (signal_pending(current))
- return -EINTR;
- save_flags(flags);
- cli();
+ unsigned long from = (unsigned long) apbs[IndexCard].RamIO + RAM_TO_PC;
+ unsigned char *to = (unsigned char *) &tmpmailbox;
+ int c;
+
+ for (c = 0; c < sizeof(struct mailbox); c++)
+ *(to++) = readb(from++);
}
- }
-
- IndexCard = i;
- NumCard = i+1;
- st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
- st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
-
-
- // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox));
- {
- unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC;
- unsigned char *to = (unsigned char *)&tmpmailbox;
- int c;
-
- for (c=0; c<sizeof(struct mailbox) ; c++)
- *(to++) = readb(from++);
- }
- writeb(1,apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
- writeb(1,apbs[IndexCard].RamIO + TYP_ACK_FROM_PC);
- writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
- writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC),
- apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
- writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
- writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY);
- writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags(flags);
+ writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC);
+ writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+ writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
+ writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
+ writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY);
+ writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
#ifdef DEBUG
- { int c;
+ {
+ int c;
- printk("Read from applicom card #%d. struct st_ram_io follows:",NumCard);
-
- for (c=0; c< sizeof(struct st_ram_io);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct st_ram_io); c++)
- {
- printk(" %2.2X",((unsigned char *)&st_loc)[c]);
- }
- }
+ printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard);
- printk("\nstruct mailbox follows:");
-
- for (c=0; c< sizeof(struct mailbox);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&tmpmailbox)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct mailbox); c++)
- {
- printk(" %2.2X",((unsigned char *)&tmpmailbox)[c]);
- }
- }
- printk("\n");
-
- }
+ for (c = 0; c < sizeof(struct st_ram_io);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
+ printk(" %2.2X", ((unsigned char *) &st_loc)[c]);
+ }
+ }
+
+ printk("\nstruct mailbox follows:");
+
+ for (c = 0; c < sizeof(struct mailbox);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
+ printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]);
+ }
+ }
+ printk("\n");
+
+ }
#endif
-
- /* Je suis stupide. DW. */
- if(copy_to_user (buf, &st_loc, sizeof(struct st_ram_io)))
- return -EFAULT;
- if(copy_to_user (&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
- return -EFAULT;
+ /* Je suis stupide. DW. */
- return 0;
+ if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
+ return -EFAULT;
+
+ return 0;
}
static void ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
{
- unsigned int i;
- unsigned int FlagInt;
- unsigned int LoopCount;
- // volatile unsigned char ResetIntBoard;
-
- // printk("Applicom interrupt on IRQ %d occurred\n", vec);
-
- LoopCount = 0;
- // for(i=boardno;i<MAX_BOARD;i++) /* loop for not configured board */
- // if (apbs[i].RamIO)
- // ResetIntBoard = *apbs[i].PtrRamItToPc; /* reset interrupt of unused boards */
-
- do
- {
- FlagInt = FALSE;
- for(i=0;i<MAX_BOARD;i++)
- {
- if (!apbs[i].RamIO)
- continue;
-
- if(readb(apbs[i].RamIO + RAM_IT_TO_PC) != 0)
- FlagInt = TRUE;
- writeb(0, apbs[i].RamIO + RAM_IT_TO_PC);
-
- if(readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2)
- {
- printk("APPLICOM driver interrupt err board %d, DataToPcReady = %d\n",
- i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
- DeviceErrorCount++;
- }
- if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) &&
- (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6))
- {
- printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n",
- i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY));
- DeviceErrorCount++;
- }
- if(readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) /* mailbox sent by the card ? */
- {
- wake_up_interruptible(&FlagSleepRec);
- }
- if(readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) /* ram i/o free for write by pc ? */
- {
- if(waitqueue_active(&apbs[i].FlagSleepSend)) /* process sleep during read ? */
- {
- wake_up_interruptible(&apbs[i].FlagSleepSend);
- }
- }
- Dummy = readb(apbs[i].RamIO + VERS);
-
- if(readb(apbs[i].RamIO + RAM_IT_TO_PC))
- i--; /* There's another int waiting on this card */
- }
- if(FlagInt) LoopCount = 0;
- else LoopCount++;
- }
- while(LoopCount < 2);
+ unsigned int i;
+ unsigned int FlagInt;
+ unsigned int LoopCount;
+ // volatile unsigned char ResetIntBoard;
+
+ // printk("Applicom interrupt on IRQ %d occurred\n", vec);
+
+ LoopCount = 0;
+ // for(i=boardno;i<MAX_BOARD;i++) /* loop for not configured board */
+ // if (apbs[i].RamIO)
+ // ResetIntBoard = *apbs[i].PtrRamItToPc; /* reset interrupt of unused boards */
+
+ do {
+ FlagInt = FALSE;
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+
+ if (readb(apbs[i].RamIO + RAM_IT_TO_PC) != 0)
+ FlagInt = TRUE;
+ writeb(0, apbs[i].RamIO + RAM_IT_TO_PC);
+
+ if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) {
+ printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY));
+ DeviceErrorCount++;
+ }
+ if ((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) {
+ printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_FROM_PC_READY));
+ DeviceErrorCount++;
+ }
+ if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */
+ wake_up_interruptible(&FlagSleepRec);
+ }
+ if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */
+ if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */
+ wake_up_interruptible(&apbs[i].FlagSleepSend);
+ }
+ }
+ Dummy = readb(apbs[i].RamIO + VERS);
+
+ if (readb(apbs[i].RamIO + RAM_IT_TO_PC))
+ i--; /* There's another int waiting on this card */
+ }
+ if (FlagInt)
+ LoopCount = 0;
+ else
+ LoopCount++;
+ }
+ while (LoopCount < 2);
}
static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{ /* @ ADG ou ATO selon le cas */
+ int i;
+ unsigned char IndexCard;
+ unsigned long pmem;
+ volatile unsigned char byte_reset_it;
+ struct st_ram_io adgl;
+ unsigned char TmpRamIo[sizeof(struct st_ram_io)];
-{ /* @ ADG ou ATO selon le cas */
- int i;
- unsigned char IndexCard;
- unsigned long pmem ;
- volatile unsigned char byte_reset_it;
- struct st_ram_io adgl ;
- unsigned char TmpRamIo[sizeof(struct st_ram_io)];
-
-
- if (copy_from_user (&adgl, (void *)arg,sizeof(struct st_ram_io)))
- return -EFAULT;
-
- IndexCard = adgl.num_card-1;
- if(cmd != 0 && cmd != 6 &&
- ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO))
- {
- printk("APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
- printk("apbs[%d].RamIO = %lx\n",IndexCard, apbs[IndexCard].RamIO);
- return -EINVAL;
- }
-
- switch( cmd )
- {
- case 0 :
- pmem = apbs[IndexCard].RamIO;
- for(i=0;i<sizeof(struct st_ram_io);i++)TmpRamIo[i]=readb(pmem++);
- if (copy_to_user((void *)arg, TmpRamIo, sizeof(struct st_ram_io)))
- return -EFAULT;
- break;
- case 1 :
- pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
- for (i=0;i<4;i++)
- adgl.conf_end_test[i] = readb(pmem++);
- for (i=0;i<2;i++)
- adgl.error_code[i] = readb(pmem++);
- for (i=0;i<4;i++)
- adgl.parameter_error[i] = readb(pmem++);
- pmem = apbs[IndexCard].RamIO + VERS;
- adgl.vers = readb(pmem);
- pmem = apbs[IndexCard].RamIO + TYPE_CARD;
- for (i=0;i<20;i++)
- adgl.reserv1[i] = readb(pmem++);
- *(int *)&adgl.reserv1[20] =
- (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) +
- (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) +
- (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) );
-
- if (copy_to_user ((void *)arg, &adgl, sizeof(struct st_ram_io)))
- return -EFAULT;
- break;
- case 2 :
- pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
- for (i=0;i<10;i++)
- writeb(0xff, pmem++);
- writeb(adgl.data_from_pc_ready,
- apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
-
- writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+
+ if (copy_from_user(&adgl, (void *) arg, sizeof(struct st_ram_io)))
+ return -EFAULT;
+
+ IndexCard = adgl.num_card - 1;
+
+ /*
+ * FIXME: user can flood the console using bogus ioctls
+ */
+
+ if (cmd != 0 && cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+ printk("APPLICOM driver IOCTL, bad board number %d\n", (int) IndexCard + 1);
+ printk("apbs[%d].RamIO = %lx\n", IndexCard, apbs[IndexCard].RamIO);
+ return -EINVAL;
+ }
+
+ /*
+ * FIXME races between ioctls with multiple clients
+ */
+
+ switch (cmd) {
+ case 0:
+ pmem = apbs[IndexCard].RamIO;
+ for (i = 0; i < sizeof(struct st_ram_io); i++)
+ TmpRamIo[i] = readb(pmem++);
+ if (copy_to_user((void *) arg, TmpRamIo, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 1:
+ pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
+ for (i = 0; i < 4; i++)
+ adgl.conf_end_test[i] = readb(pmem++);
+ for (i = 0; i < 2; i++)
+ adgl.error_code[i] = readb(pmem++);
+ for (i = 0; i < 4; i++)
+ adgl.parameter_error[i] = readb(pmem++);
+ pmem = apbs[IndexCard].RamIO + VERS;
+ adgl.vers = readb(pmem);
+ pmem = apbs[IndexCard].RamIO + TYPE_CARD;
+ for (i = 0; i < 20; i++)
+ adgl.reserv1[i] = readb(pmem++);
+ *(int *) &adgl.reserv1[20] = (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2));
+
+ if (copy_to_user((void *) arg, &adgl, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 2:
+ pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
+ for (i = 0; i < 10; i++)
+ writeb(0xff, pmem++);
+ writeb(adgl.data_from_pc_ready, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+
+ /*
+ * FIXME: can trash waitqueue that is active.
+ */
#if LINUX_VERSION_CODE > 0x20300
- init_waitqueue_head (&FlagSleepRec);
+ init_waitqueue_head(&FlagSleepRec);
#else
- FlagSleepRec = NULL;
+ FlagSleepRec = NULL;
#endif
- for (i=0;i<MAX_BOARD;i++)
- {
- if (apbs[i].RamIO)
- {
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (apbs[i].RamIO) {
#if LINUX_VERSION_CODE > 0x20300
- init_waitqueue_head (&apbs[i].FlagSleepSend);
+ init_waitqueue_head(&apbs[i].FlagSleepSend);
#else
- apbs[i].FlagSleepSend = NULL;
+ apbs[i].FlagSleepSend = NULL;
#endif
- byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC);
- }
- }
- break ;
- case 3 :
- pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC;
- writeb(adgl.tic_des_from_pc, pmem);
- break;
- case 4 :
- pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC;
- adgl.tic_owner_to_pc = readb(pmem++);
- adgl.numcard_owner_to_pc = readb(pmem);
- if (copy_to_user ((void *)arg, &adgl,sizeof(struct st_ram_io)))
- return -EFAULT;
- break;
- case 5 :
- writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
- writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
- writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
- writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
- writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
- break ;
- case 6 :
- printk("APPLICOM driver release .... V2.8.0\n");
- printk("Number of installed boards . %d\n",(int)numboards);
- printk("Segment of board ........... %X\n",(int)mem);
- printk("Interrupt IRQ number ....... %d\n",(int)irq);
- for(i=0;i<MAX_BOARD;i++)
- {
- int serial;
- char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
-
- if (!apbs[i].RamIO)
- continue;
-
-
- for(serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
- boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
- boardname[serial]=0;
-
-
- printk("Prom version board %d ....... V%d.%d %s",
- i+1,
- (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4),
- (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF),
- boardname);
-
-
- serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
-
- if (serial != 0)
- printk (" S/N %d\n", serial);
- else
- printk("\n");
- }
- if(DeviceErrorCount != 0)
- printk("DeviceErrorCount ........... %d\n",DeviceErrorCount);
- if(ReadErrorCount != 0)
- printk("ReadErrorCount ............. %d\n",ReadErrorCount);
- if(WriteErrorCount != 0)
- printk("WriteErrorCount ............ %d\n",WriteErrorCount);
- if(waitqueue_active(&FlagSleepRec))
- printk("Process in read pending\n");
- for(i=0;i<MAX_BOARD;i++)
- {
- if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend))
- printk("Process in write pending board %d\n",i+1);
- }
- break;
- default :
- printk("APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
- return -EINVAL;
- break;
- }
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- return 0;
+ byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC);
+ }
+ }
+ break;
+ case 3:
+ pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC;
+ writeb(adgl.tic_des_from_pc, pmem);
+ break;
+ case 4:
+ pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC;
+ adgl.tic_owner_to_pc = readb(pmem++);
+ adgl.numcard_owner_to_pc = readb(pmem);
+ if (copy_to_user((void *) arg, &adgl, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 5:
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+ writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ break;
+ case 6:
+ printk(KERN_INFO "APPLICOM driver release .... V2.8.0\n");
+ printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards);
+ printk(KERN_INFO "Segment of board ........... %X\n", (int) mem);
+ printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq);
+ for (i = 0; i < MAX_BOARD; i++) {
+ int serial;
+ char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
+
+ if (!apbs[i].RamIO)
+ continue;
+
+
+ for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
+ boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
+ boardname[serial] = 0;
+
+
+ printk(KERN_INFO "Prom version board %d ....... V%d.%d %s", i + 1, (int) (readb(apbs[IndexCard].RamIO + VERS) >> 4), (int) (readb(apbs[IndexCard].RamIO + VERS) & 0xF), boardname);
+
+
+ serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2));
+
+ if (serial != 0)
+ printk(" S/N %d\n", serial);
+ else
+ printk("\n");
+ }
+ if (DeviceErrorCount != 0)
+ printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount);
+ if (ReadErrorCount != 0)
+ printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount);
+ if (WriteErrorCount != 0)
+ printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount);
+ if (waitqueue_active(&FlagSleepRec))
+ printk("Process in read pending\n");
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend))
+ printk("Process in write pending board %d\n", i + 1);
+ }
+ break;
+ default:
+ printk("APPLICOM driver ioctl, unknown function code %d\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ return 0;
}
#ifndef MODULE
static int __init applicom_setup(char *str)
{
int ints[4];
-
- (void)get_options(str, 4, ints);
+
+ (void) get_options(str, 4, ints);
if (ints[0] > 2) {
printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n");
}
-
+
if (ints[0] < 2) {
printk("applicom numargs: %d\n", ints[0]);
return 0;
}
-
- mem=ints[1];
- irq=ints[2];
+
+ mem = ints[1];
+ irq = ints[2];
return 1;
}
+
#if LINUX_VERSION_CODE > 0x20300
__setup("applicom=", applicom_setup);
#endif
-#endif /* MODULE */
-
+#endif /* MODULE */
diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c
index 38de427e6..223793374 100644
--- a/drivers/char/atixlmouse.c
+++ b/drivers/char/atixlmouse.c
@@ -92,10 +92,14 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
+ /* Lock module as request_irq may sleep */
+ MOD_INC_USE_COUNT;
if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
+ {
+ MOD_DEC_USE_COUNT;
return -EBUSY;
+ }
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
- MOD_INC_USE_COUNT;
return 0;
}
@@ -107,7 +111,13 @@ static int __init atixl_busmouse_init(void)
{
unsigned char a,b,c;
- if (check_region(ATIXL_MSE_DATA_PORT, 3))
+ /*
+ * We must request the resource and claim it atomically
+ * nowdays. We can throw it away on error. Otherwise we
+ * may race another module load of the same I/O
+ */
+
+ if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse"))
return -EIO;
a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */
@@ -116,16 +126,20 @@ static int __init atixl_busmouse_init(void)
if (( a != b ) && ( a == c ))
printk(KERN_INFO "\nATI Inport ");
else
+ {
+ release_region(ATIXL_MSE_DATA_PORT,3);
return -EIO;
+ }
outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */
outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */
outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
- request_region(ATIXL_MSE_DATA_PORT, 3, "atixl");
-
msedev = register_busmouse(&atixlmouse);
if (msedev < 0)
+ {
printk("Bus mouse initialisation error.\n");
+ release_region(ATIXL_MSE_DATA_PORT,3); /* Was missing */
+ }
else
printk("Bus mouse detected and installed.\n");
return msedev < 0 ? msedev : 0;
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index 66dfc0fe5..59adf47bc 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -121,6 +121,7 @@ static unsigned int autoload = 0;
#define I2C_GET() (btread(BT848_I2C)&1)
#define BURSTOFFSET 76
+#define BTTV_ERRORS 5
/* ----------------------------------------------------------------------- */
@@ -133,7 +134,6 @@ int bttv_get_id(unsigned int card)
if (card >= bttv_num) {
return -1;
}
-
return bttvs[card].type;
}
@@ -146,10 +146,7 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
}
btv = &bttvs[card];
- down(&btv->lock);
btaor(data, ~mask, BT848_GPIO_OUT_EN);
- up(&btv->lock);
-
return 0;
}
@@ -167,15 +164,9 @@ int bttv_read_gpio(unsigned int card, unsigned long *data)
return -ENODEV;
}
- down(&btv->lock);
-
/* prior setting BT848_GPIO_REG_INP is (probably) not needed
because we set direct input on init */
-
*data = btread(BT848_GPIO_DATA);
-
- up(&btv->lock);
-
return 0;
}
@@ -189,15 +180,9 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
btv = &bttvs[card];
- down(&btv->lock);
-
/* prior setting BT848_GPIO_REG_INP is (probably) not needed
because direct input is set on init */
-
btaor(data & mask, ~mask, BT848_GPIO_DATA);
-
- up(&btv->lock);
-
return 0;
}
@@ -210,11 +195,9 @@ WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card)
}
btv = &bttvs[card];
-
if (bttvs[card].shutdown) {
return NULL;
}
-
return &btv->gpioq;
}
@@ -787,7 +770,7 @@ static struct tvcard tvcards[] =
4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0,
1,1,1,1,0 },
{ "Hauppauge old",
- 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
+ 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
1,1,0,1,0 },
{ "STB",
3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
@@ -815,7 +798,7 @@ static struct tvcard tvcards[] =
3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0,
1,1,1,1,0 },
{ "Hauppauge new (bt878)",
- 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
+ 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
1,1,0,1,0 },
{ "MIRO PCTV pro",
3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0,
@@ -1213,7 +1196,7 @@ static void make_vbitab(struct bttv *btv)
unsigned int *pe=(unsigned int *) btv->vbi_even;
if (debug)
- printk("bttv%d: vbi: po=%08lx pe=%08lx\n",
+ printk("bttv%d: vbi1: po=%08lx pe=%08lx\n",
btv->nr,virt_to_bus(po), virt_to_bus(pe));
*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
@@ -1233,8 +1216,10 @@ static void make_vbitab(struct bttv *btv)
}
*(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16));
*(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
- DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po));
- DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
+
+ if (debug)
+ printk("bttv%d: vbi2: po=%08lx pe=%08lx\n",
+ btv->nr,virt_to_bus(po), virt_to_bus(pe));
}
static int fmtbppx2[16] = {
@@ -1310,7 +1295,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro,
int shift, csize;
if (debug)
- printk("bttv%d: prisc: ro=%08lx re=%08lx\n",
+ printk("bttv%d: prisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
switch(fmt)
@@ -1406,6 +1391,10 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro,
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
+ if (debug)
+ printk("bttv%d: prisc2: ro=%08lx re=%08lx\n",
+ btv->nr,virt_to_bus(ro), virt_to_bus(re));
+
return 0;
}
@@ -1428,7 +1417,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
return make_prisctab(btv, ro, re, vbuf, width, height, palette);
if (debug)
- printk("bttv%d: vrisc: ro=%08lx re=%08lx\n",
+ printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
@@ -1478,6 +1467,10 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
+
+ if (debug)
+ printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n",
+ btv->nr,virt_to_bus(ro), virt_to_bus(re));
return 0;
}
@@ -1555,7 +1548,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
width=btv->win.width;
height=btv->win.height;
if (debug)
- printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
+ printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
btv->nr,btv->picture.palette,width,height,bpl,bpp);
if(width > 1023)
width = 1023; /* sanity check */
@@ -1662,6 +1655,10 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP);
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
+
+ if (debug)
+ printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
+ btv->nr,btv->picture.palette,width,height,bpl,bpp);
}
/*
@@ -1879,7 +1876,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED)
return -EBUSY;
- if(mp->height <0 || mp->width <0)
+ if(mp->height < 32 || mp->width < 32)
return -EINVAL;
if (mp->format >= PALETTEFMT_MAX)
return -EINVAL;
@@ -1891,12 +1888,6 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
return -EINVAL;
/*
- * FIXME: Check the format of the grab here. This is probably
- * also less restrictive than the normal overlay grabs. Stuff
- * like QCIF has meaning as a capture.
- */
-
- /*
* Ok load up the BT848
*/
@@ -1906,7 +1897,8 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
if (debug)
- printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame);
+ printk("bttv%d: cap vgrab: queue %d (%dx%d)\n",
+ btv->nr,mp->frame,mp->width,mp->height);
cli();
btv->gbuf[mp->frame].stat = GBUFFER_GRABBING;
btv->gbuf[mp->frame].fmt = palette2fmt[mp->format];
@@ -1995,6 +1987,26 @@ static inline void burst(int on)
tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0);
}
+static void bt848_restart(struct bttv *btv)
+{
+ if (verbose)
+ printk("bttv%d: resetting chip\n",btv->nr);
+ btwrite(0xfffffUL, BT848_INT_STAT);
+ btand(~15, BT848_GPIO_DMA_CTL);
+ btwrite(0, BT848_SRESET);
+ btwrite(virt_to_bus(btv->risc_jmp+2),
+ BT848_RISC_STRT_ADD);
+
+ /* enforce pll reprogramming */
+ btv->pll.pll_current = 0;
+ set_pll(btv);
+
+ btv->errors = 0;
+ btv->needs_restart = 0;
+ bt848_set_geo(btv,0);
+ bt848_set_risc_jmps(btv,-1);
+}
+
/*
* Open a bttv card. Right now the flags stuff is just playing
*/
@@ -2020,6 +2032,8 @@ static int bttv_open(struct video_device *dev, int flags)
for (i = 0; i < gbuffers; i++)
btv->gbuf[i].stat = GBUFFER_UNUSED;
+ if (btv->needs_restart)
+ bt848_restart(btv);
burst(0);
set_pll(btv);
btv->user++;
@@ -2117,7 +2131,6 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
btaor(datahi, ~1, BT848_O_CONTROL);
}
-
/*
* ioctl routine
*/
@@ -2126,7 +2139,7 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct bttv *btv=(struct bttv *)dev;
- int i,ret;
+ int i,ret = 0;
if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
@@ -2281,7 +2294,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
-
+
if(vw.flags || vw.width < 16 || vw.height < 16)
{
down(&btv->lock);
@@ -2296,6 +2309,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
vw.width &= ~3;
}
down(&btv->lock);
+ if (btv->needs_restart)
+ bt848_restart(btv);
btv->win.x=vw.x;
btv->win.y=vw.y;
btv->win.width=vw.width;
@@ -2551,14 +2566,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EINVAL;
switch (btv->gbuf[i].stat) {
case GBUFFER_UNUSED:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
case GBUFFER_GRABBING:
while(btv->gbuf[i].stat==GBUFFER_GRABBING) {
if (debug)
printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i);
interruptible_sleep_on(&btv->capq);
- if(signal_pending(current))
- return -EINTR;
+ if(signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
}
/* fall throuth */
case GBUFFER_DONE:
@@ -2567,9 +2585,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (debug)
printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret);
btv->gbuf[i].stat = GBUFFER_UNUSED;
- return ret;
}
- return 0;
+ if (btv->needs_restart) {
+ down(&btv->lock);
+ bt848_restart(btv);
+ up(&btv->lock);
+ }
+ return ret;
case BTTV_FIELDNR:
if(copy_to_user((void *) arg, (void *) &btv->last_field,
@@ -2742,6 +2764,11 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count,
todo=count;
while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
{
+ if (btv->needs_restart) {
+ down(&btv->lock);
+ bt848_restart(btv);
+ up(&btv->lock);
+ }
if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
return -EFAULT;
todo-=q;
@@ -2796,6 +2823,8 @@ static int vbi_open(struct video_device *dev, int flags)
struct bttv *btv=(struct bttv *)(dev-2);
down(&btv->lock);
+ if (btv->needs_restart)
+ bt848_restart(btv);
btv->vbip=VBIBUF_SIZE;
btv->vbi_on = 1;
bt848_set_risc_jmps(btv,-1);
@@ -2938,8 +2967,8 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(v.tuner||btv->channel) /* Only tuner 0 */
return -EINVAL;
strcpy(v.name, "Radio");
- v.rangelow=(int)(87.5*16);
- v.rangehigh=(int)(108*16);
+ v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */
+ v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */
v.flags= 0; /* XXX */
v.mode = 0; /* XXX */
if(copy_to_user(arg,&v,sizeof(v)))
@@ -3100,12 +3129,10 @@ static void idcard(int i)
/* print which board we have found */
printk(KERN_INFO "bttv%d: model: ",btv->nr);
- sprintf(btv->video_dev.name,"BT%d",btv->id);
- if (btv->id==848 && btv->revision==0x12)
- strcat(btv->video_dev.name,"A");
- strcat(btv->video_dev.name,"(");
- strcat(btv->video_dev.name, tvcards[btv->type].name);
- strcat(btv->video_dev.name,")");
+ sprintf(btv->video_dev.name,"BT%d%s(%.22s)",
+ btv->id,
+ (btv->id==848 && btv->revision==0x12) ? "A" : "",
+ tvcards[btv->type].name);
printk("%s\n",btv->video_dev.name);
/* board specific initialisations */
@@ -3357,6 +3384,9 @@ static int init_bt848(int i)
btv->vbibuf=0;
btv->field=btv->last_field=0;
+ btv->errors=0;
+ btv->needs_restart=0;
+
/* i2c */
btv->tuner_type=-1;
init_bttv_i2c(btv);
@@ -3458,7 +3488,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
{
u32 stat,astat;
u32 dstat;
- int count;
+ int count,i;
struct bttv *btv;
btv=(struct bttv *)dev_id;
@@ -3498,24 +3528,43 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->field++;
}
if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
- printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr,
- (astat&BT848_INT_SCERR) ? " SCERR" : "",
- (astat&BT848_INT_OCERR) ? " OCERR" : "",
- btread(BT848_RISC_COUNT));
- bt848_set_risc_jmps(btv,0);
- btwrite(0, BT848_SRESET);
- btwrite(virt_to_bus(btv->risc_jmp),
- BT848_RISC_STRT_ADD);
- bt848_set_geo(btv,0);
- bt848_set_risc_jmps(btv,-1);
-#if 0
- wake_up_interruptible(&btv->vbiq);
- wake_up_interruptible(&btv->capq);
-#endif
+ if (verbose)
+ printk("bttv%d: irq:%s%s risc_count=%08x\n",
+ btv->nr,
+ (astat&BT848_INT_SCERR) ? " SCERR" : "",
+ (astat&BT848_INT_OCERR) ? " OCERR" : "",
+ btread(BT848_RISC_COUNT));
+ btv->errors++;
+ if (btv->errors < BTTV_ERRORS) {
+ btand(~15, BT848_GPIO_DMA_CTL);
+ btwrite(virt_to_bus(btv->risc_jmp+2),
+ BT848_RISC_STRT_ADD);
+ bt848_set_geo(btv,0);
+ bt848_set_risc_jmps(btv,-1);
+ } else {
+ if (verbose)
+ printk("bttv%d: aiee: error loops\n",btv->nr);
+ /* cancel all outstanding grab requests */
+ btv->gq_in = 0;
+ btv->gq_out = 0;
+ btv->gq_grab = -1;
+ for (i = 0; i < gbuffers; i++)
+ if (btv->gbuf[i].stat == GBUFFER_GRABBING)
+ btv->gbuf[i].stat = GBUFFER_ERROR;
+ /* disable DMA */
+ btv->risc_cap_odd = 0;
+ btv->risc_cap_even = 0;
+ bt848_set_risc_jmps(btv,0);
+
+ btv->needs_restart = 1;
+ wake_up_interruptible(&btv->vbiq);
+ wake_up_interruptible(&btv->capq);
+ }
}
if (astat&BT848_INT_RISCI)
{
- IDEBUG(printk ("bttv%d: IRQ_RISCI\n", btv->nr));
+ if (debug > 1)
+ printk("bttv%d: IRQ_RISCI\n",btv->nr);
/* captured VBI frame */
if (stat&(1<<28))
@@ -3527,11 +3576,12 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
/* captured full frame */
- if (stat&(2<<28))
+ if (stat&(2<<28) && btv->gq_grab != -1)
{
btv->last_field=btv->field;
if (debug)
printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab);
+ do_gettimeofday(&btv->gbuf[btv->gq_grab].tv);
btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE;
btv->gq_grab = -1;
if (btv->gq_in != btv->gq_out)
@@ -3662,6 +3712,11 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
btv->id=dev->device;
btv->irq=dev->irq;
btv->bt848_adr=dev->resource[0].start;
+ if (!request_mem_region(pci_resource_start(dev,0),
+ pci_resource_len(dev,0),
+ "bttv")) {
+ return -EBUSY;
+ }
if (btv->id >= 878)
btv->i2c_command = 0x83;
else
@@ -3720,15 +3775,15 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
{
printk(KERN_ERR "bttv%d: Bad irq number or handler\n",
bttv_num);
- return -EINVAL;
+ goto fail;
}
if (result==-EBUSY)
{
printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq);
- return result;
+ goto fail;
}
if (result < 0)
- return result;
+ goto fail;
pci_set_master(dev);
@@ -3744,11 +3799,16 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
if (!(command&BT878_EN_TBFX))
{
printk("bttv: 430FX compatibility could not be enabled\n");
- return -1;
+ result = -1;
+ goto fail;
}
}
-
return 0;
+
+ fail:
+ release_mem_region(pci_resource_start(btv->dev,0),
+ pci_resource_len(btv->dev,0));
+ return result;
}
static int find_bt848(void)
@@ -3834,6 +3894,8 @@ static void release_bttv(void)
if (radio[btv->nr] && btv->radio_dev.minor != -1)
video_unregister_device(&btv->radio_dev);
+ release_mem_region(pci_resource_start(btv->dev,0),
+ pci_resource_len(btv->dev,0));
/* wake up any waiting processes
because shutdown flag is set, no new processes (in this queue)
are expected
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index 3a2cd7e21..c1e9b3e9a 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -21,7 +21,7 @@
#ifndef _BTTV_H_
#define _BTTV_H_
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,22)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,24)
#include <linux/types.h>
#include <linux/wait.h>
@@ -112,7 +112,8 @@ struct bttv_gbuf {
#define GBUFFER_GRABBING 1
#define GBUFFER_DONE 2
#define GBUFFER_ERROR 3
-
+ struct timeval tv;
+
u16 width;
u16 height;
u16 fmt;
@@ -122,8 +123,7 @@ struct bttv_gbuf {
unsigned long re;
};
-struct bttv
-{
+struct bttv {
struct video_device video_dev;
struct video_device radio_dev;
struct video_device vbi_dev;
@@ -193,6 +193,9 @@ struct bttv
int i2c_command;
int triton1;
+ int errors;
+ int needs_restart;
+
WAIT_QUEUE gpioq;
int shutdown;
};
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 03ff3a033..afc10a697 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -48,8 +47,6 @@
*/
/*#define BROKEN_MOUSE*/
-extern int sun_mouse_init(void);
-
struct busmouse_data {
struct miscdevice miscdev;
struct busmouse *ops;
@@ -70,7 +67,13 @@ struct busmouse_data {
#define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev))
#define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE)
+/*
+ * List of mice and guarding semaphore. You must take the semaphore
+ * before you take the misc device semaphore if you need both
+ */
+
static struct busmouse_data *busmouse_data[NR_MICE];
+static DECLARE_MUTEX(mouse_sem);
/* a mouse driver just has to interface with these functions
* These are !!!OLD!!! Do not use!!!
@@ -98,8 +101,7 @@ int add_mouse_buttonchange(int set, int value)
/* New interface. !!! Use this one !!!
* These routines will most probably be called from interrupt.
*/
-void
-busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
+void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
{
struct busmouse_data *mse = busmouse_data[mousedev];
int changed;
@@ -141,24 +143,21 @@ busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
}
}
-void
-busmouse_add_movement(int mousedev, int dx, int dy)
+void busmouse_add_movement(int mousedev, int dx, int dy)
{
struct busmouse_data *mse = busmouse_data[mousedev];
busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
}
-void
-busmouse_add_buttons(int mousedev, int clear, int eor)
+void busmouse_add_buttons(int mousedev, int clear, int eor)
{
struct busmouse_data *mse = busmouse_data[mousedev];
busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
}
-static int
-busmouse_fasync(int fd, struct file *filp, int on)
+static int busmouse_fasync(int fd, struct file *filp, int on)
{
struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
int retval;
@@ -169,8 +168,7 @@ busmouse_fasync(int fd, struct file *filp, int on)
return 0;
}
-static int
-busmouse_release(struct inode *inode, struct file *file)
+static int busmouse_release(struct inode *inode, struct file *file)
{
struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
int ret = 0;
@@ -190,33 +188,34 @@ busmouse_release(struct inode *inode, struct file *file)
return ret;
}
-static int
-busmouse_open(struct inode *inode, struct file *file)
+static int busmouse_open(struct inode *inode, struct file *file)
{
struct busmouse_data *mse;
unsigned long flags;
unsigned int mousedev;
- int ret = 0;
+ int ret = -ENODEV;
mousedev = DEV_TO_MOUSE(inode->i_rdev);
if (mousedev >= NR_MICE)
return -EINVAL;
+
+ down(&mouse_sem);
mse = busmouse_data[mousedev];
if (!mse)
/* shouldn't happen, but... */
- return -ENODEV;
-
+ goto end;
+
if (mse->ops &&
mse->ops->open)
ret = mse->ops->open(inode, file);
if (ret)
- return ret;
+ goto end;
file->private_data = mse;
if (mse->active++)
- return 0;
+ goto end;
MOD_INC_USE_COUNT;
@@ -231,18 +230,17 @@ busmouse_open(struct inode *inode, struct file *file)
mse->buttons = 7;
spin_unlock_irqrestore(&mse->lock, flags);
-
- return 0;
+end:
+ up(&mouse_sem);
+ return ret;
}
-static ssize_t
-busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
return -EINVAL;
}
-static ssize_t
-busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
DECLARE_WAITQUEUE(wait, current);
@@ -328,8 +326,7 @@ repeat:
return count;
}
-static unsigned int
-busmouse_poll(struct file *file, poll_table *wait)
+static unsigned int busmouse_poll(struct file *file, poll_table *wait)
{
struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
@@ -351,8 +348,16 @@ struct file_operations busmouse_fops=
fasync: busmouse_fasync,
};
-int
-register_busmouse(struct busmouse *ops)
+/**
+ * register_busmouse - register a bus mouse interface
+ * @ops: busmouse structure for the mouse
+ *
+ * Registers a mouse with the driver. The return is mouse number on
+ * success and a negative errno code on an error. The passed ops
+ * structure most not be freed until the mouser is unregistered
+ */
+
+int register_busmouse(struct busmouse *ops)
{
unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
struct busmouse_data *mse;
@@ -364,13 +369,18 @@ register_busmouse(struct busmouse *ops)
return -EINVAL;
}
- if (busmouse_data[msedev])
- return -EBUSY;
-
mse = kmalloc(sizeof(*mse), GFP_KERNEL);
if (!mse)
return -ENOMEM;
+ down(&mouse_sem);
+ if (busmouse_data[msedev])
+ {
+ up(&mouse_sem);
+ kfree(mse);
+ return -EBUSY;
+ }
+
memset(mse, 0, sizeof(*mse));
mse->miscdev.minor = ops->minor;
@@ -385,13 +395,23 @@ register_busmouse(struct busmouse *ops)
ret = misc_register(&mse->miscdev);
if (!ret)
ret = msedev;
-
+ up(&mouse_sem);
+
return ret;
}
-int
-unregister_busmouse(int mousedev)
+/**
+ * unregister_busmouse - unregister a bus mouse interface
+ * @mousedev: Mouse number to release
+ *
+ * Unregister a previously installed mouse handler. The mousedev
+ * passed is the return code from a previous call to register_busmouse
+ */
+
+
+int unregister_busmouse(int mousedev)
{
+ int err = -EINVAL;
if (mousedev < 0)
return 0;
if (mousedev >= NR_MICE) {
@@ -400,32 +420,27 @@ unregister_busmouse(int mousedev)
return -EINVAL;
}
+ down(&mouse_sem);
+
if (!busmouse_data[mousedev]) {
printk(KERN_WARNING "busmouse: trying to free free mouse"
" on mousedev %d\n", mousedev);
- return -EINVAL;
+ goto fail;
}
if (busmouse_data[mousedev]->active) {
printk(KERN_ERR "busmouse: trying to free active mouse"
" on mousedev %d\n", mousedev);
- return -EINVAL;
+ goto fail;
}
- misc_deregister(&busmouse_data[mousedev]->miscdev);
+ err=misc_deregister(&busmouse_data[mousedev]->miscdev);
kfree(busmouse_data[mousedev]);
busmouse_data[mousedev] = NULL;
- return 0;
-}
-
-int __init
-bus_mouse_init(void)
-{
-#ifdef CONFIG_SUN_MOUSE
- sun_mouse_init();
-#endif
- return 0;
+fail:
+ up(&mouse_sem);
+ return err;
}
EXPORT_SYMBOL(busmouse_add_movementbuttons);
@@ -433,16 +448,3 @@ EXPORT_SYMBOL(busmouse_add_movement);
EXPORT_SYMBOL(busmouse_add_buttons);
EXPORT_SYMBOL(register_busmouse);
EXPORT_SYMBOL(unregister_busmouse);
-
-#ifdef MODULE
-int
-init_module(void)
-{
- return bus_mouse_init();
-}
-
-void
-cleanup_module(void)
-{
-}
-#endif
diff --git a/drivers/char/busmouse.h b/drivers/char/busmouse.h
index 3626334d9..4ba7c9ce4 100644
--- a/drivers/char/busmouse.h
+++ b/drivers/char/busmouse.h
@@ -23,6 +23,4 @@ extern void busmouse_add_buttons(int mousedev, int clear, int eor);
extern int register_busmouse(struct busmouse *ops);
extern int unregister_busmouse(int mousedev);
-extern int bus_mouse_init(void);
-
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 53939959f..30c7f4f89 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -57,6 +57,7 @@
* Head entry for the doubly linked miscdevice list
*/
static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list };
+static DECLARE_MUTEX(misc_sem);
/*
* Assigned numbers, used for dynamic minors
@@ -97,32 +98,42 @@ static int misc_read_proc(char *buf, char **start, off_t offset,
static int misc_open(struct inode * inode, struct file * file)
{
int minor = MINOR(inode->i_rdev);
- struct miscdevice *c = misc_list.next;
+ struct miscdevice *c;
+ int err = -ENODEV;
+
file->f_op = NULL;
+
+ down(&misc_sem);
+
+ c = misc_list.next;
while ((c != &misc_list) && (c->minor != minor))
c = c->next;
if (c == &misc_list) {
char modname[20];
+ up(&misc_sem);
sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
request_module(modname);
+ down(&misc_sem);
c = misc_list.next;
while ((c != &misc_list) && (c->minor != minor))
c = c->next;
if (c == &misc_list)
- return -ENODEV;
+ goto fail;
}
if ((file->f_op = c->fops) && file->f_op->open)
- return file->f_op->open(inode,file);
- else
- return -ENODEV;
+ err=file->f_op->open(inode,file);
+fail:
+ up(&misc_sem);
+ return err;
}
static struct file_operations misc_fops = {
open: misc_open,
};
+
/**
* misc_register - register a miscellaneous device
* @misc: device structure
@@ -145,12 +156,17 @@ int misc_register(struct miscdevice * misc)
if (misc->next || misc->prev)
return -EBUSY;
+ down(&misc_sem);
if (misc->minor == MISC_DYNAMIC_MINOR) {
int i = DYNAMIC_MINORS;
while (--i >= 0)
if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
break;
- if (i<0) return -EBUSY;
+ if (i<0)
+ {
+ up(&misc_sem);
+ return -EBUSY;
+ }
misc->minor = i;
}
if (misc->minor < DYNAMIC_MINORS)
@@ -171,6 +187,7 @@ int misc_register(struct miscdevice * misc)
misc->next = misc_list.next;
misc->prev->next = misc;
misc->next->prev = misc;
+ up(&misc_sem);
return 0;
}
@@ -189,6 +206,7 @@ int misc_deregister(struct miscdevice * misc)
int i = misc->minor;
if (!misc->next || !misc->prev)
return -EINVAL;
+ down(&misc_sem);
misc->prev->next = misc->next;
misc->next->prev = misc->prev;
misc->next = NULL;
@@ -197,6 +215,7 @@ int misc_deregister(struct miscdevice * misc)
if (i < DYNAMIC_MINORS && i>0) {
misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
}
+ up(&misc_sem);
return 0;
}
@@ -206,9 +225,6 @@ EXPORT_SYMBOL(misc_deregister);
int __init misc_init(void)
{
create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
-#ifdef CONFIG_BUSMOUSE
- bus_mouse_init();
-#endif
#if defined CONFIG_82C710_MOUSE
qpmouse_init();
#endif
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 97014d26a..ea9fded05 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -669,15 +669,15 @@ found:
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(year); /* This should never happen... */
- if (year > 10 && year < 44) {
+ if (year > 20 && year < 48) {
epoch = 1980;
guess = "ARC console";
- } else if (year >= 70 && year <= 72) {
- epoch = 1928;
- guess = "Digital DECstation";
- } else if (year < 96) {
+ } else if (year >= 48 && year < 70) {
epoch = 1952;
guess = "Digital UNIX";
+ } else if (year >= 70 && year < 100) {
+ epoch = 1928;
+ guess = "Digital DECstation";
}
if (guess)
printk("rtc: %s epoch (%lu) detected\n", guess, epoch);
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 2c512ccbf..a29a904dd 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -39,13 +39,17 @@
*
* 8/99: Generalized PCI support added. Theodore Ts'o
*
+ * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a
+ * few races on freeing buffers too.
+ * Alan Modra <alan@linuxcare.com>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
*/
-static char *serial_version = "4.92";
-static char *serial_revdate = "2000-1-27";
+static char *serial_version = "4.93";
+static char *serial_revdate = "2000-03-20";
/*
* Serial driver configuration section. Here are the various options:
@@ -98,7 +102,7 @@ static char *serial_revdate = "2000-1-27";
#endif
#endif
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
#ifndef ENABLE_SERIAL_PNP
#define ENABLE_SERIAL_PNP
#endif
@@ -133,7 +137,7 @@ static char *serial_revdate = "2000-1-27";
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
-#if (defined(__i386__) && (CPU==386 || CPU==486))
+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
#define SERIAL_INLINE
#endif
@@ -220,7 +224,6 @@ extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
unsigned int minor);
extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
-
static char *serial_name = "Serial driver";
static DECLARE_TASK_QUEUE(tq_serial);
@@ -253,7 +256,7 @@ static unsigned long break_pressed; /* break, really ... */
#endif
static unsigned detect_uart_irq (struct serial_state * state);
-static void autoconfig(struct serial_state * info);
+static void autoconfig(struct serial_state * state);
static void change_speed(struct async_struct *info, struct termios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -321,9 +324,6 @@ static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
@@ -379,7 +379,7 @@ static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
return inb(info->port+1);
#endif
case SERIAL_IO_MEM:
- return readb(info->iomem_base +
+ return readb((unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
#ifdef CONFIG_SERIAL_GSC
case SERIAL_IO_GSC:
@@ -401,7 +401,7 @@ static _INLINE_ void serial_out(struct async_struct *info, int offset,
break;
#endif
case SERIAL_IO_MEM:
- writeb(value, info->iomem_base +
+ writeb(value, (unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
break;
#ifdef CONFIG_SERIAL_GSC
@@ -481,7 +481,9 @@ static void rs_start(struct tty_struct *tty)
return;
save_flags(flags); cli();
- if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+ if (info->xmit.head != info->xmit.tail
+ && info->xmit.buf
+ && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
@@ -633,7 +635,7 @@ static _INLINE_ void receive_chars(struct async_struct *info,
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
{
int count;
-
+
if (info->x_char) {
serial_outp(info, UART_TX, info->x_char);
info->state->icount.tx++;
@@ -642,8 +644,9 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
*intr_done = 0;
return;
}
- if ((info->xmit_cnt <= 0) || info->tty->stopped ||
- info->tty->hw_stopped) {
+ if (info->xmit.head == info->xmit.tail
+ || info->tty->stopped
+ || info->tty->hw_stopped) {
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
return;
@@ -651,14 +654,16 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
count = info->xmit_fifo_size;
do {
- serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+ info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
info->state->icount.tx++;
- if (--info->xmit_cnt <= 0)
+ if (info->xmit.head == info->xmit.tail)
break;
} while (--count > 0);
- if (info->xmit_cnt < WAKEUP_CHARS)
+ if (CIRC_CNT(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
#ifdef SERIAL_DEBUG_INTR
@@ -667,7 +672,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
if (intr_done)
*intr_done = 0;
- if (info->xmit_cnt <= 0) {
+ if (info->xmit.head == info->xmit.tail) {
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
@@ -759,11 +764,11 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt(%d)...", irq);
#endif
-
+
info = IRQ_ports[irq];
if (!info)
return;
-
+
#ifdef CONFIG_SERIAL_MULTIPORT
multi = &rs_multiport[irq];
if (multi->port_monitor)
@@ -833,7 +838,7 @@ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d)...", irq);
#endif
-
+
info = IRQ_ports[irq];
if (!info || !info->tty)
return;
@@ -888,7 +893,7 @@ static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_multi(%d)...", irq);
#endif
-
+
info = IRQ_ports[irq];
if (!info)
return;
@@ -1026,7 +1031,7 @@ static void rs_timer(void)
serial_out(info, UART_IER, info->IER);
info = info->next_port;
} while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT
+#ifdef CONFIG_SERIAL_MULTIPORT
if (rs_multiport[i].port1)
rs_interrupt_multi(i, NULL, NULL);
else
@@ -1117,10 +1122,10 @@ static int startup(struct async_struct * info)
free_page(page);
goto errout;
}
- if (info->xmit_buf)
+ if (info->xmit.buf)
free_page(page);
else
- info->xmit_buf = (unsigned char *) page;
+ info->xmit.buf = (unsigned char *) page;
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttys%d (irq %d)...", info->line, state->irq);
@@ -1298,7 +1303,7 @@ static int startup(struct async_struct * info)
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->xmit.head = info->xmit.tail = 0;
/*
* Set up serial timers...
@@ -1393,9 +1398,10 @@ static void shutdown(struct async_struct * info)
free_irq(state->irq, &IRQ_ports[state->irq]);
}
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
+ if (info->xmit.buf) {
+ unsigned long pg = (unsigned long) info->xmit.buf;
+ info->xmit.buf = 0;
+ free_page(pg);
}
info->IER = 0;
@@ -1570,7 +1576,7 @@ static void change_speed(struct async_struct *info,
* when DLL is 0.
*/
if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
- (info->state->revision == 0x5202))
+ (info->state->revision == 0x5201))
quot++;
info->quot = quot;
@@ -1654,7 +1660,7 @@ static void change_speed(struct async_struct *info,
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
}
serial_outp(info, UART_FCR, fcr); /* set fcr */
- }
+ }
restore_flags(flags);
}
@@ -1666,18 +1672,19 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->device, "rs_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!tty || !info->xmit.buf)
return;
save_flags(flags); cli();
- if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+ if (CIRC_SPACE(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE) == 0) {
restore_flags(flags);
return;
}
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= SERIAL_XMIT_SIZE-1;
- info->xmit_cnt++;
+ info->xmit.buf[info->xmit.head] = ch;
+ info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
restore_flags(flags);
}
@@ -1689,8 +1696,10 @@ static void rs_flush_chars(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
return;
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf)
+ if (info->xmit.head == info->xmit.tail
+ || tty->stopped
+ || tty->hw_stopped
+ || !info->xmit.buf)
return;
save_flags(flags); cli();
@@ -1709,16 +1718,19 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (serial_paranoia_check(info, tty->device, "rs_write"))
return 0;
- if (!tty || !info->xmit_buf || !tmp_buf)
+ if (!tty || !info->xmit.buf || !tmp_buf)
return 0;
save_flags(flags);
if (from_user) {
down(&tmp_buf_sem);
while (1) {
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ int c1;
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
if (c <= 0)
break;
@@ -1729,12 +1741,14 @@ static int rs_write(struct tty_struct * tty, int from_user,
break;
}
cli();
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- info->xmit_head = ((info->xmit_head + c) &
+ c1 = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (c1 < c)
+ c = c1;
+ memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
(SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
restore_flags(flags);
buf += c;
count -= c;
@@ -1742,27 +1756,29 @@ static int rs_write(struct tty_struct * tty, int from_user,
}
up(&tmp_buf_sem);
} else {
+ cli();
while (1) {
- cli();
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
if (c <= 0) {
- restore_flags(flags);
break;
}
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = ((info->xmit_head + c) &
+ memcpy(info->xmit.buf + info->xmit.head, buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
(SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
- restore_flags(flags);
buf += c;
count -= c;
ret += c;
}
+ restore_flags(flags);
}
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
- !(info->IER & UART_IER_THRI)) {
+ if (info->xmit.head != info->xmit.tail
+ && !tty->stopped
+ && !tty->hw_stopped
+ && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
@@ -1772,14 +1788,10 @@ static int rs_write(struct tty_struct * tty, int from_user,
static int rs_write_room(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
- int ret;
-
+
if (serial_paranoia_check(info, tty->device, "rs_write_room"))
return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
static int rs_chars_in_buffer(struct tty_struct *tty)
@@ -1788,7 +1800,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
return 0;
- return info->xmit_cnt;
+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
static void rs_flush_buffer(struct tty_struct *tty)
@@ -1799,7 +1811,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return;
save_flags(flags); cli();
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->xmit.head = info->xmit.tail = 0;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -2071,8 +2083,9 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value)
* interrupt happens).
*/
if (info->x_char ||
- ((info->xmit_cnt > 0) && !info->tty->stopped &&
- !info->tty->hw_stopped))
+ ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+ SERIAL_XMIT_SIZE) > 0) &&
+ !info->tty->stopped && !info->tty->hw_stopped))
result &= TIOCSER_TEMT;
if (copy_to_user(value, &result, sizeof(int)))
@@ -2708,8 +2721,8 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
char_time = char_time / 5;
if (char_time == 0)
char_time = 1;
- if (timeout)
- char_time = MIN(char_time, timeout);
+ if (timeout && timeout < char_time)
+ char_time = timeout;
/*
* If the transmitter hasn't cleared in twice the approximate
* amount of time to send the entire FIFO, it probably won't
@@ -3060,7 +3073,7 @@ static inline int line_info(char *buf, struct serial_state *state)
int ret;
unsigned long flags;
- ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+ ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
state->line, uart_config[state->type].name,
state->port, state->irq);
@@ -3083,9 +3096,9 @@ static inline int line_info(char *buf, struct serial_state *state)
}
save_flags(flags); cli();
status = serial_in(info, UART_MSR);
- control = info ? info->MCR : serial_in(info, UART_MCR);
+ control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
restore_flags(flags);
-
+
stat_buf[0] = 0;
stat_buf[1] = 0;
if (control & UART_MCR_RTS)
@@ -3403,7 +3416,7 @@ static void autoconfig(struct serial_state * state)
state->type = PORT_UNKNOWN;
#ifdef SERIAL_DEBUG_AUTOCONF
- printk("Testing ttyS%d (0x%04x, 0x%04x)...\n", state->line,
+ printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
state->port, (unsigned) state->iomem_base);
#endif
@@ -3743,15 +3756,10 @@ pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
/* enable/disable interrupts */
p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
- if (dev->vendor == PCI_VENDOR_ID_PANACOM) {
- scratch = readl(p + 0x4c);
- if (enable)
- scratch |= 0x40;
- else
- scratch &= ~0x40;
- writel(scratch, p + 0x4c);
- } else
- writel(enable ? 0x41 : 0x00, p + 0x4c);
+ scratch = 0x41;
+ if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+ scratch = 0x43;
+ writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c);
iounmap(p);
if (!enable)
@@ -3806,7 +3814,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
break;
}
- writew(readw(p + 0x28) & data, p + 0x28);
+ writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
iounmap(p);
return 0;
}
@@ -4181,6 +4189,19 @@ static struct pci_board pci_boards[] __initdata = {
{ PCI_VENDOR_ID_USR, 0x1008,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE0, 1, 115200 },
+ /* Titan Electronic cards */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 1, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 2, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 4, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 4, 921600 },
/*
* Untested PCI modems, sent in from various folks...
*/
@@ -4188,10 +4209,9 @@ static struct pci_board pci_boards[] __initdata = {
{ PCI_VENDOR_ID_ROCKWELL, 0x1004,
0x1048, 0x1500,
SPCI_FL_BASE1, 1, 115200 },
-#ifdef CONFIG_DDB5074
+#if 0 /* No definition for PCI_DEVICE_ID_NEC_NILE4 */
/*
* NEC Vrc-5074 (Nile 4) builtin UART.
- * Conditionally compiled in since this is a motherboard device.
*/
{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
PCI_ANY_ID, PCI_ANY_ID,
@@ -4306,18 +4326,41 @@ static void __init probe_serial_pci(void)
#ifdef ENABLE_SERIAL_PNP
static struct pci_board pnp_devices[] __initdata = {
+ /* Motorola VoiceSURFR 56K Modem */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */
{ ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
+ 1, 115200 },
+ /* AZT3005 PnP SOUND DEVICE */
+ { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Best Data Products Inc. Smart One 336F PnP Modem */
+ { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Boca Research 33,600 ACF Modem */
{ ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* Best Data Products Inc. Smart One 336F PnP Modem */
- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
+ /* Creative Modem Blaster Flash56 DI5601-1 */
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Creative Modem Blaster V.90 DI5660 */
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Pace 56 Voice Internal Plug & Play Modem */
+ { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* SupraExpress 28.8 Data/Fax PnP modem */
{ ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* US Robotics Sporster 33600 Modem */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* U.S. Robotics 56K FAX INT */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+
/* These ID's are taken from M$ documentation */
/* Compaq 14400 Modem */
{ ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0,
@@ -4334,6 +4377,24 @@ static struct pci_board pnp_devices[] __initdata = {
{ 0, }
};
+static void inline avoid_irq_share(struct pci_dev *dev)
+{
+ int i, map = 0x1FF8;
+ struct serial_state *state = rs_table;
+ struct isapnp_irq *irq;
+ struct isapnp_resources *res = dev->sysdata;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ if (state->type != PORT_UNKNOWN)
+ clear_bit(state->irq, &map);
+ state++;
+ }
+
+ for ( ; res; res = res->alt)
+ for(irq = res->irq; irq; irq = irq->next)
+ irq->map = map;
+}
+
static void __init probe_serial_pnp(void)
{
struct pci_dev *dev = NULL;
@@ -4352,9 +4413,9 @@ static void __init probe_serial_pnp(void)
for (board = pnp_devices; board->vendor; board++) {
while ((dev = isapnp_find_dev(NULL, board->vendor,
board->device, dev))) {
-
- start_pci_pnp_board(dev, board);
-
+ if (board->flags & SPCI_FL_NO_SHIRQ)
+ avoid_irq_share(dev);
+ start_pci_pnp_board(dev, board);
}
}
@@ -4417,7 +4478,11 @@ int __init rs_init(void)
#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
#endif
+#if (LINUX_VERSION_CODE > 0x2032D)
serial_driver.name = "tts/%d";
+#else
+ serial_driver.name = "ttyS";
+#endif
serial_driver.major = TTY_MAJOR;
serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
serial_driver.num = NR_PORTS;
@@ -4461,7 +4526,11 @@ int __init rs_init(void)
* major number and the subtype code.
*/
callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D)
callout_driver.name = "cua/%d";
+#else
+ callout_driver.name = "cua";
+#endif
callout_driver.major = TTYAUX_MAJOR;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
#if (LINUX_VERSION_CODE >= 131343)
@@ -4503,7 +4572,7 @@ int __init rs_init(void)
&& (state->flags & ASYNC_AUTO_IRQ)
&& (state->port != 0))
state->irq = detect_uart_irq(state);
- printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
+ printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
state->line + SERIAL_DEV_OFFSET,
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
state->port, state->irq,
@@ -4538,7 +4607,7 @@ int __init rs_init(void)
* The port is then probed and if neccessary the IRQ is autodetected
* If this fails an error is returned.
*
- * On success the port is ready to use and the line number is returned.
+ * On success the port is ready to use and the line number is returned.
*/
int register_serial(struct serial_struct *req)
@@ -4548,8 +4617,7 @@ int register_serial(struct serial_struct *req)
struct serial_state *state;
struct async_struct *info;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
for (i = 0; i < NR_PORTS; i++) {
if ((rs_table[i].port == req->port) &&
(rs_table[i].iomem_base == req->iomem_base))
@@ -4568,7 +4636,7 @@ int register_serial(struct serial_struct *req)
state = &rs_table[i];
if (rs_table[i].count) {
restore_flags(flags);
- printk("Couldn't configure serial #%d (port=%d,irq=%d): "
+ printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
"device already open\n", i, req->port, req->irq);
return -1;
}
@@ -4598,12 +4666,11 @@ int register_serial(struct serial_struct *req)
if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
state->irq = detect_uart_irq(state);
- printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+ printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
state->line + SERIAL_DEV_OFFSET,
state->iomem_base ? "iomem" : "port",
state->iomem_base ? (unsigned long)state->iomem_base :
- (unsigned long)state->port,
- state->irq, uart_config[state->type].name);
+ state->port, state->irq, uart_config[state->type].name);
tty_register_devfs(&serial_driver, 0,
serial_driver.minor_start + state->line);
tty_register_devfs(&callout_driver, 0,
@@ -4625,8 +4692,7 @@ void unregister_serial(int line)
unsigned long flags;
struct serial_state *state = &rs_table[line];
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if (state->info && state->info->tty)
tty_hangup(state->info->tty);
state->type = PORT_UNKNOWN;
@@ -4642,12 +4708,7 @@ void unregister_serial(int line)
}
#ifdef MODULE
-int init_module(void)
-{
- return rs_init();
-}
-
-void cleanup_module(void)
+void rs_fini(void)
{
unsigned long flags;
int e1, e2;
@@ -4655,8 +4716,7 @@ void cleanup_module(void)
struct async_struct *info;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
timer_active &= ~(1 << RS_TIMER);
timer_table[RS_TIMER].fn = NULL;
timer_table[RS_TIMER].expires = 0;
@@ -4693,12 +4753,16 @@ void cleanup_module(void)
}
#endif
if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
+ unsigned long pg = (unsigned long) tmp_buf;
tmp_buf = NULL;
+ free_page(pg);
}
}
#endif /* MODULE */
+module_init(rs_init);
+module_exit(rs_fini);
+
/*
* ------------------------------------------------------------
@@ -4960,6 +5024,6 @@ void __init serial_console_init(void)
/*
Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
End:
*/
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 48e426623..67deb7f27 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -28,7 +28,7 @@
extern void wakeup_bdflush(int);
extern void reset_vc(unsigned int);
extern int console_loglevel;
-extern struct vfsmount *vfsmntlist;
+extern struct list_head super_blocks;
/* Machine specific power off function */
void (*sysrq_power_off)(void) = NULL;
@@ -174,22 +174,16 @@ static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard
}
}
-static void go_sync(kdev_t dev, int remount_flag)
+static void go_sync(struct super_block *sb, int remount_flag)
{
printk(KERN_INFO "%sing device %s ... ",
remount_flag ? "Remount" : "Sync",
- kdevname(dev));
+ kdevname(sb->s_dev));
if (remount_flag) { /* Remount R/O */
- struct super_block *sb = get_super(dev);
- struct vfsmount *vfsmnt;
int ret, flags;
struct list_head *p;
- if (!sb) {
- printk("Superblock not found\n");
- return;
- }
if (sb->s_flags & MS_RDONLY) {
printk("R/O\n");
return;
@@ -204,7 +198,7 @@ static void go_sync(kdev_t dev, int remount_flag)
}
file_list_unlock();
DQUOT_OFF(sb);
- fsync_dev(dev);
+ fsync_dev(sb->s_dev);
flags = MS_RDONLY;
if (sb->s_op && sb->s_op->remount_fs) {
ret = sb->s_op->remount_fs(sb, &flags, NULL);
@@ -217,7 +211,7 @@ static void go_sync(kdev_t dev, int remount_flag)
} else
printk("nothing to do\n");
} else {
- fsync_dev(dev); /* Sync only */
+ fsync_dev(sb->s_dev); /* Sync only */
printk("OK\n");
}
}
@@ -233,20 +227,24 @@ int emergency_sync_scheduled;
void do_emergency_sync(void)
{
- struct vfsmount *mnt;
+ struct super_block *sb;
int remount_flag;
lock_kernel();
remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
emergency_sync_scheduled = 0;
- for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
- if (is_local_disk(mnt->mnt_dev))
- go_sync(mnt->mnt_dev, remount_flag);
-
- for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
- if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev))
- go_sync(mnt->mnt_dev, remount_flag);
+ for (sb = sb_entry(super_blocks.next);
+ sb != sb_entry(&super_blocks);
+ sb = sb_entry(sb->s_list.next))
+ if (is_local_disk(sb->s_dev))
+ go_sync(sb, remount_flag);
+
+ for (sb = sb_entry(super_blocks.next);
+ sb != sb_entry(&super_blocks);
+ sb = sb_entry(sb->s_list.next))
+ if (!is_local_disk(sb->s_dev) && MAJOR(sb->s_dev))
+ go_sync(sb, remount_flag);
unlock_kernel();
printk(KERN_INFO "Done.\n");
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index e1e504b79..1e0c22ee6 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2278,9 +2278,6 @@ void __init tty_init(void)
#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
espserial_init();
#endif
-#ifdef CONFIG_SERIAL
- rs_init();
-#endif
#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
vme_scc_init();
#endif
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index 029a76bd4..0ce42945d 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -159,10 +159,6 @@ static int wdt_status(void)
* Handle an interrupt from the board. These are raised when the status
* map changes in what the board considers an interesting way. That means
* a failure condition occuring.
- *
- * FIXME: We need to pass a dev_id as the PCI card can share irqs
- * although its arguably a _very_ dumb idea to share watchdog
- * irq lines
*/
void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -494,7 +490,7 @@ void cleanup_module(void)
int __init wdt_init(void)
{
printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq);
- if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL))
+ if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", &wdt_miscdev))
{
printk(KERN_ERR "IRQ %d is not free.\n", irq);
return -EIO;
diff --git a/drivers/i2c/i2c-algo-pcf.c b/drivers/i2c/i2c-algo-pcf.c
index 39a16825e..3f740784e 100644
--- a/drivers/i2c/i2c-algo-pcf.c
+++ b/drivers/i2c/i2c-algo-pcf.c
@@ -581,7 +581,7 @@ int i2c_pcf_del_bus(struct i2c_adapter *adap)
return 0;
}
-static int __init i2c_algo_pcf_init (void)
+int __init i2c_algo_pcf_init (void)
{
printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n");
return 0;
diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in
index 2d4d2228c..15e1fd52b 100644
--- a/drivers/ide/Config.in
+++ b/drivers/ide/Config.in
@@ -38,11 +38,12 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING $CONFIG_BLK_DEV_AEC6210 $CONFIG_IDEDMA_PCI_WIP
dep_bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+ dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE $CONFIG_BLK_DEV_AMD7409 $CONFIG_IDEDMA_PCI_WIP
dep_bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID $CONFIG_BLK_DEV_CMD64X $CONFIG_IDEDMA_PCI_WIP
- dep_bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 $CONFIG_IDEDMA_PCI_EXPERIMENTAL
+ dep_bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
@@ -53,14 +54,14 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_mbool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
fi
- dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_IDEDMA_PCI_EXPERIMENTAL
+ dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
dep_bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
dep_mbool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER $CONFIG_BLK_DEV_PDC202XX $CONFIG_IDEDMA_PCI_WIP
dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
- dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_IDEDMA_PCI_EXPERIMENTAL
- dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_IDEDMA_PCI_EXPERIMENTAL
+ dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+ dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
fi
if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
diff --git a/drivers/ide/aec6210.c b/drivers/ide/aec6210.c
index cc0aca5fd..cf41fa3d0 100644
--- a/drivers/ide/aec6210.c
+++ b/drivers/ide/aec6210.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/aec6210.c Version 0.05 Feb. 10, 2000
+ * linux/drivers/ide/aec6210.c Version 0.06 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -191,6 +191,7 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
@@ -230,6 +231,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
((id->dma_1word >> 8) & 7) ? ide_dma_on :
ide_dma_off_quietly);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
static void aec6210_tune_drive (ide_drive_t *drive, byte pio)
{
@@ -252,6 +254,7 @@ static void aec6210_tune_drive (ide_drive_t *drive, byte pio)
(void) aec6210_tune_chipset(drive, speed);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -314,6 +317,7 @@ int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_AEC6210_TUNING */
unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
@@ -336,13 +340,13 @@ void __init ide_init_aec6210 (ide_hwif_t *hwif)
{
#ifdef CONFIG_AEC6210_TUNING
hwif->tuneproc = &aec6210_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
- if (hwif->dma_base) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (hwif->dma_base)
hwif->dmaproc = &aec6210_dmaproc;
- } else {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_AEC6210_TUNING */
}
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
index b3ffaa529..ff87917c5 100644
--- a/drivers/ide/ali14xx.c
+++ b/drivers/ide/ali14xx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996
+ * linux/drivers/ide/ali14xx.c Version 0.03 Feb 09, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index bc3d2b9e3..b043d6774 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000
+ * linux/drivers/ide/alim15x3.c Version 0.09 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Michel Aubry, Maintainer
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -37,7 +37,7 @@
static int ali_get_info(char *buffer, char **addr, off_t offset, int count);
extern int (*ali_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-struct pci_dev *bmide_dev;
+static struct pci_dev *bmide_dev;
char *fifo[4] = {
"FIFO Off",
@@ -67,7 +67,7 @@ char *channel_status[8] = {
"error DRQ busy"
};
-static int ali_get_info(char *buffer, char **addr, off_t offset, int count)
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
{
byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
unsigned int bibma;
@@ -356,6 +356,12 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
return (err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ ali15x3_tune_drive(drive, 5);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
{
struct hd_driveid *id = drive->id;
@@ -401,26 +407,21 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
return rval;
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- ali15x3_tune_drive(drive, 5);
-}
-
-
static byte ali15x3_can_ultra (ide_drive_t *drive)
{
+#ifdef CONFIG_WDC_ALI15X3
struct hd_driveid *id = drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
-#if 0
- if (m5229_revision < 0x20) {
-#else
if (m5229_revision <= 0x20) {
-#endif
return 0;
} else if ((m5229_revision < 0xC2) &&
- ((drive->media!=ide_disk) ||
- (chip_is_1543c_e &&
- strstr(id->model, "WDC ")))) {
+#ifdef CONFIG_WDC_ALI15X3
+ ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+ (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+ (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
return 0;
} else {
return 1;
@@ -495,6 +496,7 @@ static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
{
@@ -519,9 +521,11 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
}
#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
- ali_proc = 1;
- bmide_dev = dev;
- ali_display_info = &ali_get_info;
+ if (!ali_proc) {
+ ali_proc = 1;
+ bmide_dev = dev;
+ ali_display_info = &ali_get_info;
+ }
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
return 0;
@@ -666,18 +670,20 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
}
hwif->tuneproc = &ali15x3_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+#ifndef CONFIG_BLK_DEV_IDEDMA
+ hwif->autodma = 0;
+ return;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
/*
* M1543C or newer for DMAing
*/
hwif->dmaproc = &ali15x3_dmaproc;
hwif->autodma = 1;
- } else {
- hwif->autodma = 0;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
}
- return;
}
void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
diff --git a/drivers/ide/amd7409.c b/drivers/ide/amd7409.c
index 7d2018029..2d44044dd 100644
--- a/drivers/ide/amd7409.c
+++ b/drivers/ide/amd7409.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/amd7409.c Version 0.03 Feb. 10, 2000
+ * linux/drivers/ide/amd7409.c Version 0.04 Mar. 18, 2000
*
* Copyright (C) 2000 Andre Hedrick <andre@suse.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -194,49 +194,6 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
return (err);
}
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- byte udma_66 = ((id->hw_config & 0x2000) &&
- (HWIF(drive)->udma_four)) ? 1 : 0;
- byte speed = 0x00;
- int rval;
-
- if ((id->dma_ultra & 0x0010) && (udma_66)) {
- speed = XFER_UDMA_4;
- } else if ((id->dma_ultra & 0x0008) && (udma_66)) {
- speed = XFER_UDMA_3;
- } else if (id->dma_ultra & 0x0004) {
- speed = XFER_UDMA_2;
- } else if (id->dma_ultra & 0x0002) {
- speed = XFER_UDMA_1;
- } else if (id->dma_ultra & 0x0001) {
- speed = XFER_UDMA_0;
- } else if (id->dma_mword & 0x0004) {
- speed = XFER_MW_DMA_2;
- } else if (id->dma_mword & 0x0002) {
- speed = XFER_MW_DMA_1;
- } else if (id->dma_mword & 0x0001) {
- speed = XFER_MW_DMA_0;
- } else {
- return ((int) ide_dma_off_quietly);
- }
-
- (void) amd7409_tune_chipset(drive, speed);
-
- rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
- ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
- ((id->dma_mword >> 8) & 7) ? ide_dma_on :
- ide_dma_off_quietly);
-
- return rval;
-}
-
static void config_chipset_for_pio (ide_drive_t *drive)
{
unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
@@ -288,6 +245,52 @@ static void amd7409_tune_drive (ide_drive_t *drive, byte pio)
(void) amd7409_tune_chipset(drive, speed);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ byte udma_66 = ((id->hw_config & 0x2000) &&
+ (HWIF(drive)->udma_four)) ? 1 : 0;
+ byte speed = 0x00;
+ int rval;
+
+ if ((id->dma_ultra & 0x0010) && (udma_66)) {
+ speed = XFER_UDMA_4;
+ } else if ((id->dma_ultra & 0x0008) && (udma_66)) {
+ speed = XFER_UDMA_3;
+ } else if (id->dma_ultra & 0x0004) {
+ speed = XFER_UDMA_2;
+ } else if (id->dma_ultra & 0x0002) {
+ speed = XFER_UDMA_1;
+ } else if (id->dma_ultra & 0x0001) {
+ speed = XFER_UDMA_0;
+ } else if (id->dma_mword & 0x0004) {
+ speed = XFER_MW_DMA_2;
+ } else if (id->dma_mword & 0x0002) {
+ speed = XFER_MW_DMA_1;
+ } else if (id->dma_mword & 0x0001) {
+ speed = XFER_MW_DMA_0;
+ } else {
+ return ((int) ide_dma_off_quietly);
+ }
+
+ (void) amd7409_tune_chipset(drive, speed);
+
+ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
+
+ return rval;
+}
+
+
+
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -351,6 +354,7 @@ int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name)
{
@@ -370,9 +374,11 @@ unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name)
printk("%s: simplex device: DMA will fail!!\n", name);
}
#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
- amd7409_proc = 1;
- bmide_dev = dev;
- amd7409_display_info = &amd7409_get_info;
+ if (!amd7409_proc) {
+ amd7409_proc = 1;
+ bmide_dev = dev;
+ amd7409_display_info = &amd7409_get_info;
+ }
#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
return 0;
@@ -396,8 +402,17 @@ unsigned int __init ata66_amd7409 (ide_hwif_t *hwif)
void __init ide_init_amd7409 (ide_hwif_t *hwif)
{
hwif->tuneproc = &amd7409_tune_drive;
+
+#ifndef CONFIG_BLK_DEV_IDEDMA
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+ return;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
if (hwif->dma_base) {
hwif->dmaproc = &amd7409_dmaproc;
+ hwif->autodma = 1;
} else {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
index 3e1cfcd33..da53155c1 100644
--- a/drivers/ide/buddha.c
+++ b/drivers/ide/buddha.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/buddha.c -- Amiga Buddha and Catweasel IDE Driver
+ * linux/drivers/ide/buddha.c -- Amiga Buddha and Catweasel IDE Driver
*
* Copyright (C) 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
index b2077df6d..7a094d497 100644
--- a/drivers/ide/cmd640.c
+++ b/drivers/ide/cmd640.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996
+ * linux/drivers/ide/cmd640.c Version 1.02 Sep 01, 1996
*
* Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index b2ae2e6b8..2aaf83b26 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -1,5 +1,7 @@
/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
*
+ * linux/drivers/ide/cmd64x.c Version 1.21 Mar. 18, 2000
+ *
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
* Note, this driver is not used at all on other systems because
* there the "BIOS" has done all of the following already.
@@ -116,19 +118,27 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
p += sprintf(p, " %sabled %sabled\n",
- (reg72&0x80) ? "dis" : " en", (reg7a&0x80) ? "dis" : " en");
+ (reg72&0x80)?"dis":" en",(reg7a&0x80)?"dis":" en");
p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (reg72&0x20) ? "yes" : "no ", (reg72&0x40) ? "yes" : "no ", (reg7a&0x20) ? "yes" : "no ", (reg7a&0x40) ? "yes" : "no " );
+ (reg72&0x20)?"yes":"no ",(reg72&0x40)?"yes":"no ",(reg7a&0x20)?"yes":"no ",(reg7a&0x40)?"yes":"no ");
p += sprintf(p, "DMA Mode: %s(%s) %s(%s) %s(%s) %s(%s)\n",
(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
- (reg72&0x20)?(((reg73&0x15)==0x15)?"4":((reg73&0x25)==0x25)?"3":((reg73&0x10)==0x10)?"2":((reg73&0x20)==0x20)?"1":((reg73&0x30)==0x30)?"0":"X"):"?",
+ (reg72&0x20)?( ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+ ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+ ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):"X"):"?",
(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
- (reg72&0x40)?(((reg73&0x4A)==0x4A)?"4":((reg73&0x8A)==0x8A)?"3":((reg73&0x40)==0x40)?"2":((reg73&0x80)==0x80)?"1":((reg73&0xC0)==0xC0)?"0":"X"):"?",
+ (reg72&0x40)?( ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+ ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+ ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):"X"):"?",
(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
- (reg7a&0x20)?(((reg7b&0x15)==0x15)?"4":((reg7b&0x25)==0x25)?"3":((reg7b&0x10)==0x10)?"2":((reg7b&0x20)==0x20)?"1":((reg7b&0x30)==0x30)?"0":"X"):"?",
+ (reg7a&0x20)?( ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+ ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+ ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):"X"):"?",
(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
- (reg7a&0x40)?(((reg7b&0x4A)==0x4A)?"4":((reg7b&0x8A)==0x8A)?"3":((reg7b&0x40)==0x40)?"2":((reg7b&0x80)==0x80)?"1":((reg7b&0xC0)==0xC0)?"0":"X"):"?" );
+ (reg7a&0x40)?( ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+ ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+ ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):"X"):"?" );
p += sprintf(p, "PIO Mode: %s %s %s %s\n",
"?", "?", "?", "?");
@@ -155,6 +165,22 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
return p-buffer; /* => must be less than 4k! */
}
+
+#if 0
+static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
+{
+ char *p = buf;
+ p += sprintf(p, "thingy stuff\n");
+ return (char *)p;
+}
+static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ p = cmd64x_chipset_data(buffer, bmide_dev);
+ return p-buffer; /* hoping it is less than 4K... */
+}
+#endif
+
#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
byte cmd64x_proc = 0;
@@ -305,76 +331,60 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
setup_count, active_count, recovery_count);
}
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ byte speed= 0x00;
+ byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+ cmd64x_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int tune_chipset_for_dma (ide_drive_t *drive, byte speed)
{
-#if 0
- struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- unsigned long dma_base = hwif->dma_base;
byte unit = (drive->select.b.unit & 0x01);
-
- u8 reg72 = 0, reg73 = 0; /* primary */
- u8 reg7a = 0, reg7b = 0; /* secondary */
- u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
- u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
- u8 regU = (hwif->channel) ? 2 : 0;
- u8 regD = (hwif->channel) ? 2 : 0;
-
- (void) pci_read_config_byte(dev, BMIDESR0, &reg72);
- (void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
- (void) pci_read_config_byte(dev, BMIDESR1, &reg7a);
- (void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
-
+ int err = 0;
+
+ u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+ u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+ u8 regU = 0;
+ u8 regD = 0;
+
+ (void) pci_read_config_byte(dev, pciD, &regD);
+ (void) pci_read_config_byte(dev, pciU, &regU);
+ regD &= ~(unit ? 0x40 : 0x20);
+ regU &= ~(unit ? 0xCA : 0x35);
+ (void) pci_write_config_byte(dev, pciD, regD);
+ (void) pci_write_config_byte(dev, pciU, regU);
+
+ (void) pci_read_config_byte(dev, pciD, &regD);
+ (void) pci_read_config_byte(dev, pciU, &regU);
switch(speed) {
- case XFER_UDMA_4:
- pciU = unit ? 0x4A : 0x15;
- case XFER_UDMA_3:
- pciU = unit ? 0x8A : 0x25;
- case XFER_UDMA_2:
- pciU = unit ? 0x42 : 0x11;
- case XFER_UDMA_1:
- pciU = unit ? 0x82 : 0x21;
- case XFER_UDMA_0:
- pciU = unit ? 0xC2 : 0x31
-(reg73&0x15)?"4":(reg73&0x25)?"3":(reg73&0x11)?"2":(reg73&0x21)?"1":(reg73&0x31)?"0":"X",
-(reg73&0x4A)?"4":(reg73&0x8A)?"3":(reg73&0x42)?"2":(reg73&0x82)?"1":(reg73&0xC2)?"0":"X",
-(reg7b&0x15)?"4":(reg7b&0x25)?"3":(reg7b&0x11)?"2":(reg7b&0x21)?"1":(reg7b&0x31)?"0":"X",
-(reg7b&0x4A)?"4":(reg7b&0x8A)?"3":(reg7b&0x42)?"2":(reg7b&0x82)?"1":(reg7b&0xC2)?"0":"X",
-
- case XFER_MW_DMA_2:
- pciD = unit ? 0x40 : 0x10;
- case XFER_MW_DMA_1:
- pciD = unit ? 0x80 : 0x20;
- case XFER_MW_DMA_0:
- pciD = unit ? 0xC0 : 0x30;
- case XFER_SW_DMA_2:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
-(reg73&0x10)?"2":(reg73&0x20)?"1":(reg73&0x30)?"0":"X",
-(reg73&0x40)?"2":(reg73&0x80)?"1":(reg73&0xC0)?"0":"X",
-(reg7b&0x10)?"2":(reg7b&0x20)?"1":(reg7b&0x30)?"0":"X",
-(reg7b&0x40)?"2":(reg7b&0x80)?"1":(reg7b&0xC0)?"0":"X" );
-
+ case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break;
+ case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break;
+ case XFER_UDMA_2: regU |= (unit ? 0x42 : 0x11); break;
+ case XFER_UDMA_1: regU |= (unit ? 0x82 : 0x21); break;
+ case XFER_UDMA_0: regU |= (unit ? 0xC2 : 0x31); break;
+ case XFER_MW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
+ case XFER_MW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
+ case XFER_MW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
+ case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
+ case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
+ case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
default:
return 1;
}
+ (void) pci_write_config_byte(dev, pciU, regU);
+ err = ide_config_drive_speed(drive, speed);
+ regD |= (unit ? 0x40 : 0x20);
+ (void) pci_write_config_byte(dev, pciD, regD);
- (void) ide_config_drive_speed(drive, speed);
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-#endif
- return 0;
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
- byte speed = 0x00;
- byte set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
-
- cmd64x_tuneproc(drive, set_pio);
- speed = XFER_PIO_0 + set_pio;
- if (set_speed)
- (void) ide_config_drive_speed(drive, speed);
+ return err;
}
static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
@@ -382,21 +392,17 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- unsigned long dma_base = hwif->dma_base;
- byte unit = (drive->select.b.unit & 0x01);
byte speed = 0x00;
byte set_pio = 0x00;
- byte udma_timing_bits = 0x00;
byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
- /* int drive_number = ((hwif->channel ? 2 : 0) + unit); */
int rval;
switch(dev->device) {
- case PCI_DEVICE_ID_CMD_643:
- case PCI_DEVICE_ID_CMD_646:
case PCI_DEVICE_ID_CMD_648:
+ case PCI_DEVICE_ID_CMD_646:
+ case PCI_DEVICE_ID_CMD_643:
default:
break;
}
@@ -416,22 +422,16 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
* in the 646U2.
* So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
*/
-
if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
speed = XFER_UDMA_4;
- udma_timing_bits = 0x10; /* 2 clock */
} else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
speed = XFER_UDMA_3;
- udma_timing_bits = 0x20; /* 3 clock */
} else if ((id->dma_ultra & 0x0004) && (udma_33)) {
speed = XFER_UDMA_2;
- udma_timing_bits = 0x10; /* 2 clock */
} else if ((id->dma_ultra & 0x0002) && (udma_33)) {
speed = XFER_UDMA_1;
- udma_timing_bits = 0x20; /* 3 clock */
} else if ((id->dma_ultra & 0x0001) && (udma_33)) {
speed = XFER_UDMA_0;
- udma_timing_bits = 0x30; /* 4 clock */
} else if (id->dma_mword & 0x0004) {
speed = XFER_MW_DMA_2;
} else if (id->dma_mword & 0x0002) {
@@ -453,27 +453,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
if (set_pio)
return ((int) ide_dma_off_quietly);
-#if 1
- /*
- * This the alternate access method. :-(
- * The correct method is to directly setup the pci-config space.
- */
- (void) ide_config_drive_speed(drive, speed);
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-
- if (speed >= XFER_UDMA_0) {
- byte udma_ctrl = inb(dma_base + 3);
- /* Put this channel into UDMA mode. */
- udma_ctrl |= (1 << unit);
- udma_ctrl &= ~(0x04 << unit);
- if (udma_66)
- udma_ctrl |= (0x04 << unit);
- udma_ctrl &= ~(0x30 << (unit * 2));
- udma_ctrl |= (udma_timing_bits << (unit * 2));
- outb(udma_ctrl, dma_base+3);
- }
-#endif
-
if (tune_chipset_for_dma(drive, speed))
return ((int) ide_dma_off);
@@ -500,17 +479,14 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
class_rev &= 0xff;
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
+ can_ultra_66 = 1;
case PCI_DEVICE_ID_CMD_643:
- can_ultra_33 = 1;
- can_ultra_66 = 0;
+ can_ultra_33 = 1;
break;
case PCI_DEVICE_ID_CMD_646:
- can_ultra_33 = (class_rev >= 0x05) ? 1 : 0;
- can_ultra_66 = 0;
- break;
- case PCI_DEVICE_ID_CMD_648:
- can_ultra_33 = 1;
- can_ultra_66 = 1;
+ can_ultra_33 = (class_rev >= 0x05) ? 1 : 0;
+ can_ultra_66 = 0;
break;
default:
return hwif->dmaproc(ide_dma_off, drive);
@@ -595,6 +571,7 @@ static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/* Other cases are done by generic IDE-DMA code. */
return cmd64x_dmaproc(func, drive);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
{
@@ -604,9 +581,11 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
-#if 0
- if (dev->resource[PCI_ROM_RESOURCE].start)
+#ifdef __i386__
+ if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+ }
#endif
switch(dev->device) {
@@ -702,7 +681,9 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
+#ifdef CONFIG_BLK_DEV_IDEDMA
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
case PCI_DEVICE_ID_CMD_643:
hwif->dmaproc = &cmd64x_dmaproc;
break;
@@ -714,10 +695,8 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
hwif->dmaproc = &cmd64x_dmaproc;
}
break;
- case PCI_DEVICE_ID_CMD_648:
- hwif->dmaproc = &cmd64x_dmaproc;
- break;
default:
break;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
index bb68f7b2e..b160d7716 100644
--- a/drivers/ide/cs5530.c
+++ b/drivers/ide/cs5530.c
@@ -1,5 +1,8 @@
/*
- * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000
+ * linux/drivers/ide/cs5530.c Version 0.6 Mar. 18, 2000
+ *
+ * Copyright (C) 2000 Andre Hedrick <andre@suse.com>
+ * Ditto of GNU General Public License.
*
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -23,6 +26,7 @@
#include <linux/ide.h>
#include <asm/io.h>
#include <asm/irq.h>
+
#include "ide_modes.h"
#define DISPLAY_CS5530_TIMINGS
@@ -120,6 +124,7 @@ static void cs5530_tuneproc (ide_drive_t *drive, byte pio) /* pio=255 means "aut
}
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* cs5530_config_dma() handles selection/setting of DMA/UDMA modes
* for both the chipset and drive.
@@ -241,6 +246,7 @@ int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/* Other cases are done by generic IDE-DMA code. */
return ide_dmaproc(func, drive);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* Initialize the cs5530 bridge for reliable IDE DMA operation.
@@ -322,9 +328,11 @@ unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
restore_flags(flags);
#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
- cs5530_proc = 1;
- bmide_dev = dev;
- cs5530_display_info = &cs5530_get_info;
+ if (!cs5530_proc) {
+ cs5530_proc = 1;
+ bmide_dev = dev;
+ cs5530_display_info = &cs5530_get_info;
+ }
#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
return 0;
@@ -343,7 +351,12 @@ void __init ide_init_cs5530 (ide_hwif_t *hwif)
} else {
unsigned int basereg, d0_timings;
+#ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &cs5530_dmaproc;
+#else
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
hwif->tuneproc = &cs5530_tuneproc;
basereg = CS5530_BASEREG(hwif);
d0_timings = inl(basereg+0);
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
index cfff0381c..4498b754b 100644
--- a/drivers/ide/cy82c693.c
+++ b/drivers/ide/cy82c693.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999
+ * linux/drivers/ide/cy82c693.c Version 0.34 Dec. 13, 1999
*
* Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer
* Copyright (C) 1998-99 Andre Hedrick, Integrater
@@ -44,6 +44,7 @@
*
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -176,6 +177,7 @@ static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
p_pclk->time_8 = (byte)clk1;
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* set DMA mode a specific channel for CY82C693
*/
@@ -262,6 +264,7 @@ static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* tune ide drive - set PIO mode
@@ -432,10 +435,14 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif)
{
hwif->chipset = ide_cy82c693;
hwif->tuneproc = &cy82c693_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &cy82c693_dmaproc;
- } else {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->autodma = 1;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
index d8838e111..28537d048 100644
--- a/drivers/ide/dtc2278.c
+++ b/drivers/ide/dtc2278.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996
+ * linux/drivers/ide/dtc2278.c Version 0.02 Feb 10, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c
index 7bce07517..096d75fc0 100644
--- a/drivers/ide/falconide.c
+++ b/drivers/ide/falconide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/falconide.c -- Atari Falcon IDE Driver
+ * linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
*
* Created 12 Jul 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
index 29cceb20e..170bf16f7 100644
--- a/drivers/ide/gayle.c
+++ b/drivers/ide/gayle.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/gayle.c -- Amiga Gayle IDE Driver
+ * linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
*
* Created 9 Jul 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c
index 5520c17b0..b64a9738c 100644
--- a/drivers/ide/hd.c
+++ b/drivers/ide/hd.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/hd.c
+ * linux/drivers/ide/hd.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
diff --git a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
index 425ce35a4..a68e7f740 100644
--- a/drivers/ide/hpt34x.c
+++ b/drivers/ide/hpt34x.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/hpt34x.c Version 0.29 Feb. 10, 2000
+ * linux/drivers/ide/hpt34x.c Version 0.30 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -144,6 +144,59 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+
+ byte timing, speed, pio;
+
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ switch(timing) {
+ 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;
+ }
+ (void) hpt34x_tune_chipset(drive, speed);
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+
+ 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 = XFER_PIO_0;break;
+ }
+ hpt34x_clear_chipset(drive);
+ (void) hpt34x_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* This allows the configuration of ide_pci chipset registers
* for cards that learn about the drive's UDMA, DMA, PIO capabilities
@@ -195,58 +248,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
ide_dma_off_quietly);
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
-
- byte timing, speed, pio;
-
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
- switch(timing) {
- 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;
- }
- (void) hpt34x_tune_chipset(drive, speed);
-}
-
-static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
-{
- byte speed;
-
- 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 = XFER_PIO_0;break;
- }
- hpt34x_clear_chipset(drive);
- (void) hpt34x_tune_chipset(drive, speed);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -347,6 +348,7 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* If the BIOS does not set the IO base addaress to XX00, 343 will fail.
@@ -395,9 +397,11 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
__restore_flags(flags); /* local CPU only */
#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
- hpt34x_proc = 1;
- bmide_dev = dev;
- hpt34x_display_info = &hpt34x_get_info;
+ if (!hpt34x_proc) {
+ hpt34x_proc = 1;
+ bmide_dev = dev;
+ hpt34x_display_info = &hpt34x_get_info;
+ }
#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
return dev->irq;
@@ -406,6 +410,8 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
void __init ide_init_hpt34x (ide_hwif_t *hwif)
{
hwif->tuneproc = &hpt34x_tune_drive;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
unsigned short pcicmd = 0;
@@ -416,4 +422,9 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif)
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index d2f2fb433..fd5971ef9 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/hpt366.c Version 0.16 Feb. 10, 2000
+ * linux/drivers/ide/hpt366.c Version 0.17 Mar. 18, 2000
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -259,6 +259,64 @@ static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ byte timing, speed, pio;
+
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_pio\n", drive->name);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 :
+ (drive->id->tPIO & 2) ? 0x02 :
+ (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ switch(timing) {
+ 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;
+ }
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+ (void) hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt366_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+ 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 = XFER_PIO_0;break;
+ }
+ (void) hpt366_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* This allows the configuration of ide_pci chipset registers
* for cards that learn about the drive's UDMA, DMA, PIO capabilities
@@ -347,63 +405,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
return rval;
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
- byte timing, speed, pio;
-
-#if HPT366_DEBUG_DRIVE_INFO
- printk("%s: config_chipset_for_pio\n", drive->name);
-#endif /* HPT366_DEBUG_DRIVE_INFO */
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 :
- (drive->id->tPIO & 2) ? 0x02 :
- (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
- switch(timing) {
- 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;
- }
-#if HPT366_DEBUG_DRIVE_INFO
- printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed);
-#endif /* HPT366_DEBUG_DRIVE_INFO */
- (void) hpt366_tune_chipset(drive, speed);
-}
-
-static void hpt366_tune_drive (ide_drive_t *drive, byte pio)
-{
- byte speed;
- 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 = XFER_PIO_0;break;
- }
- (void) hpt366_tune_chipset(drive, speed);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -478,6 +479,7 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
{
@@ -532,13 +534,20 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
void __init ide_init_hpt366 (ide_hwif_t *hwif)
{
hwif->tuneproc = &hpt366_tune_drive;
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &hpt366_dmaproc;
+ hwif->autodma = 1;
} else {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
index 6b7d5af72..1c0b55dac 100644
--- a/drivers/ide/ht6560b.c
+++ b/drivers/ide/ht6560b.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ht6560b.c Version 0.07 Feb 1, 2000
+ * linux/drivers/ide/ht6560b.c Version 0.07 Feb 1, 2000
*
* Copyright (C) 1995-2000 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index d0e8f8328..213ddbff0 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/icside.c
+ * linux/drivers/ide/icside.c
*
* Copyright (c) 1996,1997 Russell King.
*
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 641783e9c..17cc3eb88 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1,5 +1,6 @@
/*
- * linux/drivers/block/ide-cd.c
+ * linux/drivers/ide/ide-cd.c
+ *
* Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov>
* Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
* Copyright (C) 1998, 1999 Jens Axboe <axboe@image.dk>
@@ -276,6 +277,7 @@
#define IDECD_VERSION "4.56"
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -2400,21 +2402,10 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size));
- if (drive->using_dma) {
- if ((drive->id->field_valid & 4) &&
- (drive->id->hw_config & 0x2000) &&
- (HWIF(drive)->udma_four) &&
- (drive->id->dma_ultra & (drive->id->dma_ultra >> 11) & 3)) {
- printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
- } else if ((drive->id->field_valid & 4) &&
- (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) {
- printk(", UDMA(33)"); /* UDMA BIOS-enabled! */
- } else if (drive->id->field_valid & 4) {
- printk(", (U)DMA"); /* Can be BIOS-enabled! */
- } else {
- printk(", DMA");
- }
- }
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (drive->using_dma)
+ (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
return nslots;
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index 1eb48ef6c..77937dd4b 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide_cd.h
+ * linux/drivers/ide/ide_cd.h
*
* Copyright (C) 1996-98 Erik Andersen
* Copyright (C) 1998-2000 Jens Axboe
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 2ef50f285..33014bc06 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999
+ * linux/drivers/ide/ide-disk.c Version 1.09 April 23, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -821,21 +821,10 @@ static void idedisk_setup (ide_drive_t *drive)
drive->name, id->model,
capacity/2048L, id->buf_size/2,
drive->bios_cyl, drive->bios_head, drive->bios_sect);
-
- if (drive->using_dma) {
- if ((id->field_valid & 4) && (id->hw_config & 0x2000) &&
- (HWIF(drive)->udma_four) &&
- (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
- printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
- } else if ((id->field_valid & 4) &&
- (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
- printk(", UDMA(33)"); /* UDMA BIOS-enabled! */
- } else if (id->field_valid & 4) {
- printk(", (U)DMA"); /* Can be BIOS-enabled! */
- } else {
- printk(", DMA");
- }
- }
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (drive->using_dma)
+ (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
drive->mult_count = 0;
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 751424831..9caffd2f1 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999
+ * linux/drivers/ide/ide-dma.c Version 4.09 April 23, 1999
*
* Copyright (c) 1999 Andre Hedrick
* May be copied or modified under the terms of the GNU General Public License
@@ -354,6 +354,29 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
return 0;
}
+int report_drive_dmaing (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+ if ((id->field_valid & 4) && (id->hw_config & 0x2000) &&
+ (HWIF(drive)->udma_four) &&
+ (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
+ if ((id->dma_ultra >> 12) & 1) {
+ printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
+ } else {
+ printk(", UDMA(44)"); /* UDMA BIOS-enabled! */
+ }
+ } else if ((id->field_valid & 4) &&
+ (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+ printk(", UDMA(33)"); /* UDMA BIOS-enabled! */
+ } else if (id->field_valid & 4) {
+ printk(", (U)DMA"); /* Can be BIOS-enabled! */
+ } else {
+ printk(", DMA");
+ }
+ return 1;
+}
+
static int config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -453,6 +476,9 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
case ide_dma_bad_drive:
case ide_dma_good_drive:
return check_drive_lists(drive, (func == ide_dma_good_drive));
+ case ide_dma_verbose:
+ return report_drive_dmaing(drive);
+ case ide_dma_retune:
case ide_dma_lostirq:
case ide_dma_timeout:
printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func);
diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
index 3f29ed591..371f57ad8 100644
--- a/drivers/ide/ide-features.c
+++ b/drivers/ide/ide-features.c
@@ -100,6 +100,8 @@ char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
case ide_dma_test_irq: return("ide_dma_test_irq");
case ide_dma_bad_drive: return("ide_dma_bad_drive");
case ide_dma_good_drive: return("ide_dma_good_drive");
+ case ide_dma_verbose: return("ide_dma_verbose");
+ case ide_dma_retune: return("ide_dma_retune");
case ide_dma_lostirq: return("ide_dma_lostirq");
case ide_dma_timeout: return("ide_dma_timeout");
default: return("unknown");
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 58eb2411d..55349e92a 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999
+ * linux/drivers/ide/ide-floppy.c Version 0.9 Jul 4, 1999
*
* Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
*/
diff --git a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
index 4c67d0911..29de5bb09 100644
--- a/drivers/ide/ide-geometry.c
+++ b/drivers/ide/ide-geometry.c
@@ -1,9 +1,9 @@
/*
- * linux/drivers/block/ide-geometry.c
+ * linux/drivers/ide/ide-geometry.c
*/
#include <linux/config.h>
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_IDE
#include <linux/ide.h>
#include <asm/io.h>
@@ -211,4 +211,4 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
drive->bios_cyl, drive->bios_head, drive->bios_sect);
return ret;
}
-#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif /* CONFIG_IDE */
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index f667ee6dd..cdd10f6e1 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999
+ * linux/drivers/ide/ide-pci.c Version 1.04 July 27, 1999
*
- * Copyright (c) 1998-1999 Andre Hedrick
+ * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org>
*
* Copyright (c) 1995-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
index e0803e6fa..7f5226db9 100644
--- a/drivers/ide/ide-pmac.c
+++ b/drivers/ide/ide-pmac.c
@@ -1,4 +1,6 @@
/*
+ * linux/drivers/ide/ide-pmac.c Version ?.?? Mar. 18, 2000
+ *
* Support for IDE interfaces on PowerMacs.
* These IDE interfaces are memory-mapped and have a DBDMA channel
* for doing DMA.
@@ -10,7 +12,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Some code taken from drivers/block/ide-dma.c:
+ * Some code taken from drivers/ide/ide-dma.c:
*
* Copyright (c) 1995-1998 Mark Lord
*
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index ffa3ade56..d8edb89c5 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-pnp.c
+ * linux/drivers/ide/ide-pnp.c
*
* This file provides autodetection for ISA PnP IDE interfaces.
* It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 0e617216d..200204ee6 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999
+ * linux/drivers/ide/ide-probe.c Version 1.05 July 3, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 753597e9c..fd33e4e42 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998
+ * linux/drivers/ide/ide-proc.c Version 1.03 January 2, 1998
*
* Copyright (C) 1997-1998 Mark Lord
*/
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 95e780abf..c4424cf90 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999
+ * linux/drivers/ide/ide-tape.c Version 1.16f Dec 15, 1999
*
* Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
*
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 9c409dfb6..89921f7b9 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.30 Dec 28, 1999
+ * linux/drivers/ide/ide.c Version 6.30 Dec 28, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -1809,9 +1809,9 @@ static void revalidate_drives (void)
static void ide_probe_module (void)
{
if (!ide_probe) {
-#ifdef CONFIG_KMOD
+#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
(void) request_module("ide-probe-mod");
-#endif /* CONFIG_KMOD */
+#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */
} else {
(void) ide_probe->init();
}
@@ -2491,6 +2491,30 @@ static int ide_ioctl (struct inode *inode, struct file *file,
return 0;
}
+ case HDIO_GETGEO_BIG:
+ {
+ struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+ if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
+ if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
+ if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+ if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+ (unsigned long *) &loc->start)) return -EFAULT;
+ return 0;
+ }
+
+ case HDIO_GETGEO_BIG_RAW:
+ {
+ struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+ if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
+ if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+ if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+ if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+ (unsigned long *) &loc->start)) return -EFAULT;
+ return 0;
+ }
+
case BLKGETSIZE: /* Return device size */
return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
@@ -2564,8 +2588,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
}
case HDIO_UNREGISTER_HWIF:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- /* should I check here for arg > MAX_HWIFS, or
- just let ide_unregister fail silently? -- shaver */
+ /* (arg > MAX_HWIFS) checked in function */
ide_unregister(arg);
return 0;
case HDIO_SET_NICE:
diff --git a/drivers/ide/ide_modes.h b/drivers/ide/ide_modes.h
index f94d91313..ff71b2c2c 100644
--- a/drivers/ide/ide_modes.h
+++ b/drivers/ide/ide_modes.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide_modes.h
+ * linux/drivers/ide/ide_modes.h
*
* Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord
*/
diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
index 0e5675fde..7a24fce25 100644
--- a/drivers/ide/ns87415.c
+++ b/drivers/ide/ns87415.c
@@ -1,12 +1,14 @@
/*
- * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997
+ * linux/drivers/ide/ns87415.c Version 1.01 Mar. 18, 2000
*
- * Copyright (C) 1997-1998 Mark Lord
- * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com>
+ * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be>
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com>
*
- * Inspired by an earlier effort from David S. Miller (davem@caipfs.rutgers.edu)
+ * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/timer.h>
@@ -78,6 +80,7 @@ static void ns87415_selectproc (ide_drive_t *drive)
ns87415_prepare_drive (drive, drive->using_dma);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -106,6 +109,7 @@ static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
void __init ide_init_ns87415 (ide_hwif_t *hwif)
{
@@ -179,7 +183,10 @@ void __init ide_init_ns87415 (ide_hwif_t *hwif)
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* share IRQ with mate */
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base)
hwif->dmaproc = &ns87415_dmaproc;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
hwif->selectproc = &ns87415_selectproc;
}
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
index cc2aa567c..277f2f490 100644
--- a/drivers/ide/opti621.c
+++ b/drivers/ide/opti621.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999
+ * linux/drivers/ide/opti621.c Version 0.6 Jan 02, 1999
*
* Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
index 9ec7c8997..b93c6ad1b 100644
--- a/drivers/ide/pdc202xx.c
+++ b/drivers/ide/pdc202xx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/pdc202xx.c Version 0.29 Feb. 10, 2000
+ * linux/drivers/ide/pdc202xx.c Version 0.30 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -9,6 +9,9 @@
* Note that BIOS v1.29 is reported to fix the problem. Since this is
* safe chipset tuning, including this support is harmless
*
+ * Promise Ultra66 cards with BIOS v1.11 this
+ * compiled into the kernel if you have more than one card installed.
+ *
* The latest chipset code will support the following ::
* Three Ultra33 controllers and 12 drives.
* 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
@@ -16,60 +19,6 @@
*
* UNLESS you enable "CONFIG_PDC202XX_BURST"
*
- * There is only one BIOS in the three contollers.
- *
- * May 8 20:56:17 Orion kernel:
- * Uniform Multi-Platform E-IDE driver Revision: 6.19
- * PDC20246: IDE controller on PCI bus 00 dev a0
- * PDC20246: not 100% native mode: will probe irqs later
- * PDC20246: ROM enabled at 0xfebd0000
- * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
- * ide0: BM-DMA at 0xef80-0xef87, BIOS settings: hda:DMA, hdb:DMA
- * ide1: BM-DMA at 0xef88-0xef8f, BIOS settings: hdc:pio, hdd:pio
- * PDC20246: IDE controller on PCI bus 00 dev 98
- * PDC20246: not 100% native mode: will probe irqs later
- * PDC20246: ROM enabled at 0xfebc0000
- * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
- * ide2: BM-DMA at 0xef40-0xef47, BIOS settings: hde:DMA, hdf:DMA
- * ide3: BM-DMA at 0xef48-0xef4f, BIOS settings: hdg:DMA, hdh:DMA
- * PDC20246: IDE controller on PCI bus 00 dev 90
- * PDC20246: not 100% native mode: will probe irqs later
- * PDC20246: ROM enabled at 0xfebb0000
- * PDC20246: (U)DMA Burst Bit DISABLED Primary PCI Mode Secondary PCI Mode.
- * PDC20246: FORCING BURST BIT 0x00 -> 0x01 ACTIVE
- * ide4: BM-DMA at 0xef00-0xef07, BIOS settings: hdi:DMA, hdj:pio
- * ide5: BM-DMA at 0xef08-0xef0f, BIOS settings: hdk:pio, hdl:pio
- * PIIX3: IDE controller on PCI bus 00 dev 39
- * PIIX3: device not capable of full native PCI mode
- *
- * ide0 at 0xeff0-0xeff7,0xefe6 on irq 19
- * ide1 at 0xefa8-0xefaf,0xebe6 on irq 19
- * ide2 at 0xefa0-0xefa7,0xef7e on irq 18
- * ide3 at 0xef68-0xef6f,0xef66 on irq 18
- * ide4 at 0xef38-0xef3f,0xef62 on irq 17
- * hda: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=13328/15/63, UDMA(33)
- * hdb: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=6256/16/63, UDMA(33)
- * hde: Maxtor 72004 AP, 1916MB w/128kB Cache, CHS=3893/16/63, DMA
- * hdf: Maxtor 71626 A, 1554MB w/64kB Cache, CHS=3158/16/63, DMA
- * hdi: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33)
- * hdj: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33)
- *
- * Promise Ultra66 cards with BIOS v1.11 this
- * compiled into the kernel if you have more than one card installed.
- *
- * PDC20262: IDE controller on PCI bus 00 dev a0
- * PDC20262: not 100% native mode: will probe irqs later
- * PDC20262: ROM enabled at 0xfebb0000
- * PDC20262: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
- * ide0: BM-DMA at 0xef00-0xef07, BIOS settings: hda:pio, hdb:pio
- * ide1: BM-DMA at 0xef08-0xef0f, BIOS settings: hdc:pio, hdd:pio
- *
- * UDMA 4/2 and UDMA 3/1 only differ by the testing bit 13 in word93.
- * Chipset timing speeds must be identical
- *
- * drive_number
- * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
*/
/*
@@ -100,7 +49,7 @@
#define PDC202XX_DEBUG_DRIVE_INFO 0
#define PDC202XX_DECODE_REGISTER_INFO 0
-#undef DISPLAY_PDC202XX_TIMINGS
+#define DISPLAY_PDC202XX_TIMINGS
#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
@@ -111,13 +60,56 @@ extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c
extern char *ide_media_verbose(ide_drive_t *);
static struct pci_dev *bmide_dev;
+char *pdc202xx_pio_verbose (u32 drive_pci)
+{
+ if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+ if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+ if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+ if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+ if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+ if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+ return("PIO ?");
+}
+
+char *pdc202xx_dma_verbose (u32 drive_pci)
+{
+ if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+ if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+ if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+ if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+ if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+ if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+ return("PIO---");
+}
+
+char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+ if ((drive_pci & 0x000ff000) == 0x000ff000)
+ return("NOTSET");
+ if ((drive_pci & 0x00012000) == 0x00012000)
+ return((slow_cable) ? "UDMA 2" : "UDMA 4");
+ if ((drive_pci & 0x00024000) == 0x00024000)
+ return((slow_cable) ? "UDMA 1" : "UDMA 3");
+ if ((drive_pci & 0x00036000) == 0x00036000)
+ return("UDMA 0");
+ return(pdc202xx_dma_verbose(drive_pci));
+}
+
static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
u32 bibma = bmide_dev->resource[4].start;
+ u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+ u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
u8 c0 = 0, c1 = 0;
+ pci_read_config_word(bmide_dev, 0x50, &reg50h);
+ pci_read_config_dword(bmide_dev, 0x60, &reg60h);
+ pci_read_config_dword(bmide_dev, 0x64, &reg64h);
+ pci_read_config_dword(bmide_dev, 0x68, &reg68h);
+ pci_read_config_dword(bmide_dev, 0x6c, &reg6ch);
+
/*
* at that point bibma+0x2 et bibma+0xa are byte registers
* to investigate:
@@ -131,6 +123,7 @@ static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count
break;
case PCI_DEVICE_ID_PROMISE_20246:
p += sprintf(p, "\n PDC20246 Chipset.\n");
+ reg50h |= 0x0c00;
break;
default:
p += sprintf(p, "\n PDC202XX Chipset.\n");
@@ -139,17 +132,18 @@ static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
p += sprintf(p, " %sabled %sabled\n",
- (c0&0x80) ? "dis" : " en",
- (c1&0x80) ? "dis" : " en");
+ (c0&0x80)?"dis":" en",(c1&0x80)?"dis":" en");
p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
- (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
- p += sprintf(p, "UDMA\n");
- p += sprintf(p, "DMA\n");
- p += sprintf(p, "PIO\n");
-
+ (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+ p += sprintf(p, "DMA Mode: %s %s %s %s\n",
+ pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+ pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+ pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+ pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+ p += sprintf(p, " PIO Mode: %s %s %s %s\n",
+ pdc202xx_pio_verbose(reg60h),pdc202xx_pio_verbose(reg64h),
+ pdc202xx_pio_verbose(reg68h),pdc202xx_pio_verbose(reg6ch));
return p-buffer; /* => must be less than 4k! */
}
#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -268,6 +262,90 @@ static void decode_registers (byte registers, byte value)
#endif /* PDC202XX_DECODE_REGISTER_INFO */
+/* 0 1 2 3 4 5 6 7 8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ * 180, 150, 120, 90, 60
+ * DMA_Speed
+ * 180, 120, 90, 90, 90, 60, 30
+ * 11, 5, 4, 3, 2, 1, 0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte drive_pci, speed;
+ byte AP, BP, TA, TB;
+
+ int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ int err;
+
+ switch (drive_number) {
+ case 0: drive_pci = 0x60; break;
+ case 1: drive_pci = 0x64; break;
+ case 2: drive_pci = 0x68; break;
+ case 3: drive_pci = 0x6c; break;
+ default: return 1;
+ }
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+
+ if ((AP & 0x0F) || (BP & 0x07)) {
+ /* clear PIO modes of lower 8421 bits of A Register */
+ pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
+ pci_read_config_byte(dev, (drive_pci), &AP);
+
+ /* clear PIO modes of lower 421 bits of B Register */
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ }
+
+ pio = (pio == 5) ? 4 : pio;
+ switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) {
+ case 4:speed = XFER_PIO_4; TA=0x01; TB=0x04; break;
+ case 3:speed = XFER_PIO_3; TA=0x02; TB=0x06; break;
+ case 2:speed = XFER_PIO_2; TA=0x03; TB=0x08; break;
+ case 1:speed = XFER_PIO_1; TA=0x05; TB=0x0C; break;
+ case 0:
+ default:speed = XFER_PIO_0; TA=0x09; TB=0x13; break;
+ }
+ pci_write_config_byte(dev, (drive_pci), AP|TA);
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+
+#if PDC202XX_DECODE_REGISTER_INFO
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+ pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+ decode_registers(REG_A, AP);
+ decode_registers(REG_B, BP);
+ decode_registers(REG_C, CP);
+ decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+ err = ide_config_drive_speed(drive, speed);
+
+#if PDC202XX_DEBUG_DRIVE_INFO
+ printk("%s: %s drive%d 0x%08x ",
+ drive->name, ide_xfer_verbose(speed),
+ drive_number, drive_conf);
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+ return err;
+}
+
+static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
+{
+ (void) config_chipset_for_pio(drive, pio);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
@@ -476,91 +554,6 @@ chipset_is_set:
ide_dma_off_quietly);
}
-/* 0 1 2 3 4 5 6 7 8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- * 180, 150, 120, 90, 60
- * DMA_Speed
- * 180, 120, 90, 90, 90, 60, 30
- * 11, 5, 4, 3, 2, 1, 0
- */
-
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- byte drive_pci, speed;
- byte AP, BP, TA, TB;
-
- int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- int err;
-
- switch (drive_number) {
- case 0: drive_pci = 0x60; break;
- case 1: drive_pci = 0x64; break;
- case 2: drive_pci = 0x68; break;
- case 3: drive_pci = 0x6c; break;
- default: return 1;
- }
-
- pci_read_config_byte(dev, (drive_pci), &AP);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-
- if ((AP & 0x0F) || (BP & 0x07)) {
- /* clear PIO modes of lower 8421 bits of A Register */
- pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
- pci_read_config_byte(dev, (drive_pci), &AP);
-
- /* clear PIO modes of lower 421 bits of B Register */
- pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
- pci_read_config_byte(dev, (drive_pci), &AP);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
- }
-
- pio = (pio == 5) ? 4 : pio;
- switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) {
- case 4: speed = XFER_PIO_4; TA=0x01; TB=0x04; break;
- case 3: speed = XFER_PIO_3; TA=0x02; TB=0x06; break;
- case 2: speed = XFER_PIO_2; TA=0x03; TB=0x08; break;
- case 1: speed = XFER_PIO_1; TA=0x05; TB=0x0C; break;
- case 0:
- default: speed = XFER_PIO_0; TA=0x09; TB=0x13; break;
- }
- pci_write_config_byte(dev, (drive_pci), AP|TA);
- pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-
-#if PDC202XX_DECODE_REGISTER_INFO
- pci_read_config_byte(dev, (drive_pci), &AP);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
- pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
- pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
- decode_registers(REG_A, AP);
- decode_registers(REG_B, BP);
- decode_registers(REG_C, CP);
- decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
- err = ide_config_drive_speed(drive, speed);
-
-#if PDC202XX_DEBUG_DRIVE_INFO
- printk("%s: %s drive%d 0x%08x ",
- drive->name, ide_xfer_verbose(speed),
- drive_number, drive_conf);
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-
- return err;
-}
-
-static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
-{
- (void) config_chipset_for_pio(drive, pio);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -625,6 +618,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
{
@@ -701,11 +695,12 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
#endif /* CONFIG_PDC202XX_MASTER */
#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
- pdc202xx_proc = 1;
- bmide_dev = dev;
- pdc202xx_display_info = &pdc202xx_get_info;
+ if (!pdc202xx_proc) {
+ pdc202xx_proc = 1;
+ bmide_dev = dev;
+ pdc202xx_display_info = &pdc202xx_get_info;
+ }
#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
-
return dev->irq;
}
@@ -722,10 +717,18 @@ void __init ide_init_pdc202xx (ide_hwif_t *hwif)
{
hwif->tuneproc = &pdc202xx_tune_drive;
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &pdc202xx_dmaproc;
+ hwif->autodma = 1;
} else {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
}
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
index 93f20566d..fa453e7d5 100644
--- a/drivers/ide/piix.c
+++ b/drivers/ide/piix.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/piix.c Version 0.30 Feb. 26, 2000
+ * linux/drivers/ide/piix.c Version 0.31 Mar. 18, 2000
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
@@ -51,31 +51,6 @@
* pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
* pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
*
- * 00:1f.1 IDE interface: Intel Corporation:
- * Unknown device 2411 (rev 01) (prog-if 80 [Master])
- * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop-
- * ParErr- Stepping- SERR- FastB2B-
- * Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
- * <TAbort- <MAbort- >SERR- <PERR-
- * Latency: 0 set
- * Region 4: I/O ports at ffa0
- * 00: 86 80 11 24 05 00 80 02 01 80 01 01 00 00 00 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: a1 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 07 a3 03 a3 00 00 00 00 05 00 02 02 00 00 00 00
- * 50: 00 00 00 00 11 04 00 00 00 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 3a 0f 00 00 00 00 00 00
- *
*/
#include <linux/config.h>
@@ -281,6 +256,7 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio)
restore_flags(flags);
}
+#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
static int piix_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -387,13 +363,16 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
/* Other cases are done by generic IDE-DMA code. */
return ide_dmaproc(func, drive);
}
+#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
{
#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
- piix_proc = 1;
- bmide_dev = dev;
- piix_display_info = &piix_get_info;
+ if (!piix_proc) {
+ piix_proc = 1;
+ bmide_dev = dev;
+ piix_display_info = &piix_get_info;
+ }
#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
return 0;
}
@@ -427,12 +406,12 @@ void __init ide_init_piix (ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
+#ifndef CONFIG_BLK_DEV_IDEDMA
+ hwif->autodma = 0;
+#else /* CONFIG_BLK_DEV_IDEDMA */
#ifdef CONFIG_PIIX_TUNING
hwif->autodma = 1;
hwif->dmaproc = &piix_dmaproc;
-#else
- if (hwif->autodma)
- hwif->autodma = 0;
-
#endif /* CONFIG_PIIX_TUNING */
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
index 0f2330370..41d4277d2 100644
--- a/drivers/ide/q40ide.c
+++ b/drivers/ide/q40ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/q40ide.c -- Q40 I/O port IDE Driver
+ * linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
*
* original file created 12 Jul 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/qd6580.c b/drivers/ide/qd6580.c
index 31781a9f0..bccf1eb6a 100644
--- a/drivers/ide/qd6580.c
+++ b/drivers/ide/qd6580.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996
+ * linux/drivers/ide/qd6580.c Version 0.02 Feb 09, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c
index 5905aca41..baa293467 100644
--- a/drivers/ide/rapide.c
+++ b/drivers/ide/rapide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/rapide.c
+ * linux/drivers/ide/rapide.c
*
* Copyright (c) 1996-1998 Russell King.
*
diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
index 455641c1d..5bd3db7d5 100644
--- a/drivers/ide/rz1000.c
+++ b/drivers/ide/rz1000.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997
+ * linux/drivers/ide/rz1000.c Version 0.05 December 8, 1997
*
* Copyright (C) 1995-1998 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index 942187900..37da5577a 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/sis5513.c Version 0.09 Feb. 10, 2000
+ * linux/drivers/ide/sis5513.c Version 0.10 Mar. 18, 2000
*
* Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -109,14 +109,14 @@ static __inline__ char * find_udma_mode (byte cycle_time)
static int sis_get_info(char *, char **, off_t, int);
extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-struct pci_dev *bmide_dev;
+static struct pci_dev *bmide_dev;
-static char *cable_type[] = {
+static char *cable_type[] __initdata = {
"80 pins",
"40 pins"
};
-static char *recovery_time [] ={
+static char *recovery_time [] __initdata ={
"12 PCICLK", "1 PCICLK",
"2 PCICLK", "3 PCICLK",
"4 PCICLK", "5 PCICLCK",
@@ -127,14 +127,14 @@ static char *recovery_time [] ={
"15 PCICLK", "15 PCICLK"
};
-static char *cycle_time [] = {
+static char * cycle_time [] __initdata = {
"Undefined", "2 CLCK",
"3 CLK", "4 CLK",
"5 CLK", "6 CLK",
"7 CLK", "8 CLK"
};
-static char *active_time [] = {
+static char * active_time [] __initdata = {
"8 PCICLK", "1 PCICLCK",
"2 PCICLK", "2 PCICLK",
"4 PCICLK", "5 PCICLK",
@@ -222,6 +222,123 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
byte sis_proc = 0;
extern char *ide_xfer_verbose (byte xfer_rate);
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ byte reg4bh = 0;
+ byte rw_prefetch = (0x11 << drive_number);
+
+ pci_read_config_byte(dev, 0x4b, &reg4bh);
+ if (drive->media != ide_disk)
+ return;
+
+ if ((reg4bh & rw_prefetch) != rw_prefetch)
+ pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+}
+
+static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ byte timing, drive_pci, test1, test2;
+
+ unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+
+#if 0
+ config_drive_art_rwp(drive);
+#endif
+
+ pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+/*
+ * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4
+ * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns)
+ * 0x41 2:0 bits 000 110 100 011 011
+ * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns)
+ * 0x40 3:0 bits 0000 0111 0100 0011 0001
+ * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
+ */
+
+ switch(drive_number) {
+ case 0: drive_pci = 0x40; break;
+ case 1: drive_pci = 0x42; break;
+ case 2: drive_pci = 0x44; break;
+ case 3: drive_pci = 0x46; break;
+ default: return;
+ }
+
+ pci_read_config_byte(dev, drive_pci, &test1);
+ pci_read_config_byte(dev, drive_pci|0x01, &test2);
+
+ /*
+ * Do a blanket clear of active and recovery timings.
+ */
+
+ test1 &= ~0x07;
+ test2 &= ~0x0F;
+
+ switch(timing) {
+ case 4: test1 |= 0x01; test2 |= 0x03; break;
+ case 3: test1 |= 0x03; test2 |= 0x03; break;
+ case 2: test1 |= 0x04; test2 |= 0x04; break;
+ case 1: test1 |= 0x07; test2 |= 0x06; break;
+ default: break;
+ }
+
+ pci_write_config_byte(dev, drive_pci, test1);
+ pci_write_config_byte(dev, drive_pci|0x01, test2);
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+ int err;
+ byte speed;
+
+ 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 = XFER_PIO_0; break;
+ }
+
+ config_art_rwp_pio(drive, pio);
+ err = ide_config_drive_speed(drive, speed);
+ return err;
+}
+
+#undef SIS5513_TUNEPROC
+
+#ifdef SIS5513_TUNEPROC
+static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
+{
+ (void) config_chipset_for_pio(drive, pio);
+}
+#endif /* SIS5513_TUNEPROC */
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* ((id->hw_config & 0x2000) && (HWIF(drive)->udma_four))
*/
@@ -331,84 +448,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
ide_dma_off_quietly);
}
-static void config_drive_art_rwp (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
-
- byte timing, pio, drive_pci, test1, test2;
-
- unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
- int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-
- if (drive->media == ide_disk) {
- struct pci_dev *dev = hwif->pci_dev;
- byte reg4bh = 0;
- byte rw_prefetch = (0x11 << drive_number);
-
- pci_read_config_byte(dev, 0x4b, &reg4bh);
- if ((reg4bh & rw_prefetch) != rw_prefetch)
- pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
- }
-
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-/*
- * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4
- * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns)
- * 0x41 2:0 bits 000 110 100 011 011
- * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns)
- * 0x40 3:0 bits 0000 0111 0100 0011 0001
- * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
- */
-
- switch(drive_number) {
- case 0: drive_pci = 0x40;break;
- case 1: drive_pci = 0x42;break;
- case 2: drive_pci = 0x44;break;
- case 3: drive_pci = 0x46;break;
- default: return;
- }
-
- pci_read_config_byte(dev, drive_pci, &test1);
- pci_read_config_byte(dev, drive_pci|0x01, &test2);
-
- /*
- * Do a blanket clear of active and recovery timings.
- */
-
- test1 &= ~0x07;
- test2 &= ~0x0F;
-
- switch(timing) {
- case 4: test1 |= 0x01;test2 |= 0x03;break;
- case 3: test1 |= 0x03;test2 |= 0x03;break;
- case 2: test1 |= 0x04;test2 |= 0x04;break;
- case 1: test1 |= 0x07;test2 |= 0x06;break;
- default: break;
- }
-
- pci_write_config_byte(dev, drive_pci, test1);
- pci_write_config_byte(dev, drive_pci|0x01, test2);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -417,9 +456,10 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
if (id && (id->capability & 1) && HWIF(drive)->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
- return HWIF(drive)->dmaproc(ide_dma_off, drive);
+ dma_func = ide_dma_off;
+ goto fast_ata_pio;
}
-
+ dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
if (id->dma_ultra & 0x001F) {
/* Force if Capable UltraDMA */
@@ -434,13 +474,25 @@ try_dma_modes:
(id->dma_1word & 0x0007)) {
/* Force if Capable regular DMA modes */
dma_func = config_chipset_for_dma(drive, 0);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
}
} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
(id->eide_dma_time > 150)) {
/* Consult the list of known "good" drives */
dma_func = config_chipset_for_dma(drive, 0);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ } else {
+ goto fast_ata_pio;
}
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ dma_func = ide_dma_off_quietly;
+no_dma_set:
+ (void) config_chipset_for_pio(drive, 5);
}
+
return HWIF(drive)->dmaproc(dma_func, drive);
}
@@ -452,12 +504,14 @@ int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
switch (func) {
case ide_dma_check:
config_drive_art_rwp(drive);
+ config_art_rwp_pio(drive, 5);
return config_drive_xfer_rate(drive);
default:
break;
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
{
@@ -492,9 +546,11 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
pci_write_config_byte(dev, 0x52, reg52h|0x04);
}
#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
- sis_proc = 1;
- bmide_dev = dev;
- sis_display_info = &sis_get_info;
+ if (!sis_proc) {
+ sis_proc = 1;
+ bmide_dev = dev;
+ sis_display_info = &sis_get_info;
+ }
#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
}
return 0;
@@ -525,11 +581,16 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
+#ifdef SIS5513_TUNEPROC
+ hwif->tuneproc = &sis5513_tune_drive;
+#endif /* SIS5513_TUNEPROC */
+
if (!(hwif->dma_base))
return;
if (host_dev) {
switch(host_dev->device) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
case PCI_DEVICE_ID_SI_530:
case PCI_DEVICE_ID_SI_540:
case PCI_DEVICE_ID_SI_620:
@@ -540,6 +601,7 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif)
hwif->autodma = 1;
hwif->dmaproc = &sis5513_dmaproc;
break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
default:
hwif->autodma = 0;
break;
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index 483a98fde..c58c612ed 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/sl82c105.c
+ * linux/drivers/ide/sl82c105.c
*
* SL82C105/Winbond 553 IDE driver
*
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
index fb5e8d1af..e7ee2e977 100644
--- a/drivers/ide/trm290.c
+++ b/drivers/ide/trm290.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/trm290.c Version 1.01 December 5, 1997
+ * linux/drivers/ide/trm290.c Version 1.02 Mar. 18, 2000
*
* Copyright (c) 1997-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
@@ -124,6 +124,7 @@
*
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -171,6 +172,7 @@ static void trm290_selectproc (ide_drive_t *drive)
trm290_prepare_drive(drive, drive->using_dma);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -209,6 +211,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
trm290_prepare_drive(drive, 0); /* select PIO xfer */
return 1;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* Invoked from ide-dma.c at boot time.
@@ -247,7 +250,11 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */
ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &trm290_dmaproc;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
hwif->selectproc = &trm290_selectproc;
hwif->autodma = 0; /* play it safe for now */
#if 1
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
index 02b581a28..5c1168972 100644
--- a/drivers/ide/umc8672.c
+++ b/drivers/ide/umc8672.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996
+ * linux/drivers/ide/umc8672.c Version 0.05 Jul 31, 1996
*
* Copyright (C) 1995-1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index afa1cc5b6..bf8e27640 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/via82cxxx.c Version 0.07 Feb. 10, 2000
+ * linux/drivers/ide/via82cxxx.c Version 0.08 Mar. 18, 2000
*
* Copyright (C) 1998-99 Michel Aubry, Maintainer
* Copyright (C) 1999 Jeff Garzik, MVP4 Support
@@ -143,14 +143,14 @@ static const struct {
#include <linux/stat.h>
#include <linux/proc_fs.h>
-static char *FIFO_str[] = {
+static char *FIFO_str[] __initdata = {
" 1 ",
"3/4",
"1/2",
"1/4"
};
-static char *control3_str[] = {
+static char *control3_str[] __initdata = {
"No limitation",
"64",
"128",
@@ -516,6 +516,62 @@ static int via_set_fifoconfig(ide_hwif_t *hwif)
#ifdef CONFIG_VIA82CXXX_TUNING
+struct chipset_bus_clock_list_entry {
+ unsigned short bus_speed;
+ byte xfer_speed;
+ byte chipset_settings;
+};
+
+PCI_DEVICE_ID_VIA_82C586_1
+PCI_DEVICE_ID_VIA_82C596
+PCI_DEVICE_ID_VIA_82C686
+PCI_DEVICE_ID_VIA_8231
+
+PCI_DEVICE_ID_VIA_82C586_1 TYPE_1
+PCI_DEVICE_ID_VIA_82C596 TYPE_2
+PCI_DEVICE_ID_VIA_82C686 TYPE_2
+PCI_DEVICE_ID_VIA_82C596 TYPE_3
+PCI_DEVICE_ID_VIA_82C686 TYPE_3
+PCI_DEVICE_ID_VIA_8231 TYPE_4
+
+struct chipset_bus_clock_list_entry ultra_33_base [] = {
+{ TYPE_1,25,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_1,33,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_1,37,0x00,0x00,0x60,0x61,0x62,0x03,0x21,0x32,0x76,0x76,0xA9 },
+{ TYPE_2,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_2,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_2,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB },
+{ TYPE_2,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE },
+{ TYPE_3,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_3,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_3,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB },
+{ TYPE_3,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE },
+{ TYPE_4,0,0,0,0,0,0,0,0,0,0,0,0 },
+{ 0,0,0,0,0,0,0,0,0,0,0,0,0 }
+};
+
+struct chipset_bus_clock_list_entry timing_66_base [] = {
+ { 37, XFER_PIO_4, 0x21 },
+ { 37, XFER_PIO_3, 0x32 },
+ { 37, XFER_PIO_2, 0x76 },
+ { 37, XFER_PIO_1, 0x76 },
+ { 37, XFER_PIO_0, 0xA9 },
+ { ANY, XFER_PIO_4, 0x20 },
+ { ANY, XFER_PIO_3, 0x31 },
+ { ANY, XFER_PIO_2, 0x65 },
+ { ANY, XFER_PIO_1, 0x65 },
+ { ANY, XFER_PIO_0, 0xA8 },
+};
+
+static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+ for ( ; chipset_table->xfer_speed ; chipset_table++)
+ if (chipset_table->xfer_speed == speed) {
+ return chipset_table->chipset_settings;
+ }
+ return 0x01208585;
+}
+
static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
{
struct hd_driveid *id = drive->id;
@@ -539,7 +595,7 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
case 2: ata2_pci = 0x4a; ata3_pci = 0x52; break;
case 3: ata2_pci = 0x4b; ata3_pci = 0x53; break;
default:
- return err;
+ return -1;
}
pci_read_config_byte(dev, ata2_pci, &timing);
@@ -575,6 +631,57 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ byte timing, speed, pio;
+
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 :
+ (drive->id->tPIO & 2) ? 0x02 :
+ (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+ switch(timing) {
+ 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;
+ }
+ (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+ 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 = XFER_PIO_0; break;
+ }
+ (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -617,56 +724,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
return rval;
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
- byte timing, speed, pio;
-
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 :
- (drive->id->tPIO & 2) ? 0x02 :
- (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
- switch(timing) {
- 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;
- }
- (void) via82cxxx_tune_chipset(drive, speed);
-}
-
-static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio)
-{
- byte speed;
- 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 = XFER_PIO_0;break;
- }
- (void) via82cxxx_tune_chipset(drive, speed);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -726,6 +783,7 @@ int via82cxxx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_VIA82CXXX_TUNING */
unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
@@ -745,7 +803,7 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
host_dev = host;
printk(ApolloHostChipInfo[i].name);
-
+ printk("\n");
for (j = 0; j < arraysize (ApolloISAChipInfo) && !isa_dev; j++) {
if (ApolloISAChipInfo[j].host_id !=
ApolloHostChipInfo[i].host_id)
@@ -777,9 +835,11 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
}
#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
- via_proc = 1;
- bmide_dev = dev;
- via_display_info = &via_get_info;
+ if (!via_proc) {
+ via_proc = 1;
+ bmide_dev = dev;
+ via_display_info = &via_get_info;
+ }
#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/
return 0;
@@ -797,13 +857,15 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif)
#ifdef CONFIG_VIA82CXXX_TUNING
hwif->tuneproc = &via82cxxx_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &via82cxxx_dmaproc;
- } else {
- hwif->autodma = 0;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->autodma = 1;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_VIA82CXXX_TUNING */
}
diff --git a/drivers/ieee1394/Config.in b/drivers/ieee1394/Config.in
index 899add490..df0e3cfd2 100644
--- a/drivers/ieee1394/Config.in
+++ b/drivers/ieee1394/Config.in
@@ -14,11 +14,12 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394
-
+
dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394
dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
+ bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
fi
endmenu
fi
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index 4ffe0fadd..a884f2a1c 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -14,6 +14,7 @@
#include "highlevel.h"
+/* FIXME: this one won't work on little endian with big endian data */
static u16 csr_crc16(unsigned *data, int length)
{
int check=0, i;
@@ -47,14 +48,18 @@ static void host_reset(struct hpsb_host *host)
host->csr.state &= ~0x100;
}
- host->csr.topology_map[1]++;
- host->csr.topology_map[2] = host->node_count << 16 | host->selfid_count;
- host->csr.topology_map[0] = (host->selfid_count + 2) << 16
- | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2);
-
- /* FIXME - generate speed map */
- host->csr.speed_map[0] = 0x3f1 << 16 | csr_crc16(host->csr.speed_map+1,
- 0x3f1);
+ host->csr.topology_map[1] =
+ cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1);
+ host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
+ | host->selfid_count);
+ host->csr.topology_map[0] =
+ cpu_to_be32((host->selfid_count + 2) << 16
+ | csr_crc16(host->csr.topology_map + 1,
+ host->selfid_count + 2));
+
+ host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
+ | csr_crc16(host->csr.speed_map+1,
+ 0x3f1));
}
@@ -78,8 +83,8 @@ static void add_host(struct hpsb_host *host)
/* Read topology / speed maps and configuration ROM */
-static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
+static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
const char *src;
@@ -100,43 +105,11 @@ static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
return RCODE_COMPLETE;
}
-/* Read FCP register space */
-static int read_fcp(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- const char *src;
-
- if (csraddr + length > CSR_FCP_END) {
- return RCODE_ADDRESS_ERROR;
- }
- src = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
-
- memcpy(buffer, src, length);
- return RCODE_COMPLETE;
-}
-
-/* Write FCP register space */
-static int write_fcp(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- char *dest;
-
- if (csraddr + length > CSR_FCP_END) {
- return RCODE_ADDRESS_ERROR;
- }
- dest = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
-
- memcpy(dest, data, length);
- return RCODE_COMPLETE;
-}
-
#define out if (--length == 0) break
-static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
- unsigned int length)
+static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
int oldcycle;
@@ -149,13 +122,13 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
switch (csraddr) {
case CSR_STATE_CLEAR:
- *(buf++) = host->csr.state;
+ *(buf++) = cpu_to_be32(host->csr.state);
out;
case CSR_STATE_SET:
- *(buf++) = host->csr.state;
+ *(buf++) = cpu_to_be32(host->csr.state);
out;
case CSR_NODE_IDS:
- *(buf++) = host->csr.node_ids;
+ *(buf++) = cpu_to_be32(host->csr.node_ids);
out;
case CSR_RESET_START:
@@ -164,10 +137,10 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
/* address gap - handled by default below */
case CSR_SPLIT_TIMEOUT_HI:
- *(buf++) = host->csr.split_timeout_hi;
+ *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
out;
case CSR_SPLIT_TIMEOUT_LO:
- *(buf++) = host->csr.split_timeout_lo;
+ *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
out;
/* address gap */
@@ -182,7 +155,7 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
/* cycle time wrapped around */
host->csr.bus_time += 1 << 7;
}
- *(buf++) = host->csr.cycle_time;
+ *(buf++) = cpu_to_be32(host->csr.cycle_time);
out;
case CSR_BUS_TIME:
oldcycle = host->csr.cycle_time;
@@ -193,7 +166,8 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
/* cycle time wrapped around */
host->csr.bus_time += (1 << 7);
}
- *(buf++) = host->csr.bus_time | (host->csr.cycle_time >> 25);
+ *(buf++) = cpu_to_be32(host->csr.bus_time
+ | (host->csr.cycle_time >> 25));
out;
/* address gap */
@@ -204,16 +178,16 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
return RCODE_ADDRESS_ERROR;
case CSR_BUS_MANAGER_ID:
- *(buf++) = host->csr.bus_manager_id;
+ *(buf++) = cpu_to_be32(host->csr.bus_manager_id);
out;
case CSR_BANDWIDTH_AVAILABLE:
- *(buf++) = host->csr.bandwidth_available;
+ *(buf++) = cpu_to_be32(host->csr.bandwidth_available);
out;
case CSR_CHANNELS_AVAILABLE_HI:
- *(buf++) = host->csr.channels_available_hi;
+ *(buf++) = cpu_to_be32(host->csr.channels_available_hi);
out;
case CSR_CHANNELS_AVAILABLE_LO:
- *(buf++) = host->csr.channels_available_lo;
+ *(buf++) = cpu_to_be32(host->csr.channels_available_lo);
out;
/* address gap to end - fall through to default */
@@ -224,8 +198,8 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
return RCODE_COMPLETE;
}
-static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
+static int write_regs(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
@@ -246,7 +220,7 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
case CSR_NODE_IDS:
host->csr.node_ids &= NODE_MASK << 16;
- host->csr.node_ids |= *(data++) & (BUS_MASK << 16);
+ host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
host->node_id = host->csr.node_ids >> 16;
host->template->devctl(host, SET_BUS_ID, host->node_id >> 6);
out;
@@ -259,10 +233,12 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
return RCODE_ADDRESS_ERROR;
case CSR_SPLIT_TIMEOUT_HI:
- host->csr.split_timeout_hi = *(data++) & 0x00000007;
+ host->csr.split_timeout_hi =
+ be32_to_cpu(*(data++)) & 0x00000007;
out;
case CSR_SPLIT_TIMEOUT_LO:
- host->csr.split_timeout_lo = *(data++) & 0xfff80000;
+ host->csr.split_timeout_lo =
+ be32_to_cpu(*(data++)) & 0xfff80000;
out;
/* address gap */
@@ -270,11 +246,12 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
case CSR_CYCLE_TIME:
/* should only be set by cycle start packet, automatically */
- host->csr.cycle_time = *data;
- host->template->devctl(host, SET_CYCLE_COUNTER, *(data++));
+ host->csr.cycle_time = be32_to_cpu(*data);
+ host->template->devctl(host, SET_CYCLE_COUNTER,
+ be32_to_cpu(*(data++)));
out;
case CSR_BUS_TIME:
- host->csr.bus_time = *(data++) & 0xffffff80;
+ host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
out;
/* address gap */
@@ -305,13 +282,13 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
/* helper function for lock_regs */
inline static void compare_swap(quadlet_t *old, quadlet_t data, quadlet_t arg)
{
- if (*old == arg) {
- *old = data;
+ if (*old == be32_to_cpu(arg)) {
+ *old = be32_to_cpu(data);
}
}
-static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int extcode)
+static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int extcode)
{
int csraddr = addr - CSR_REGISTER_BASE;
unsigned long flags;
@@ -327,25 +304,28 @@ static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
switch (csraddr) {
case CSR_BUS_MANAGER_ID:
- *store = host->csr.bus_manager_id;
+ *store = cpu_to_be32(host->csr.bus_manager_id);
compare_swap(&host->csr.bus_manager_id,
data, arg);
break;
case CSR_BANDWIDTH_AVAILABLE:
- *store = host->csr.bandwidth_available;
+ *store = cpu_to_be32(host->
+ csr.bandwidth_available);
compare_swap(&host->csr.bandwidth_available,
data, arg);
break;
case CSR_CHANNELS_AVAILABLE_HI:
- *store = host->csr.channels_available_hi;
+ *store = cpu_to_be32(host->
+ csr.channels_available_hi);
compare_swap(&host->csr.channels_available_hi,
data, arg);
break;
case CSR_CHANNELS_AVAILABLE_LO:
- *store = host->csr.channels_available_lo;
+ *store = cpu_to_be32(host->
+ csr.channels_available_lo);
compare_swap(&host->csr.channels_available_lo,
data, arg);
break;
@@ -377,34 +357,48 @@ static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
}
}
+static int write_fcp(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+
+ if (length > 512) {
+ return RCODE_TYPE_ERROR;
+ }
+
+ switch (csraddr) {
+ case CSR_FCP_COMMAND:
+ highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
+ break;
+ case CSR_FCP_RESPONSE:
+ highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
+ break;
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+
+ return RCODE_COMPLETE;
+}
+
struct hpsb_highlevel_ops csr_ops = {
- add_host,
- NULL,
- host_reset,
- NULL
+ add_host: add_host,
+ host_reset: host_reset,
};
struct hpsb_address_ops map_ops = {
- read_maps,
- NULL,
- NULL,
- NULL
+ read: read_maps,
};
struct hpsb_address_ops fcp_ops = {
- read_fcp,
- write_fcp,
- NULL,
- NULL
+ write: write_fcp,
};
struct hpsb_address_ops reg_ops = {
- read_regs,
- write_regs,
- lock_regs,
- NULL
+ read: read_regs,
+ write: write_regs,
+ lock: lock_regs,
};
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
index 70bacdd10..7bc97f549 100644
--- a/drivers/ieee1394/csr.h
+++ b/drivers/ieee1394/csr.h
@@ -46,7 +46,6 @@ struct csr_control {
quadlet_t topology_map[256];
quadlet_t speed_map[1024];
- quadlet_t fcp_data[1024];
};
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 3b4ac40f5..3e20824aa 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -192,23 +192,35 @@ void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
read_unlock(&hl_drivers_lock);
}
+void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ u8 *data, unsigned int length)
+{
+ struct list_head *entry;
+ struct hpsb_highlevel *hl;
+ int cts = data[0];
+
+ read_lock(&hl_drivers_lock);
+ entry = hl_drivers.next;
+
+ while (entry != &hl_drivers) {
+ hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+ if (hl->op->fcp_request) {
+ hl->op->fcp_request(host, nodeid, direction, cts, data,
+ length);
+ }
+ entry = entry->next;
+ }
+ read_unlock(&hl_drivers_lock);
+}
-int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
+int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length)
{
struct hpsb_address_serve *as;
struct list_head *entry;
unsigned int partlength;
int rcode = RCODE_ADDRESS_ERROR;
- if ((addr | length) & 0x3) {
- /* Addresses or lengths not a multiple of a quadlet pose a big
- * problem on little endian machines because we always do this
- * in arch endian and swapping would mess it all up. So we
- * simply don't allow this at all. */
- return RCODE_TYPE_ERROR;
- }
-
read_lock(&addr_space_lock);
entry = addr_space.next;
@@ -220,7 +232,7 @@ int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
length);
if (as->op->read != NULL) {
- rcode = as->op->read(host, buffer, addr,
+ rcode = as->op->read(host, nodeid, buffer, addr,
partlength);
} else {
rcode = RCODE_TYPE_ERROR;
@@ -247,18 +259,14 @@ int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
return rcode;
}
-int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
+int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
{
struct hpsb_address_serve *as;
struct list_head *entry;
unsigned int partlength;
int rcode = RCODE_ADDRESS_ERROR;
- if ((addr | length) & 0x3) {
- return RCODE_TYPE_ERROR;
- }
-
read_lock(&addr_space_lock);
entry = addr_space.next;
@@ -270,7 +278,7 @@ int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
length);
if (as->op->write != NULL) {
- rcode = as->op->write(host, data, addr,
+ rcode = as->op->write(host, nodeid, data, addr,
partlength);
} else {
rcode = RCODE_TYPE_ERROR;
@@ -298,8 +306,8 @@ int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
}
-int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode)
+int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
{
struct hpsb_address_serve *as;
struct list_head *entry;
@@ -313,8 +321,8 @@ int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
while (as->start <= addr) {
if (as->end > addr) {
if (as->op->lock != NULL) {
- rcode = as->op->lock(host, store, addr, data,
- arg, ext_tcode);
+ rcode = as->op->lock(host, nodeid, store, addr,
+ data, arg, ext_tcode);
} else {
rcode = RCODE_TYPE_ERROR;
}
@@ -331,8 +339,8 @@ int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
return rcode;
}
-int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode)
+int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
{
struct hpsb_address_serve *as;
struct list_head *entry;
@@ -346,8 +354,9 @@ int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
while (as->start <= addr) {
if (as->end > addr) {
if (as->op->lock64 != NULL) {
- rcode = as->op->lock64(host, store, addr, data,
- arg, ext_tcode);
+ rcode = as->op->lock64(host, nodeid, store,
+ addr, data, arg,
+ ext_tcode);
} else {
rcode = RCODE_TYPE_ERROR;
}
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index 9bf406742..f4f615a7b 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -55,6 +55,13 @@ struct hpsb_highlevel_ops {
* for channel/host combinations you did not request. */
void (*iso_receive) (struct hpsb_host *host, int channel,
quadlet_t *data, unsigned int length);
+
+ /* A write request was received on either the FCP_COMMAND (direction =
+ * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
+ * contains the cts field (first byte of data).
+ */
+ void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, unsigned int length);
};
struct hpsb_address_ops {
@@ -67,17 +74,17 @@ struct hpsb_address_ops {
*/
/* These functions have to implement block reads for themselves. */
- int (*read) (struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length);
- int (*write) (struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length);
+ int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length);
+ int (*write) (struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length);
/* Lock transactions: write results of ext_tcode operation into
* *store. */
- int (*lock) (struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode);
- int (*lock64) (struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode);
+ int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+ int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
};
@@ -87,17 +94,19 @@ void highlevel_add_host(struct hpsb_host *host);
void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host);
-int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length);
-int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length);
-int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode);
-int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode);
+int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length);
+int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length);
+int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
unsigned int length);
+void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ u8 *data, unsigned int length);
/*
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
index dfca3aef3..c9f42373e 100644
--- a/drivers/ieee1394/ieee1394.h
+++ b/drivers/ieee1394/ieee1394.h
@@ -63,4 +63,103 @@
#define SELFID_PORT_NCONN 0x1
#define SELFID_PORT_NONE 0x0
+
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN_BITFIELD
+
+struct selfid {
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if true is struct ext_selfid */
+ u32 link_active:1;
+ u32 gap_count:6;
+ /* byte */
+ u32 speed:2;
+ u32 phy_delay:2;
+ u32 contender:1;
+ u32 power_class:3;
+ /* byte */
+ u32 port0:2;
+ u32 port1:2;
+ u32 port2:2;
+ u32 initiated_reset:1;
+ u32 more_packets:1;
+} __attribute__((packed));
+
+struct ext_selfid {
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if false is struct selfid */
+ u32 seq_nr:3;
+ u32 reserved:2;
+ u32 porta:2;
+ /* byte */
+ u32 portb:2;
+ u32 portc:2;
+ u32 portd:2;
+ u32 porte:2;
+ /* byte */
+ u32 portf:2;
+ u32 portg:2;
+ u32 porth:2;
+ u32 reserved2:1;
+ u32 more_packets:1;
+} __attribute__((packed));
+
+#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
+
+/*
+ * Note: these mean to be bit fields of a big endian SelfID as seen on a little
+ * endian machine.
+ */
+
+struct selfid {
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 gap_count:6;
+ u32 link_active:1;
+ u32 extended:1; /* if true is struct ext_selfid */
+ /* byte */
+ u32 power_class:3;
+ u32 contender:1;
+ u32 phy_delay:2;
+ u32 speed:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 initiated_reset:1;
+ u32 port2:2;
+ u32 port1:2;
+ u32 port0:2;
+} __attribute__((packed));
+
+struct ext_selfid {
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 porta:2;
+ u32 reserved:2;
+ u32 seq_nr:3;
+ u32 extended:1; /* if false is struct selfid */
+ /* byte */
+ u32 porte:2;
+ u32 portd:2;
+ u32 portc:2;
+ u32 portb:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 reserved2:1;
+ u32 porth:2;
+ u32 portg:2;
+ u32 portf:2;
+} __attribute__((packed));
+
+#else
+#error What? PDP endian?
+#endif /* __BIG_ENDIAN_BITFIELD */
+
+
#endif /* _IEEE1394_IEEE1394_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 771189f0b..c7ce73144 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -2,11 +2,12 @@
* IEEE 1394 for Linux
*
* Core support: hpsb_packet management, packet handling and forwarding to
- * csr or lowlevel code
+ * highlevel or lowlevel code
*
* Copyright (C) 1999, 2000 Andreas E. Bombe
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
@@ -62,7 +63,7 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
packet->header = header;
if (data_size) {
- data = kmalloc(data_size + 4, kmflags);
+ data = kmalloc(data_size + 8, kmflags);
if (data == NULL) {
kfree(header);
kfree(packet);
@@ -70,18 +71,14 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
}
packet->data = data;
- packet->data_size = data_size - 4;
+ packet->data_size = data_size;
}
INIT_LIST_HEAD(&packet->list);
sema_init(&packet->state_change, 0);
packet->state = unused;
packet->generation = get_hpsb_generation();
-
-#ifdef __BIG_ENDIAN
- /* set default */
packet->data_be = 1;
-#endif
return packet;
}
@@ -133,59 +130,55 @@ static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
{
int nodeid = -1;
int rest_of_selfids = num_of_selfids;
- quadlet_t *sidp = host->topology_map;
- quadlet_t sid = *sidp;
+ struct selfid *sid = (struct selfid *)host->topology_map;
+ struct ext_selfid *esid;
int esid_seq = 23;
- int i;
while (rest_of_selfids--) {
- sid = *(sidp++);
-
- if (!(sid & 0x00800000) /* !extended */) {
+ if (!sid->extended) {
nodeid++;
esid_seq = 0;
-
- if (((sid >> 24) & NODE_MASK) != nodeid) {
+
+ if (sid->phy_id != nodeid) {
HPSB_INFO("SelfIDs failed monotony check with "
- "%d", (sid >> 24) & NODE_MASK);
+ "%d", sid->phy_id);
return 0;
}
-
- /* "if is contender and link active" */
- if ((sid & (1<<11)) && (sid & (1<<22))) {
- host->irm_id = LOCAL_BUS | ((sid >> 24)
- & NODE_MASK);
+
+ if (sid->contender && sid->link_active) {
+ host->irm_id = LOCAL_BUS | sid->phy_id;
}
} else {
- if ((((sid >> 24) & NODE_MASK) != nodeid)
- || (((sid >> 20) & 0x7) != esid_seq)) {
+ esid = (struct ext_selfid *)sid;
+
+ if ((esid->phy_id != nodeid)
+ || (esid->seq_nr != esid_seq)) {
HPSB_INFO("SelfIDs failed monotony check with "
- "%d/%d", (sid >> 24) & NODE_MASK,
- (sid >> 20) & 0x7);
+ "%d/%d", esid->phy_id, esid->seq_nr);
return 0;
}
esid_seq++;
}
- }
-
- sidp--;
- while (sid & 0x00800000 /* extended */) {
- /* check that no ports go to a parent */
- for (i = 2; i < 18; i += 2) {
- if ((sid & (0x3 << i)) == (0x2 << i)) {
+ sid++;
+ }
+
+ esid = (struct ext_selfid *)(sid - 1);
+ while (esid->extended) {
+ if ((esid->porta == 0x2) || (esid->portb == 0x2)
+ || (esid->portc == 0x2) || (esid->portd == 0x2)
+ || (esid->porte == 0x2) || (esid->portf == 0x2)
+ || (esid->portg == 0x2) || (esid->porth == 0x2)) {
HPSB_INFO("SelfIDs failed root check on "
"extended SelfID");
return 0;
- }
}
- sid = *(sidp--);
+ esid--;
}
- for (i = 2; i < 8; i += 2) {
- if ((sid & (0x3 << i)) == (0x2 << i)) {
+ sid = (struct selfid *)esid;
+ if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) {
HPSB_INFO("SelfIDs failed root check");
return 0;
- }
}
return nodeid + 1;
@@ -196,7 +189,8 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
char speedcap[nodecount];
char cldcnt[nodecount];
u8 *map = host->speed_map;
- quadlet_t *sidp;
+ struct selfid *sid;
+ struct ext_selfid *esid;
int i, j, n;
for (i = 0; i < (nodecount * 64); i += 64) {
@@ -210,22 +204,26 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
}
/* find direct children count and speed */
- for (sidp = &host->topology_map[host->selfid_count-1],
+ for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
n = nodecount - 1;
- sidp >= host->topology_map; sidp--) {
- if (*sidp & 0x00800000 /* extended */) {
- for (i = 2; i < 18; i += 2) {
- if ((*sidp & (0x3 << i)) == (0x3 << i)) {
- cldcnt[n]++;
- }
- }
+ (void *)sid >= (void *)host->topology_map; sid--) {
+ if (sid->extended) {
+ esid = (struct ext_selfid *)sid;
+
+ if (esid->porta == 0x3) cldcnt[n]++;
+ if (esid->portb == 0x3) cldcnt[n]++;
+ if (esid->portc == 0x3) cldcnt[n]++;
+ if (esid->portd == 0x3) cldcnt[n]++;
+ if (esid->porte == 0x3) cldcnt[n]++;
+ if (esid->portf == 0x3) cldcnt[n]++;
+ if (esid->portg == 0x3) cldcnt[n]++;
+ if (esid->porth == 0x3) cldcnt[n]++;
} else {
- for (i = 2; i < 8; i += 2) {
- if ((*sidp & (0x3 << i)) == (0x3 << i)) {
- cldcnt[n]++;
- }
- }
- speedcap[n] = (*sidp >> 14) & 0x3;
+ if (sid->port0 == 0x3) cldcnt[n]++;
+ if (sid->port1 == 0x3) cldcnt[n]++;
+ if (sid->port2 == 0x3) cldcnt[n]++;
+
+ speedcap[n] = sid->speed;
n--;
}
}
@@ -262,7 +260,7 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{
if (host->in_bus_reset) {
- printk("including selfid 0x%x\n", sid);
+ HPSB_DEBUG("including selfid 0x%x", sid);
host->topology_map[host->selfid_count++] = sid;
} else {
/* FIXME - info on which host */
@@ -293,7 +291,12 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
}
/* irm_id is kept up to date by check_selfids() */
- host->is_irm = (host->irm_id == host->node_id);
+ if (host->irm_id == host->node_id) {
+ host->is_irm = 1;
+ host->is_busmgr = 1;
+ host->busmgr_id = host->node_id;
+ host->csr.bus_manager_id = host->node_id;
+ }
host->reset_retries = 0;
inc_hpsb_generation();
@@ -346,6 +349,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64
+ (packet->node_id & NODE_MASK)];
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
switch (packet->speed_code) {
case 2:
dump_packet("send packet 400:", packet->header,
@@ -359,6 +363,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
dump_packet("send packet 100:", packet->header,
packet->header_size);
}
+#endif
return host->template->transmit_packet(host, packet);
}
@@ -459,12 +464,14 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
{
struct hpsb_packet *p;
+ dsize += (dsize % 4 ? 4 - (dsize % 4) : 0);
+
p = alloc_hpsb_packet(dsize);
if (p == NULL) {
/* FIXME - send data_error response */
return NULL;
}
-
+
p->type = async;
p->state = unused;
p->host = host;
@@ -472,6 +479,10 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
p->tlabel = (data[0] >> 10) & 0x3f;
p->no_waiter = 1;
+ if (dsize % 4) {
+ p->data[dsize / 4] = 0;
+ }
+
return p;
}
@@ -479,21 +490,12 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
packet = create_reply_packet(host, data, length); \
if (packet == NULL) break
-inline void swap_quadlets_on_le(quadlet_t *q)
-{
-#ifdef __LITTLE_ENDIAN
- quadlet_t saved = q[0];
- q[0] = q[1];
- q[1] = saved;
-#endif
-}
-
-
void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
size_t size)
{
struct hpsb_packet *packet;
int length, rcode, extcode;
+ int source = data[1] >> 16;
u64 addr;
/* big FIXME - no error checking is done for an out of bounds length */
@@ -501,7 +503,7 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
switch (tcode) {
case TCODE_WRITEQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, data+3, addr, 4);
+ rcode = highlevel_write(host, source, data+3, addr, 4);
if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
@@ -513,7 +515,8 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
case TCODE_WRITEB:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, data+4, addr, data[3]>>16);
+ rcode = highlevel_write(host, source, data+4, addr,
+ data[3]>>16);
if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
@@ -527,7 +530,7 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
PREP_REPLY_PACKET(0);
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, data, addr, 4);
+ rcode = highlevel_read(host, source, data, addr, 4);
fill_async_readquad_resp(packet, rcode, *data);
send_packet_nocare(packet);
break;
@@ -537,7 +540,8 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
PREP_REPLY_PACKET(length);
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, packet->data, addr, length);
+ rcode = highlevel_read(host, source, packet->data, addr,
+ length);
fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
break;
@@ -556,35 +560,32 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
switch (length) {
case 4:
- rcode = highlevel_lock(host, packet->data, addr,
+ rcode = highlevel_lock(host, source, packet->data, addr,
data[4], 0, extcode);
fill_async_lock_resp(packet, rcode, extcode, 4);
break;
case 8:
if ((extcode != EXTCODE_FETCH_ADD)
&& (extcode != EXTCODE_LITTLE_ADD)) {
- rcode = highlevel_lock(host, packet->data, addr,
+ rcode = highlevel_lock(host, source,
+ packet->data, addr,
data[5], data[4],
extcode);
fill_async_lock_resp(packet, rcode, extcode, 4);
} else {
- swap_quadlets_on_le(data + 4);
- rcode = highlevel_lock64(host,
+ rcode = highlevel_lock64(host, source,
(octlet_t *)packet->data, addr,
*(octlet_t *)(data + 4), 0ULL,
extcode);
- swap_quadlets_on_le(packet->data);
fill_async_lock_resp(packet, rcode, extcode, 8);
}
break;
case 16:
- swap_quadlets_on_le(data + 4);
- swap_quadlets_on_le(data + 6);
- rcode = highlevel_lock64(host, (octlet_t *)packet->data,
- addr, *(octlet_t *)(data + 6),
+ rcode = highlevel_lock64(host, source,
+ (octlet_t *)packet->data, addr,
+ *(octlet_t *)(data + 6),
*(octlet_t *)(data + 4),
extcode);
- swap_quadlets_on_le(packet->data);
fill_async_lock_resp(packet, rcode, extcode, 8);
break;
default:
@@ -609,7 +610,9 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size)
return;
}
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
dump_packet("received packet:", data, size);
+#endif
tcode = (data[0] >> 4) & 0xf;
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index 171a2fa9f..636aef40e 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -40,29 +40,26 @@ struct hpsb_packet {
unsigned no_waiter:1;
/* Data big endianness flag - may vary from request to request. The
- * header is always in machine byte order. */
+ * header is always in machine byte order.
+ * Not really used currently. */
unsigned data_be:1;
/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
unsigned speed_code:2;
- /* --- 16 bytes (one cacheline) --- */
-
- /* *header and *data are guaranteed to be 32-bit DMAable and may be
+ /*
+ * *header and *data are guaranteed to be 32-bit DMAable and may be
* overwritten to allow in-place byte swapping. Neither of these is
* CRCed (the sizes also don't include CRC), but contain space for at
* least one additional quadlet to allow in-place CRCing. The memory is
* also guaranteed to have physical mapping (virt_to_bus() is meaningful
* on these pointers).
- * NOTE: The 32-bit DMA guarantee is currently not enforced.
- * That's a Linux 2.3 issue.
*/
quadlet_t *header;
quadlet_t *data;
size_t header_size;
size_t data_size;
- /* --- 32 bytes --- */
struct hpsb_host *host;
unsigned int generation;
@@ -139,12 +136,14 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
* for other cases (internal errors that don't justify a panic). Safe to call
* from within a transmit packet routine.
*/
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode);
+void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
+ int ackcode);
/*
* Hand over received packet to the core. The contents of data are expected to
* be the full packet but with the CRCs left out (data block follows header
- * immediately) and in machine byte order. *data can be safely overwritten
+ * immediately), with the header (i.e. the first four quadlets) in machine byte
+ * order and the data block in big endian. *data can be safely overwritten
* after this call.
*/
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size);
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index e2eeffc68..6f07a7f6a 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -68,7 +68,7 @@ void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
packet->header[3] = length << 16;
packet->header_size = 16;
- packet->data_size = length;
+ packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
}
void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data)
@@ -85,8 +85,8 @@ void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length)
PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
packet->header[3] = length << 16;
packet->header_size = 16;
- packet->data_size = length;
packet->expect_response = 1;
+ packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
}
void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
@@ -260,7 +260,7 @@ int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr,
quadlet_t *buffer, size_t length)
{
if (host->node_id != node) return -1;
- return highlevel_read(host, buffer, addr, length);
+ return highlevel_read(host, node, buffer, addr, length);
}
struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
@@ -284,7 +284,7 @@ struct hpsb_packet *hpsb_make_readbpacket(struct hpsb_host *host, nodeid_t node,
{
struct hpsb_packet *p;
- p = alloc_hpsb_packet(length);
+ p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
if (!p) return NULL;
p->host = host;
@@ -318,9 +318,13 @@ struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
{
struct hpsb_packet *p;
- p = alloc_hpsb_packet(length);
+ p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
if (!p) return NULL;
+ if (length % 4) {
+ p->data[length / 4] = 0;
+ }
+
p->host = host;
p->tlabel = get_tlabel(host, node, 1);
p->node_id = node;
@@ -370,7 +374,7 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
}
if (host->node_id == node) {
- switch(highlevel_read(host, buffer, addr, length)) {
+ switch(highlevel_read(host, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
@@ -381,16 +385,6 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
}
}
- if (length & 0x3) {
- /* FIXME: Lengths not multiple of 4 are not implemented. Mainly
- * there is the problem with little endian machines because we
- * always swap to little endian on receive. If we read 5 bytes
- * 12345 we receive them as 12345000 and swap them to 43210005.
- * How should we copy that to the caller? Require *buffer to be
- * a full quadlet multiple in length? */
- return -EACCES;
- }
-
if (length == 4) {
packet = hpsb_make_readqpacket(host, node, addr);
} else {
@@ -432,7 +426,7 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
}
if (host->node_id == node) {
- switch(highlevel_write(host, buffer, addr, length)) {
+ switch(highlevel_write(host, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
@@ -443,12 +437,6 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
}
}
- if (length & 0x3) {
- /* FIXME: Lengths not multiple of 4 are not implemented. See function
- * hpsb_read for explanation, same reason, different direction. */
- return -EACCES;
- }
-
if (length == 4) {
packet = hpsb_make_writeqpacket(host, node, addr, *buffer);
} else {
@@ -483,7 +471,8 @@ int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
int retval = 0, length;
if (host->node_id == node) {
- switch(highlevel_lock(host, data, addr, *data, arg, extcode)) {
+ switch(highlevel_lock(host, node, data, addr, *data, arg,
+ extcode)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
index d619182dd..d817e61c6 100644
--- a/drivers/ieee1394/ieee1394_types.h
+++ b/drivers/ieee1394/ieee1394_types.h
@@ -6,6 +6,7 @@
#include <linux/types.h>
#include <linux/version.h>
#include <linux/list.h>
+#include <asm/byteorder.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
@@ -24,6 +25,8 @@ static __inline__ void list_add_tail(struct list_head *new, struct list_head *he
__list_add(new, head->prev, head);
}
+#define __constant_cpu_to_be32(x) __constant_htonl((x))
+
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index b8fae7ee2..488e013fb 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -35,9 +35,18 @@
* . Config ROM
*
* Known bugs:
- * . Self-id are not received properly if card
- * is initialized with no other nodes on the
- * bus.
+ * . Self-id are sometimes not received properly
+ * if card is initialized with no other nodes
+ * on the bus
+ */
+
+/*
+ * Acknowledgments:
+ *
+ * Emilie Chung <emilie.chung@axis.com>
+ * .Tip on Async Request Filter
+ * Pascal Drolet <pascal.drolet@informission.ca>
+ * .Various tips for optimization and functionnalities
*/
#include <linux/config.h>
@@ -71,11 +80,15 @@
#include "ieee1394_core.h"
#include "ohci1394.h"
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define OHCI1394_DEBUG
+#endif
+
#ifdef DBGMSG
#undef DBGMSG
#endif
-#if OHCI1394_DEBUG
+#ifdef OHCI1394_DEBUG
#define DBGMSG(card, fmt, args...) \
printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args)
#else
@@ -97,10 +110,14 @@ printk(level "ohci1394_%d: " fmt "\n" , card , ## args)
return 1;
int supported_chips[][2] = {
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV22 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV23 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV26 },
{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
{ PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 },
{ -1, -1 }
};
@@ -213,7 +230,7 @@ inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
if (q[0] == ~q[1]) {
PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd",
q[0]);
- hpsb_selfid_received(host, q[0]);
+ hpsb_selfid_received(host, cpu_to_be32(q[0]));
if (((q[0]&0x3f000000)>>24)==phyid) {
lsid=q[0];
PRINT(KERN_INFO, ohci->id,
@@ -369,6 +386,23 @@ static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
}
+/* Count the number of available iso contexts */
+static int get_nb_iso_ctx(struct ti_ohci *ohci)
+{
+ int i,ctx=0;
+ u32 tmp;
+
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0xffffffff);
+ tmp = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+
+ /* Count the number of contexts */
+ for(i=0; i<32; i++) {
+ if(tmp & 1) ctx++;
+ tmp >>= 1;
+ }
+ return ctx;
+}
+
/* Global initialization */
static int ohci_initialize(struct hpsb_host *host)
{
@@ -411,15 +445,22 @@ static int ohci_initialize(struct hpsb_host *host)
virt_to_bus(ohci->csr_config_rom));
/* Write the config ROM header */
- reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->csr_config_rom[0]);
+ reg_write(ohci, OHCI1394_ConfigROMhdr,
+ cpu_to_be32(ohci->csr_config_rom[0]));
/* Set bus options */
- reg_write(ohci, OHCI1394_BusOptions, ohci->csr_config_rom[2]);
-
- /* Write the GUID into the csr config rom */
- ohci->csr_config_rom[3] = reg_read(ohci, OHCI1394_GUIDHi);
- ohci->csr_config_rom[4] = reg_read(ohci, OHCI1394_GUIDLo);
+ reg_write(ohci, OHCI1394_BusOptions,
+ cpu_to_be32(ohci->csr_config_rom[2]));
+ /* Write the GUID into the csr config rom */
+ ohci->csr_config_rom[3] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
+ ohci->csr_config_rom[4] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
+
+ ohci->max_packet_size =
+ 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
+ PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes",
+ ohci->max_packet_size);
+
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -427,7 +468,10 @@ static int ohci_initialize(struct hpsb_host *host)
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
/* Initialize IR dma */
- for (i=0;i<4;i++) { /* FIXME : how many contexts are available ? */
+ ohci->nb_iso_ctx = get_nb_iso_ctx(ohci);
+ PRINT(KERN_INFO, ohci->id, "%d iso contexts available",
+ ohci->nb_iso_ctx);
+ for (i=0;i<ohci->nb_iso_ctx;i++) {
reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i,
0xffffffff);
reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0);
@@ -465,7 +509,6 @@ static int ohci_initialize(struct hpsb_host *host)
* Accept AT requests from all nodes. This probably
* will have to be controlled from the subsystem
* on a per node basis.
- * (Tip by Emilie Chung <emilie.chung@axis.com>)
*/
reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
@@ -578,8 +621,9 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
unsigned char tcode;
int i=50;
- if (packet->data_size >= 4096) {
- PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)",
+ if (packet->data_size >= ohci->max_packet_size) {
+ PRINT(KERN_ERR, ohci->id,
+ "transmit packet size = %d too big",
packet->data_size);
return 0;
}
@@ -587,24 +631,8 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
/* Decide wether we have a request or a response packet */
tcode = (packet->header[0]>>4)&0xf;
- if ((tcode==TCODE_READQ)||
- (tcode==TCODE_WRITEQ)||
- (tcode==TCODE_READB)||
- (tcode==TCODE_WRITEB)||
- (tcode==TCODE_LOCK_REQUEST))
- d = ohci->at_req_context;
-
- else if ((tcode==TCODE_WRITE_RESPONSE)||
- (tcode==TCODE_READQ_RESPONSE)||
- (tcode==TCODE_READB_RESPONSE)||
- (tcode==TCODE_LOCK_RESPONSE))
- d = ohci->at_resp_context;
-
- else {
- PRINT(KERN_ERR, ohci->id,
- "Unexpected packet tcode=%d in AT DMA", tcode);
- return 0;
- }
+ if (tcode & 0x02) d = ohci->at_resp_context;
+ else d = ohci->at_req_context;
spin_lock(&d->lock);
@@ -659,6 +687,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
switch (cmd) {
case RESET_BUS:
+ host->attempt_root=1;
PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
(host->attempt_root ? " and attempting to become root"
: ""));
@@ -679,15 +708,21 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
break;
case ACT_CYCLE_MASTER:
-#if 0
if (arg) {
- /* enable cycleTimer, cycleMaster, cycleSource */
- reg_write(ohci, OHCI1394_LinkControlSet, 0x00700000);
+ /* check if we are root and other nodes are present */
+ u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
+ if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
+ /*
+ * enable cycleTimer cycleMaster cycleSource
+ */
+ DBGMSG(ohci->id, "Cycle master enabled");
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ 0x00700000);
+ }
} else {
/* disable cycleTimer, cycleMaster, cycleSource */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000);
- };
-#endif
+ }
break;
case CANCEL_REQUESTS:
@@ -811,8 +846,20 @@ static void ohci_irq_handler(int irq, void *dev_id,
struct hpsb_host *host = ohci->host;
int phyid = -1, isroot = 0;
+ /* read the interrupt event register */
event=reg_read(ohci, OHCI1394_IntEventSet);
+#if 0
+ /*
+ * clear the interrupt event register, except for the
+ * bus reset event interrupt (if any). This is an
+ * attempt to comply with ohci spec 7.2.3.2
+ */
+ reg_write(ohci, OHCI1394_IntEventClear, event & (~OHCI1394_busReset));
+#else
+ /* The above attempt doesn't work */
+ reg_write(ohci, OHCI1394_IntEventClear, event);
+#endif
if (event & OHCI1394_busReset) {
if (!host->in_bus_reset) {
PRINT(KERN_INFO, ohci->id, "Bus reset");
@@ -821,6 +868,11 @@ static void ohci_irq_handler(int irq, void *dev_id,
dma_trm_reset(ohci->at_req_context);
dma_trm_reset(ohci->at_resp_context);
+#if 0
+ /* clear the bus reset event */
+ reg_write(ohci, OHCI1394_IntEventClear,
+ OHCI1394_busReset);
+#endif
/* Subsystem call */
hpsb_bus_reset(ohci->host);
@@ -891,7 +943,7 @@ static void ohci_irq_handler(int irq, void *dev_id,
if (event & OHCI1394_selfIDComplete) {
if (host->in_bus_reset) {
node_id = reg_read(ohci, OHCI1394_NodeID);
- if (node_id & 0x8000000) { /* NodeID valid */
+ if (node_id & 0x80000000) { /* NodeID valid */
phyid = node_id & 0x0000003f;
isroot = (node_id & 0x40000000) != 0;
@@ -924,8 +976,6 @@ static void ohci_irq_handler(int irq, void *dev_id,
#endif
}
- /* clear the interrupt event register */
- reg_write(ohci, OHCI1394_IntEventClear, event);
}
/* Put the buffer back into the dma context */
@@ -963,44 +1013,34 @@ static int block_length(struct dma_rcv_ctx *d, int idx,
return length;
}
-static int packet_length(struct dma_rcv_ctx *d, int idx,
- quadlet_t *buf_ptr, int offset)
+const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
+ -1, 0, -1, 0, -1, -1, 16, -1};
+
+/*
+ * Determine the length of a packet in the buffer
+ * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
+ */
+static int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
+int offset)
{
- unsigned char tcode;
- int length;
+ unsigned char tcode;
+ int length = -1;
/* Let's see what kind of packet is in there */
- tcode = (buf_ptr[0]>>4)&0xf;
-
- if (d->ctx==0) { /* Async Receive Request */
- if (tcode==TCODE_READQ) return 16;
- else if (tcode==TCODE_WRITEQ ||
- tcode==TCODE_READB) return 20;
- else if (tcode==TCODE_WRITEB ||
- tcode==TCODE_LOCK_REQUEST) {
- return block_length(d, idx, buf_ptr, offset) + 20;
- }
- else if (tcode==0xE) { /* Phy packet */
- return 16;
- }
- else return -1;
- }
- else if (d->ctx==1) { /* Async Receive Response */
- if (tcode==TCODE_WRITE_RESPONSE) return 16;
- else if (tcode==TCODE_READQ_RESPONSE) return 20;
- else if (tcode==TCODE_READB_RESPONSE ||
- tcode==TCODE_LOCK_RESPONSE) {
- return block_length(d, idx, buf_ptr, offset) + 20;
- }
- else return -1;
+ tcode = (buf_ptr[0] >> 4) & 0xf;
+
+ if (d->ctx < 2) { /* Async Receive Response/Request */
+ length = TCODE_SIZE[tcode];
+ if (length == 0)
+ length = block_length(d, idx, buf_ptr, offset) + 20;
}
else if (d->ctx==2) { /* Iso receive */
/* Assumption: buffer fill mode with header/trailer */
length = (buf_ptr[0]>>16);
if (length % 4) length += 4 - (length % 4);
- return length+8;
+ length+=8;
}
- return -1;
+ return length;
}
/* Bottom half that processes dma receive buffers */
@@ -1336,6 +1376,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
static int add_card(struct pci_dev *dev)
{
struct ti_ohci *ohci; /* shortcut to currently handled device */
+ int i;
if (num_of_cards == MAX_OHCI1394_CARDS) {
PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
@@ -1344,6 +1385,10 @@ static int add_card(struct pci_dev *dev)
return 1;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ pci_enable_device(dev);
+#endif
+
ohci = &cards[num_of_cards++];
ohci->id = num_of_cards-1;
@@ -1363,7 +1408,11 @@ static int add_card(struct pci_dev *dev)
if (ohci->csr_config_rom == NULL) {
FAIL("failed to allocate buffer config rom");
}
- memcpy(ohci->csr_config_rom, ohci_csr_rom, sizeof(ohci_csr_rom));
+ for (i=0;i<sizeof(ohci_csr_rom)/4;i++)
+ ohci->csr_config_rom[i] = cpu_to_be32(ohci_csr_rom[i]);
+
+ DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x",
+ *((char *)ohci->csr_config_rom+4));
/* self-id dma buffer allocation */
ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL);
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index 46d9a270f..f0ec83d48 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -4,16 +4,18 @@
#include "ieee1394_types.h"
-#define OHCI1394_DEBUG 1
-
#define OHCI1394_DRIVER_NAME "ohci1394"
-#ifndef PCI_DEVICE_ID_TI_OHCI1394
-#define PCI_DEVICE_ID_TI_OHCI1394 0x8009
-#endif
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV22
+#define PCI_DEVICE_ID_TI_OHCI1394_LV22 0x8009
+#endif
+
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV23
+#define PCI_DEVICE_ID_TI_OHCI1394_LV23 0x8019
+#endif
-#ifndef PCI_DEVICE_ID_TI_OHCI1394_2
-#define PCI_DEVICE_ID_TI_OHCI1394_2 0x8019
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV26
+#define PCI_DEVICE_ID_TI_OHCI1394_LV26 0x8020
#endif
#ifndef PCI_DEVICE_ID_VIA_OHCI1394
@@ -28,6 +30,22 @@
#define PCI_DEVICE_ID_SONY_CXD3222 0x8039
#endif
+#ifndef PCI_DEVICE_ID_NEC_1394
+#define PCI_DEVICE_ID_NEC_1394 0x00cd
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72862
+#define PCI_DEVICE_ID_NEC_UPD72862 0x0063
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72870
+#define PCI_DEVICE_ID_NEC_UPD72870 0x00cd
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72871
+#define PCI_DEVICE_ID_NEC_UPD72871 0x00ce
+#endif
+
#define MAX_OHCI1394_CARDS 4
#define OHCI1394_MAX_AT_REQ_RETRIES 0x2
@@ -113,6 +131,8 @@ struct ti_ohci {
quadlet_t *self_id_buffer; /* dma buffer for self-id packets */
quadlet_t *csr_config_rom; /* buffer for csr config rom */
+ unsigned int max_packet_size;
+
/* async receive */
struct dma_rcv_ctx *ar_resp_context;
struct dma_rcv_ctx *ar_req_context;
@@ -125,6 +145,7 @@ struct ti_ohci {
struct dma_rcv_ctx *ir_context;
u64 IR_channel_usage;
spinlock_t IR_channel_lock;
+ int nb_iso_ctx;
/* IEEE-1394 part follows */
struct hpsb_host *host;
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 2714a6eb5..773d68983 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -59,6 +59,13 @@
/* print card specific information */
#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
+#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
+#else
+#define PRINT_GD(level, fmt, args...)
+#define PRINTD(level, card, fmt, args...)
+#endif
static struct ti_lynx cards[MAX_PCILYNX_CARDS];
static int num_of_cards = 0;
@@ -313,7 +320,8 @@ static quadlet_t generate_own_selfid(struct ti_lynx *lynx,
}
}
- printk("-%d- generated own selfid 0x%x\n", lynx->id, lsid);
+ cpu_to_be32s(&lsid);
+ PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);
return lsid;
}
@@ -322,7 +330,14 @@ static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t s
quadlet_t *q = lynx->rcv_page;
int phyid, isroot;
quadlet_t lsid = 0;
+ int i;
+ i = (size > 16 ? 16 : size) / 4 - 1;
+ while (i >= 0) {
+ cpu_to_be32s(&q[i]);
+ i--;
+ }
+
if (!lynx->phyic.reg_1394a) {
lsid = generate_own_selfid(lynx, host);
}
@@ -339,17 +354,20 @@ static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t s
}
while (size > 0) {
- if (!lynx->phyic.reg_1394a
- && (q[0] & 0x3f800000) == ((phyid + 1) << 24)) {
+ struct selfid *sid = (struct selfid *)q;
+
+ if (!lynx->phyic.reg_1394a && !sid->extended
+ && (sid->phy_id == (phyid + 1))) {
hpsb_selfid_received(host, lsid);
}
if (q[0] == ~q[1]) {
- printk("-%d- selfid packet 0x%x rcvd\n", lynx->id, q[0]);
+ PRINT(KERN_DEBUG, lynx->id, "selfid packet 0x%x rcvd",
+ q[0]);
hpsb_selfid_received(host, q[0]);
} else {
- printk("-%d- inconsistent selfid 0x%x/0x%x\n", lynx->id,
- q[0], q[1]);
+ PRINT(KERN_INFO, lynx->id,
+ "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
}
q += 2;
size -= 8;
@@ -429,14 +447,14 @@ static int lynx_initialize(struct hpsb_host *host)
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
#ifdef __BIG_ENDIAN
- pcl.buffer[0].control = PCL_CMD_RCV | 2048;
- pcl.buffer[1].control = PCL_LAST_BUFF | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#else
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 2048;
- pcl.buffer[1].control = PCL_LAST_BUFF | PCL_BIGENDIAN | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#endif
pcl.buffer[0].pointer = virt_to_bus(lynx->rcv_page);
- pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 2048;
+ pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 16;
put_pcl(lynx, lynx->rcv_pcl, &pcl);
pcl.next = pcl_bus(lynx, lynx->async_pcl);
@@ -445,10 +463,11 @@ static int lynx_initialize(struct hpsb_host *host)
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_LAST_BUFF | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | 4;
#ifndef __BIG_ENDIAN
pcl.buffer[0].control |= PCL_BIGENDIAN;
#endif
+ pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
for (i = 0; i < NUM_ISORCV_PCL; i++) {
int page = i / ISORCV_PER_PAGE;
@@ -456,6 +475,7 @@ static int lynx_initialize(struct hpsb_host *host)
pcl.buffer[0].pointer = virt_to_bus(lynx->iso_rcv.page[page])
+ sec * MAX_ISORCV_SIZE;
+ pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
}
@@ -539,6 +559,10 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
}
packet->xnext = NULL;
+ if (packet->tcode == TCODE_WRITEQ
+ || packet->tcode == TCODE_READQ_RESPONSE) {
+ cpu_to_be32s(&packet->header[3]);
+ }
spin_lock_irqsave(&lynx->async_queue_lock, flags);
@@ -1054,8 +1078,8 @@ static void lynx_irq_handler(int irq, void *dev_id,
}
if (linkint & LINK_INT_PHY_REG_RCVD) {
if (!host->in_bus_reset) {
- printk("-%d- phy reg received without reset\n",
- lynx->id);
+ PRINT(KERN_INFO, lynx->id,
+ "phy reg received without reset");
}
}
if (linkint & LINK_INT_ISO_STUCK) {
@@ -1082,7 +1106,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
}
if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
- PRINT(KERN_INFO, lynx->id, "iso receive");
+ PRINTD(KERN_DEBUG, lynx->id, "iso receive");
spin_lock(&lynx->iso_rcv.lock);
@@ -1094,7 +1118,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
|| !lynx->iso_rcv.chan_count) {
- printk("stopped\n");
+ PRINTD(KERN_DEBUG, lynx->id, "stopped");
reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
}
@@ -1125,9 +1149,9 @@ static void lynx_irq_handler(int irq, void *dev_id,
spin_unlock(&lynx->async_queue_lock);
if (ack & DMA_CHAN_STAT_SPECIALACK) {
- printk("-%d- special ack %d\n", lynx->id,
- (ack >> 15) & 0xf);
- ack = ACKX_SEND_ERROR;
+ ack = (ack >> 15) & 0xf;
+ PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
+ ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
} else {
ack = (ack >> 15) & 0xf;
}
@@ -1139,7 +1163,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
/* general receive DMA completed */
int stat = reg_read(lynx, DMA1_CHAN_STAT);
- printk("-%d- received packet size %d\n", lynx->id,
+ PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",
stat & 0x1fff);
if (stat & DMA_CHAN_STAT_SELFID) {
@@ -1149,8 +1173,12 @@ static void lynx_irq_handler(int irq, void *dev_id,
| LINK_CONTROL_TX_ASYNC_EN
| LINK_CONTROL_RX_ASYNC_EN);
} else {
- hpsb_packet_received(host, lynx->rcv_page,
- stat & 0x1fff);
+ quadlet_t *q_data = lynx->rcv_page;
+ if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE
+ || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
+ cpu_to_be32s(q_data + 3);
+ }
+ hpsb_packet_received(host, q_data, stat & 0x1fff);
}
run_pcl(lynx, lynx->rcv_pcl_start, 1);
@@ -1411,7 +1439,7 @@ static int init_driver()
}
if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
- PRINT_G(KERN_ERR, "allocation of char major number %d failed\n",
+ PRINT_G(KERN_ERR, "allocation of char major number %d failed",
PCILYNX_MAJOR);
return -EBUSY;
}
@@ -1453,13 +1481,13 @@ MODULE_SUPPORTED_DEVICE("pcilynx");
void cleanup_module(void)
{
hpsb_unregister_lowlevel(get_lynx_template());
- PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module\n");
+ PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
}
int init_module(void)
{
if (hpsb_register_lowlevel(get_lynx_template())) {
- PRINT_G(KERN_ERR, "registering failed\n");
+ PRINT_G(KERN_ERR, "registering failed");
return -ENXIO;
} else {
return 0;
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
index 2809bde08..f8154bb42 100644
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -462,71 +462,75 @@ inline static void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
#define PCL_BIGENDIAN (1<<16)
+#define _(x) (__constant_cpu_to_be32(x))
+
quadlet_t lynx_csr_rom[] = {
/* bus info block */
- 0x04040000, /* info/CRC length, CRC */
- 0x31333934, /* 1394 magic number */
- 0xf064a000, /* misc. settings */
- 0x08002850, /* vendor ID, chip ID high */
- 0x0000ffff, /* chip ID low */
+ _(0x04040000), /* info/CRC length, CRC */
+ _(0x31333934), /* 1394 magic number */
+ _(0xf064a000), /* misc. settings */
+ _(0x08002850), /* vendor ID, chip ID high */
+ _(0x0000ffff), /* chip ID low */
/* root directory */
- 0x00090000, /* CRC length, CRC */
- 0x03080028, /* vendor ID (Texas Instr.) */
- 0x81000009, /* offset to textual ID */
- 0x0c000200, /* node capabilities */
- 0x8d00000e, /* offset to unique ID */
- 0xc7000010, /* offset to module independent info */
- 0x04000000, /* module hardware version */
- 0x81000026, /* offset to textual ID */
- 0x09000000, /* node hardware version */
- 0x81000026, /* offset to textual ID */
+ _(0x00090000), /* CRC length, CRC */
+ _(0x03080028), /* vendor ID (Texas Instr.) */
+ _(0x81000009), /* offset to textual ID */
+ _(0x0c000200), /* node capabilities */
+ _(0x8d00000e), /* offset to unique ID */
+ _(0xc7000010), /* offset to module independent info */
+ _(0x04000000), /* module hardware version */
+ _(0x81000026), /* offset to textual ID */
+ _(0x09000000), /* node hardware version */
+ _(0x81000026), /* offset to textual ID */
/* module vendor ID textual */
- 0x00080000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54455841, /* "Texas Instruments" */
- 0x5320494e,
- 0x53545255,
- 0x4d454e54,
- 0x53000000,
+ _(0x00080000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54455841), /* "Texas Instruments" */
+ _(0x5320494e),
+ _(0x53545255),
+ _(0x4d454e54),
+ _(0x53000000),
/* node unique ID leaf */
- 0x00020000, /* CRC length, CRC */
- 0x08002850, /* vendor ID, chip ID high */
- 0x0000ffff, /* chip ID low */
+ _(0x00020000), /* CRC length, CRC */
+ _(0x08002850), /* vendor ID, chip ID high */
+ _(0x0000ffff), /* chip ID low */
/* module dependent info */
- 0x00060000, /* CRC length, CRC */
- 0xb8000006, /* offset to module textual ID */
- 0x81000004, /* ??? textual descriptor */
- 0x39010000, /* SRAM size */
- 0x3a010000, /* AUXRAM size */
- 0x3b000000, /* AUX device */
+ _(0x00060000), /* CRC length, CRC */
+ _(0xb8000006), /* offset to module textual ID */
+ _(0x81000004), /* ??? textual descriptor */
+ _(0x39010000), /* SRAM size */
+ _(0x3a010000), /* AUXRAM size */
+ _(0x3b000000), /* AUX device */
/* module textual ID */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54534231, /* "TSB12LV21" */
- 0x324c5632,
- 0x31000000,
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54534231), /* "TSB12LV21" */
+ _(0x324c5632),
+ _(0x31000000),
/* part number */
- 0x00060000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x39383036, /* "9806000-0001" */
- 0x3030342d,
- 0x30303431,
- 0x20000001,
+ _(0x00060000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x39383036), /* "9806000-0001" */
+ _(0x3030342d),
+ _(0x30303431),
+ _(0x20000001),
/* module hardware version textual */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x5453424b, /* "TSBKPCITST" */
- 0x50434954,
- 0x53540000,
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x5453424b), /* "TSBKPCITST" */
+ _(0x50434954),
+ _(0x53540000),
/* node hardware version textual */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54534232, /* "TSB21LV03" */
- 0x313c5630,
- 0x33000000
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54534232), /* "TSB21LV03" */
+ _(0x313c5630),
+ _(0x33000000)
};
+
+#undef _
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 0e63acb33..4a994aba5 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -59,7 +59,7 @@ static void free_pending_request(struct pending_request *req)
{
if (req->ibs) {
if (atomic_dec_and_test(&req->ibs->refcount)) {
- atomic_sub((req->data[0] >> 16) + 4, &iso_buffer_size);
+ atomic_sub(req->ibs->data_size, &iso_buffer_size);
kfree(req->ibs);
}
} else if (req->free_data) {
@@ -109,6 +109,7 @@ static void queue_complete_cb(struct pending_request *req)
}
free_tlabel(packet->host, packet->node_id, packet->tlabel);
+
queue_complete_req(req);
}
@@ -215,6 +216,7 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
LIST_HEAD(reqs);
if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+ HPSB_INFO("dropped iso packet");
return;
}
@@ -230,22 +232,23 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
continue;
}
+ req = __alloc_pending_request(SLAB_ATOMIC);
+ if (!req) break;
+
if (!ibs) {
ibs = kmalloc(sizeof(struct iso_block_store)
+ length, SLAB_ATOMIC);
- if (!ibs) break;
+ if (!ibs) {
+ kfree(req);
+ break;
+ }
atomic_add(length, &iso_buffer_size);
atomic_set(&ibs->refcount, 0);
+ ibs->data_size = length;
memcpy(ibs->data, data, length);
}
- req = __alloc_pending_request(SLAB_ATOMIC);
- if (!req) {
- kfree(ibs);
- break;
- }
-
atomic_inc(&ibs->refcount);
req->file_info = fi;
@@ -270,6 +273,75 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
}
}
+static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, unsigned int length)
+{
+ unsigned long flags;
+ struct list_head *lh;
+ struct host_info *hi;
+ struct file_info *fi;
+ struct pending_request *req;
+ struct iso_block_store *ibs = NULL;
+ LIST_HEAD(reqs);
+
+ if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+ HPSB_INFO("dropped fcp request");
+ return;
+ }
+
+ spin_lock_irqsave(&host_info_lock, flags);
+ hi = find_host_info(host);
+
+ if (hi != NULL) {
+ for (lh = hi->file_info_list.next; lh != &hi->file_info_list;
+ lh = lh->next) {
+ fi = list_entry(lh, struct file_info, list);
+
+ if (!fi->fcp_buffer) {
+ continue;
+ }
+
+ req = __alloc_pending_request(SLAB_ATOMIC);
+ if (!req) break;
+
+ if (!ibs) {
+ ibs = kmalloc(sizeof(struct iso_block_store)
+ + length, SLAB_ATOMIC);
+ if (!ibs) {
+ kfree(req);
+ break;
+ }
+
+ atomic_add(length, &iso_buffer_size);
+ atomic_set(&ibs->refcount, 0);
+ ibs->data_size = length;
+ memcpy(ibs->data, data, length);
+ }
+
+ atomic_inc(&ibs->refcount);
+
+ req->file_info = fi;
+ req->ibs = ibs;
+ req->data = ibs->data;
+ req->req.type = RAW1394_REQ_FCP_REQUEST;
+ req->req.generation = get_hpsb_generation();
+ req->req.misc = nodeid | (direction << 16);
+ req->req.recvb = (quadlet_t *)fi->fcp_buffer;
+ req->req.length = length;
+
+ list_add_tail(&req->list, &reqs);
+ }
+ }
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
+ lh = reqs.next;
+ while (lh != &reqs) {
+ req = list_entry(lh, struct pending_request, list);
+ lh = lh->next;
+ queue_complete_req(req);
+ }
+}
+
static int dev_read(struct file *file, char *buffer, size_t count,
loff_t *offset_is_ignored)
@@ -455,8 +527,28 @@ static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
spin_unlock(&host_info_lock);
}
+static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
+{
+ if (req->req.misc) {
+ if (fi->fcp_buffer) {
+ req->req.error = RAW1394_ERROR_ALREADY;
+ } else {
+ fi->fcp_buffer = (u8 *)req->req.recvb;
+ }
+ } else {
+ if (!fi->fcp_buffer) {
+ req->req.error = RAW1394_ERROR_ALREADY;
+ } else {
+ fi->fcp_buffer = NULL;
+ }
+ }
+
+ req->req.length = 0;
+ queue_complete_req(req);
+}
+
static int handle_local_request(struct file_info *fi,
- struct pending_request *req)
+ struct pending_request *req, int node)
{
u64 addr = req->req.address & 0xffffffffffffULL;
@@ -466,7 +558,7 @@ static int handle_local_request(struct file_info *fi,
switch (req->req.type) {
case RAW1394_REQ_ASYNC_READ:
- req->req.error = highlevel_read(fi->host, req->data, addr,
+ req->req.error = highlevel_read(fi->host, node, req->data, addr,
req->req.length);
break;
@@ -477,8 +569,8 @@ static int handle_local_request(struct file_info *fi,
break;
}
- req->req.error = highlevel_write(fi->host, req->data, addr,
- req->req.length);
+ req->req.error = highlevel_write(fi->host, node, req->data,
+ addr, req->req.length);
req->req.length = 0;
break;
@@ -503,14 +595,16 @@ static int handle_local_request(struct file_info *fi,
}
if (req->req.length == 8) {
- req->req.error = highlevel_lock(fi->host, req->data,
- addr, req->data[1],
+ req->req.error = highlevel_lock(fi->host, node,
+ req->data, addr,
+ req->data[1],
req->data[0],
req->req.misc);
req->req.length = 4;
} else {
- req->req.error = highlevel_lock(fi->host, req->data,
- addr, req->data[0], 0,
+ req->req.error = highlevel_lock(fi->host, node,
+ req->data, addr,
+ req->data[0], 0,
req->req.misc);
}
break;
@@ -539,28 +633,27 @@ static int handle_remote_request(struct file_info *fi,
if (!packet) return -ENOMEM;
req->data = &packet->header[3];
- } else if ((req->req.length % 4) == 0) {
+ } else {
packet = hpsb_make_readbpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
req->data = packet->data;
- } else {
- req->req.error = RAW1394_ERROR_UNTIDY_LEN;
}
break;
case RAW1394_REQ_ASYNC_WRITE:
if (req->req.length == 4) {
- packet = hpsb_make_writeqpacket(fi->host, node, addr,
- 0);
- if (!packet) return -ENOMEM;
+ quadlet_t x;
- if (copy_from_user(&packet->header[3], req->req.sendb,
- 4)) {
+ if (copy_from_user(&x, req->req.sendb, 4)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
- } else if ((req->req.length % 4) == 0) {
+
+ packet = hpsb_make_writeqpacket(fi->host, node, addr,
+ x);
+ if (!packet) return -ENOMEM;
+ } else {
packet = hpsb_make_writebpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
@@ -569,8 +662,6 @@ static int handle_remote_request(struct file_info *fi,
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
- } else {
- req->req.error = RAW1394_ERROR_UNTIDY_LEN;
}
req->req.length = 0;
break;
@@ -649,6 +740,11 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
return sizeof(struct raw1394_request);
}
+ if (req->req.type == RAW1394_REQ_FCP_LISTEN) {
+ handle_fcp_listen(fi, req);
+ return sizeof(struct raw1394_request);
+ }
+
if (req->req.length == 0) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
queue_complete_req(req);
@@ -656,7 +752,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
}
if (fi->host->node_id == node) {
- return handle_local_request(fi, req);
+ return handle_local_request(fi, req, node);
}
return handle_remote_request(fi, req, node);
@@ -806,10 +902,11 @@ static int dev_release(struct inode *inode, struct file *file)
}
static struct hpsb_highlevel_ops hl_ops = {
- add_host,
- remove_host,
- host_reset,
- iso_receive
+ add_host: add_host,
+ remove_host: remove_host,
+ host_reset: host_reset,
+ iso_receive: iso_receive,
+ fcp_request: fcp_request,
};
static struct file_operations file_ops = {
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
index b1b0e4b90..f23bfc051 100644
--- a/drivers/ieee1394/raw1394.h
+++ b/drivers/ieee1394/raw1394.h
@@ -5,7 +5,7 @@
#define RAW1394_DEVICE_MAJOR 171
#define RAW1394_DEVICE_NAME "raw1394"
-#define RAW1394_KERNELAPI_VERSION 1
+#define RAW1394_KERNELAPI_VERSION 2
/* state: opened */
#define RAW1394_REQ_INITIALIZE 1
@@ -21,10 +21,12 @@
#define RAW1394_REQ_LOCK64 103
#define RAW1394_REQ_ISO_LISTEN 200
+#define RAW1394_REQ_FCP_LISTEN 201
/* kernel to user */
#define RAW1394_REQ_BUS_RESET 10000
#define RAW1394_REQ_ISO_RECEIVE 10001
+#define RAW1394_REQ_FCP_REQUEST 10002
/* error codes */
#define RAW1394_ERROR_NONE 0
@@ -67,6 +69,7 @@ struct raw1394_khost_list {
struct iso_block_store {
atomic_t refcount;
+ size_t data_size;
quadlet_t data[0];
};
@@ -83,6 +86,8 @@ struct file_info {
spinlock_t reqlists_lock;
wait_queue_head_t poll_wait_complete;
+ u8 *fcp_buffer;
+
u64 listen_channels;
quadlet_t *iso_buffer;
size_t iso_buffer_length;
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index a73c26766..e4ba2cf1f 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -85,8 +85,14 @@ dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
fi
-dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
-if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
+dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ bool 'CAPI2.0 Middleware support' CONFIG_ISDN_CAPI_MIDDLEWARE
+ if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" != "n" ]; then
+ bool 'CAPI2.0 filesystem support' CONFIG_ISDN_CAPIFS
+ fi
+fi
+if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index c94551716..b1e43f487 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -97,12 +97,12 @@ else
endif
endif
-ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
+ifeq ($(CONFIG_ISDN_CAPI),y)
L_OBJS += avmb1/avmb1.o
SUB_DIRS += avmb1
MOD_SUB_DIRS += avmb1
else
- ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
+ ifeq ($(CONFIG_ISDN_CAPI),m)
MOD_SUB_DIRS += avmb1
endif
endif
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
index bfeb81939..77a701611 100644
--- a/drivers/isdn/avmb1/Makefile
+++ b/drivers/isdn/avmb1/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $
+# $Id: Makefile,v 1.16 2000/03/17 12:15:44 calle Exp $
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
@@ -11,6 +11,49 @@
# parent makes..
#
# $Log: Makefile,v $
+# Revision 1.16 2000/03/17 12:15:44 calle
+# ALL_SUB_DIRS were wrong.
+#
+# Revision 1.15 2000/03/16 15:21:03 calle
+# Bugfix in c4_remove: loop 5 times instead of 4 :-(
+#
+# Revision 1.14 2000/03/13 17:50:55 calle
+# Added avm_cs.c for 2.3.x PCMCIA support.
+#
+# Revision 1.13 2000/03/08 17:06:33 calle
+# - changes for devfs and 2.3.49
+# - capifs now configurable (no need with devfs)
+# - New Middleware ioctl CAPI_NCCI_GETUNIT
+# - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+#
+# Revision 1.12 2000/03/06 18:00:23 calle
+# - Middleware extention now working with 2.3.49 (capifs).
+# - Fixed typos in debug section of capi.c
+# - Bugfix: Makefile corrected for b1pcmcia.c
+#
+# Revision 1.11 2000/03/06 09:17:07 calle
+# - capifs: fileoperations now in inode (change for 2.3.49)
+# - Config.in: Middleware extention not a tristate, uups.
+#
+# Revision 1.10 2000/03/03 16:48:38 calle
+# - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+# It is now possible to create a connection with a CAPI2.0 applikation
+# and than to handle the data connection from /dev/capi/ (capifs) and also
+# using async or sync PPP on this connection.
+# The two major device number 190 and 191 are not confirmed yet,
+# but I want to save the code in cvs, before I go on.
+#
+# Revision 1.9 2000/03/03 15:50:42 calle
+# - kernel CAPI:
+# - Changed parameter "param" in capi_signal from __u32 to void *.
+# - rewrote notifier handling in kcapi.c
+# - new notifier NCCI_UP and NCCI_DOWN
+# - User CAPI:
+# - /dev/capi20 is now a cloning device.
+# - middleware extentions prepared.
+# - capidrv.c
+# - locking of list operations and module count updates.
+#
# Revision 1.8 2000/01/25 14:33:38 calle
# - Added Support AVM B1 PCI V4.0 (tested with prototype)
# - splitted up t1pci.c into b1dma.c for common function with b1pciv4
@@ -64,6 +107,9 @@
#
#
+SUB_DIRS :=
+MOD_SUB_DIRS :=
+ALL_SUB_DIRS := # fcpci fcclassic
#
# Objects that don't export a symtab
#
@@ -82,53 +128,78 @@ MX_OBJS := # used as module
O_TARGET := # used for .o targets (from O and OX objects)
L_TARGET := # used for .a targets (from L and LX objects)
-ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
+ifeq ($(CONFIG_ISDN_CAPI),y)
O_TARGET += avmb1.o
OX_OBJS += kcapi.o
O_OBJS += capi.o
+ ifdef CONFIG_ISDN_CAPIFS
+ OX_OBJS += capifs.o
+ endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
- O_OBJS += b1isa.o
+ O_OBJS += b1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
- O_OBJS += b1pci.o
+ O_OBJS += b1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
- O_OBJS += t1isa.o
+ O_OBJS += t1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- OX_OBJS += b1pcmcia.o
+ OX_OBJS += b1pcmcia.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
- O_OBJS += t1pci.o
+ O_OBJS += t1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_C4
- O_OBJS += c4.o
+ O_OBJS += c4.o
endif
- OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
-else
- ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
- O_TARGET += kernelcapi.o
- OX_OBJS += kcapi.o
- M_OBJS += capi.o kernelcapi.o
- ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
- M_OBJS += b1isa.o
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
- M_OBJS += b1pci.o
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI
+ SUB_DIRS += fcpci
+ MOD_SUB_DIRS += fcpci
endif
- ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
- M_OBJS += t1isa.o
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC
+ SUB_DIRS += fcclassic
+ MOD_SUB_DIRS += fcclassic
endif
- ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- MX_OBJS += b1pcmcia.o
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
- M_OBJS += t1pci.o
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_C4
- M_OBJS += c4.o
- endif
- MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
+ OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
+else
+ ifeq ($(CONFIG_ISDN_CAPI),m)
+ O_TARGET += kernelcapi.o
+ OX_OBJS += kcapi.o
+ M_OBJS += capi.o kernelcapi.o
+ ifdef CONFIG_ISDN_CAPIFS
+ MX_OBJS += capifs.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
+ M_OBJS += b1isa.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
+ M_OBJS += b1pci.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
+ M_OBJS += t1isa.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ MX_OBJS += b1pcmcia.o
+ ifeq ($(CONFIG_HOTPLUG),y)
+ ifneq ($(CONFIG_PCMCIA),n)
+ M_OBJS += avm_cs.o
+ endif
+ endif
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
+ M_OBJS += t1pci.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_C4
+ M_OBJS += c4.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI
+ MOD_SUB_DIRS += fcpci
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC
+ MOD_SUB_DIRS += fcclassic
+ endif
+ MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
endif
endif
diff --git a/drivers/isdn/avmb1/avm_cs.c b/drivers/isdn/avmb1/avm_cs.c
new file mode 100644
index 000000000..4b8c9a1b4
--- /dev/null
+++ b/drivers/isdn/avmb1/avm_cs.c
@@ -0,0 +1,528 @@
+/*======================================================================
+
+ A PCMCIA client driver for AVM B1/M1/M2
+
+ Written by Carsten Paeth, calle@calle.in-berlin.de
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <linux/skbuff.h>
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+#include <linux/b1pcmcia.h>
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* This means pick from 15, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static int default_irq_list[10] = { 15, 12, 11, 10, 9, 7, 5, 4, 3, -1 };
+static int irq_list[10] = { -1 };
+
+MODULE_PARM(irq_list, "1-10i");
+
+/*====================================================================*/
+
+/*
+ The event() function is this driver's Card Services event handler.
+ It will be called by Card Services when an appropriate card status
+ event is received. The config() and release() entry points are
+ used to configure or release a socket, in response to card insertion
+ and ejection events. They are invoked from the skeleton event
+ handler.
+*/
+
+static void avmcs_config(dev_link_t *link);
+static void avmcs_release(u_long arg);
+static int avmcs_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+/*
+ The attach() and detach() entry points are used to create and destroy
+ "instances" of the driver, where each instance represents everything
+ needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *avmcs_attach(void);
+static void avmcs_detach(dev_link_t *);
+
+/*
+ The dev_info variable is the "key" that is used to match up this
+ device driver with appropriate cards, through the card configuration
+ database.
+*/
+
+static dev_info_t dev_info = "avm_cs";
+
+/*
+ A linked list of "instances" of the skeleton device. Each actual
+ PCMCIA card corresponds to one device instance, and is described
+ by one dev_link_t structure (defined in ds.h).
+
+ You may not want to use a linked list for this -- for example, the
+ memory card driver uses an array of dev_link_t pointers, where minor
+ device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+ A dev_link_t structure has fields for most things that are needed
+ to keep track of a socket, but there will usually be some device
+ specific information that also needs to be kept track of. The
+ 'priv' pointer in a dev_link_t structure can be used to point to
+ a device-specific private data structure, like this.
+
+ A driver needs to provide a dev_node_t structure for each device
+ on a card. In some cases, there is only one device per card (for
+ example, ethernet cards, modems). In other cases, there may be
+ many actual or logical devices (SCSI adapters, memory cards with
+ multiple partitions). The dev_node_t structures need to be kept
+ in a linked list starting at the 'dev' field of a dev_link_t
+ structure. We allocate them in the card's private data structure,
+ because they generally can't be allocated dynamically.
+*/
+
+typedef struct local_info_t {
+ dev_node_t node;
+} local_info_t;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+ avmcs_attach() creates an "instance" of the driver, allocating
+ local data structures for one device. The device is registered
+ with Card Services.
+
+ The dev_link structure is initialized, but we don't actually
+ configure the card at this point -- we wait until we receive a
+ card insertion event.
+
+======================================================================*/
+
+static dev_link_t *avmcs_attach(void)
+{
+ client_reg_t client_reg;
+ dev_link_t *link;
+ local_info_t *local;
+ int ret, i;
+
+ /* Initialize the dev_link_t structure */
+ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+ memset(link, 0, sizeof(struct dev_link_t));
+ link->release.function = &avmcs_release;
+ link->release.data = (u_long)link;
+
+ /* The io structure describes IO port mapping */
+ link->io.NumPorts1 = 16;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.NumPorts2 = 16;
+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+ link->io.IOAddrLines = 5;
+
+ /* Interrupt setup */
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] != -1) {
+ for (i = 0; i < 10 && irq_list[i] > 0; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ } else {
+ for (i = 0; i < 10 && default_irq_list[i] > 0; i++)
+ link->irq.IRQInfo2 |= 1 << default_irq_list[i];
+ }
+
+ /* General socket configuration */
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.ConfigIndex = 1;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Allocate space for private device-specific data */
+ local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ memset(local, 0, sizeof(local_info_t));
+ link->priv = local;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &avmcs_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ avmcs_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* avmcs_attach */
+
+/*======================================================================
+
+ This deletes a driver "instance". The device is de-registered
+ with Card Services. If it has been released, all local data
+ structures are freed. Otherwise, the structures will be freed
+ when the device is released.
+
+======================================================================*/
+
+static void avmcs_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ /*
+ If the device is currently configured and active, we won't
+ actually delete it yet. Instead, it is marked so that when
+ the release() function is called, that will trigger a proper
+ detach().
+ */
+ if (link->state & DEV_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+
+ /* Break the link with Card Services */
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free pieces */
+ *linkp = link->next;
+ if (link->priv) {
+ kfree_s(link->priv, sizeof(local_info_t));
+ }
+ kfree_s(link, sizeof(struct dev_link_t));
+
+} /* avmcs_detach */
+
+/*======================================================================
+
+ avmcs_config() is scheduled to run after a CARD_INSERTION event
+ is received, to configure the PCMCIA socket, and to make the
+ ethernet device available to the system.
+
+======================================================================*/
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
+ cisparse_t *parse)
+{
+ int i;
+ i = CardServices(fn, handle, tuple);
+ if (i != CS_SUCCESS) return i;
+ i = CardServices(GetTupleData, handle, tuple);
+ if (i != CS_SUCCESS) return i;
+ return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+static void avmcs_config(dev_link_t *link)
+{
+ client_handle_t handle;
+ tuple_t tuple;
+ cisparse_t parse;
+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ local_info_t *dev;
+ int i;
+ u_char buf[64];
+ char devname[128];
+ int cardtype;
+ int (*addcard)(unsigned int port, unsigned irq);
+
+ handle = link->handle;
+ dev = link->priv;
+
+ /*
+ This reads the card's CONFIG tuple to find its configuration
+ registers.
+ */
+ do {
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ i = CardServices(GetFirstTuple, handle, &tuple);
+ if (i != CS_SUCCESS) break;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ i = CardServices(GetTupleData, handle, &tuple);
+ if (i != CS_SUCCESS) break;
+ i = CardServices(ParseTuple, handle, &tuple, &parse);
+ if (i != CS_SUCCESS) break;
+ link->conf.ConfigBase = parse.config.base;
+ } while (0);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, ParseTuple, i);
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+ }
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ do {
+
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = 254;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = CISTPL_VERS_1;
+
+ devname[0] = 0;
+ if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
+ strncpy(devname,parse.version_1.str + parse.version_1.ofs[1],
+ sizeof(devname));
+ }
+ /*
+ * find IO port
+ */
+ tuple.TupleData = (cisdata_t *)buf;
+ tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ i = first_tuple(handle, &tuple, &parse);
+ while (i == CS_SUCCESS) {
+ if (cf->io.nwin > 0) {
+ link->conf.ConfigIndex = cf->index;
+ link->io.BasePort1 = cf->io.win[0].base;
+ link->io.NumPorts1 = cf->io.win[0].len;
+ printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
+ link->io.BasePort1,
+ link->io.BasePort1+link->io.NumPorts1);
+ i = CardServices(RequestIO, link->handle, &link->io);
+ if (i == CS_SUCCESS) goto found_port;
+ }
+ i = next_tuple(handle, &tuple, &parse);
+ }
+
+found_port:
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestIO, i);
+ break;
+ }
+
+ /*
+ * allocate an interrupt line
+ */
+ i = CardServices(RequestIRQ, link->handle, &link->irq);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestIRQ, i);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ break;
+ }
+
+ /*
+ * configure the PCMCIA socket
+ */
+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestConfiguration, i);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+ break;
+ }
+
+ } while (0);
+
+ /* At this point, the dev_node_t structure(s) should be
+ initialized and arranged in a linked list at link->dev. */
+
+ if (devname[0]) {
+ char *s = strrchr(devname, ' ');
+ if (!s)
+ s = devname;
+ else s++;
+ strcpy(dev->node.dev_name, s);
+ if (strcmp("M1", s) == 0) {
+ cardtype = AVM_CARDTYPE_M1;
+ } else if (strcmp("M2", s) == 0) {
+ cardtype = AVM_CARDTYPE_M2;
+ } else {
+ cardtype = AVM_CARDTYPE_B1;
+ }
+ } else {
+ strcpy(dev->node.dev_name, "b1");
+ cardtype = AVM_CARDTYPE_B1;
+ }
+
+ dev->node.major = 64;
+ dev->node.minor = 0;
+ link->dev = &dev->node;
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ /* If any step failed, release any partially configured state */
+ if (i != 0) {
+ avmcs_release((u_long)link);
+ return;
+ }
+
+
+ switch (cardtype) {
+ case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
+ case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
+ default:
+ case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
+ }
+ if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
+ printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
+ dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
+ avmcs_release((u_long)link);
+ return;
+ }
+ dev->node.minor = i;
+
+} /* avmcs_config */
+
+/*======================================================================
+
+ After a card is removed, avmcs_release() will unregister the net
+ device, and release the PCMCIA configuration. If the device is
+ still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void avmcs_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ /*
+ If the device is currently in use, we won't release until it
+ is actually closed.
+ */
+ if (link->open) {
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
+
+ /* Unlink the device chain */
+ link->dev = NULL;
+
+ /* Don't bother checking to see if these succeed or not */
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
+
+ if (link->state & DEV_STALE_LINK)
+ avmcs_detach(link);
+
+} /* avmcs_release */
+
+/*======================================================================
+
+ The card status event handler. Mostly, this schedules other
+ stuff to run after an event is received. A CARD_REMOVAL event
+ also sets some flags to discourage the net drivers from trying
+ to talk to the card any more.
+
+ When a CARD_REMOVAL event is received, we immediately set a flag
+ to block future accesses to this device. All the functions that
+ actually access the device should check this flag to make sure
+ the card is still present.
+
+======================================================================*/
+
+static int avmcs_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + (HZ/20);
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ avmcs_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG)
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ break;
+ }
+ return 0;
+} /* avmcs_event */
+
+/*====================================================================*/
+
+int init_module(void)
+{
+ servinfo_t serv;
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "avm_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL) {
+ if (dev_list->state & DEV_CONFIG)
+ avmcs_release((u_long)dev_list);
+ avmcs_detach(dev_list);
+ }
+}
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
index 1785e1740..d61b88375 100644
--- a/drivers/isdn/avmb1/b1dma.c
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -40,7 +40,7 @@ static char *revision = "$Revision: 1.3 $";
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-static int suppress_pollack = 0;
+int suppress_pollack = 0;
MODULE_PARM(suppress_pollack, "0-1i");
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c
index 6e39c43d2..ff90b42c8 100644
--- a/drivers/isdn/avmb1/b1pcmcia.c
+++ b/drivers/isdn/avmb1/b1pcmcia.c
@@ -1,11 +1,16 @@
/*
- * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $
+ * $Id: b1pcmcia.c,v 1.8 2000/03/06 18:00:23 calle Exp $
*
* Module for AVM B1/M1/M2 PCMCIA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pcmcia.c,v $
+ * Revision 1.8 2000/03/06 18:00:23 calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
* Revision 1.7 2000/02/02 18:36:03 calle
* - Modules are now locked while init_module is running
* - fixed problem with memory mapping if address is not aligned
@@ -70,7 +75,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.8 $";
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
index 76f34569d..e016bfde2 100644
--- a/drivers/isdn/avmb1/c4.c
+++ b/drivers/isdn/avmb1/c4.c
@@ -1,11 +1,17 @@
/*
- * $Id: c4.c,v 1.4 2000/02/02 18:36:03 calle Exp $
+ * $Id: c4.c,v 1.6 2000/03/17 12:21:08 calle Exp $
*
* Module for AVM C4 card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: c4.c,v $
+ * Revision 1.6 2000/03/17 12:21:08 calle
+ * send patchvalues now working.
+ *
+ * Revision 1.5 2000/03/16 15:21:03 calle
+ * Bugfix in c4_remove: loop 5 times instead of 4 :-(
+ *
* Revision 1.4 2000/02/02 18:36:03 calle
* - Modules are now locked while init_module is running
* - fixed problem with memory mapping if address is not aligned
@@ -40,7 +46,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.6 $";
#undef CONFIG_C4_DEBUG
#undef CONFIG_C4_POLLDEBUG
@@ -65,7 +71,7 @@ static char *revision = "$Revision: 1.4 $";
/* ------------------------------------------------------------- */
-static int suppress_pollack = 0;
+int suppress_pollack = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -770,45 +776,78 @@ static void c4_send_init(avmcard *card)
c4_dispatch_tx(card);
}
-static int c4_send_config(avmcard *card, capiloaddatapart * config)
+static int queue_sendconfigword(avmcard *card, __u32 val)
{
struct sk_buff *skb;
- __u8 val[sizeof(__u32)];
void *p;
- unsigned char *dp;
- int left, retval;
-
- skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC);
+
+ skb = alloc_skb(3+4, GFP_ATOMIC);
if (!skb) {
- printk(KERN_CRIT "%s: no memory, can't send config.\n",
+ printk(KERN_CRIT "%s: no memory, send config\n",
card->name);
- return -ENOMEM;
+ return -ENOMEM;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_CONFIG);
- _put_word(&p, 1);
+ _put_word(&p, val);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ return 0;
+}
+
+static int queue_sendconfig(avmcard *card, char cval[4])
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(3+4, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, send config\n",
+ card->name);
+ return -ENOMEM;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
_put_byte(&p, SEND_CONFIG);
- _put_word(&p, config->len); /* 12 */
+ _put_byte(&p, cval[0]);
+ _put_byte(&p, cval[1]);
+ _put_byte(&p, cval[2]);
+ _put_byte(&p, cval[3]);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ return 0;
+}
+
+static int c4_send_config(avmcard *card, capiloaddatapart * config)
+{
+ __u8 val[4];
+ unsigned char *dp;
+ int left, retval;
+
+ if ((retval = queue_sendconfigword(card, 1)) != 0)
+ return retval;
+ if ((retval = queue_sendconfigword(card, config->len)) != 0)
+ return retval;
dp = config->data;
left = config->len;
while (left >= sizeof(__u32)) {
if (config->user) {
retval = copy_from_user(val, dp, sizeof(val));
- if (retval) {
- dev_kfree_skb(skb);
+ if (retval)
return -EFAULT;
- }
} else {
memcpy(val, dp, sizeof(val));
}
- _put_byte(&p, SEND_CONFIG);
- _put_byte(&p, val[0]);
- _put_byte(&p, val[1]);
- _put_byte(&p, val[2]);
- _put_byte(&p, val[3]);
+ if ((retval = queue_sendconfig(card, val)) != 0)
+ return retval;
left -= sizeof(val);
dp += sizeof(val);
}
@@ -816,25 +855,15 @@ static int c4_send_config(avmcard *card, capiloaddatapart * config)
memset(val, 0, sizeof(val));
if (config->user) {
retval = copy_from_user(&val, dp, left);
- if (retval) {
- dev_kfree_skb(skb);
+ if (retval)
return -EFAULT;
- }
} else {
memcpy(&val, dp, left);
}
- _put_byte(&p, SEND_CONFIG);
- _put_byte(&p, val[0]);
- _put_byte(&p, val[1]);
- _put_byte(&p, val[2]);
- _put_byte(&p, val[3]);
+ if ((retval = queue_sendconfig(card, val)) != 0)
+ return retval;
}
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- c4_dispatch_tx(card);
-
return 0;
}
@@ -871,8 +900,15 @@ static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
restore_flags(flags);
- if (data->configuration.len > 0 && data->configuration.data)
- c4_send_config(card, &data->configuration);
+ if (data->configuration.len > 0 && data->configuration.data) {
+ retval = c4_send_config(card, &data->configuration);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to set config!!\n",
+ card->name);
+ c4_reset(card);
+ return retval;
+ }
+ }
c4_send_init(card);
@@ -904,7 +940,7 @@ static void c4_remove_ctr(struct capi_ctr *ctrl)
c4_reset(card);
- for (i=0; i <= 4; i++) {
+ for (i=0; i < 4; i++) {
cinfo = &card->ctrlinfo[i];
if (cinfo->capi_ctrl)
di->detach_ctr(cinfo->capi_ctrl);
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 6cd9cf3e4..3bbc329e1 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -1,11 +1,51 @@
/*
- * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $
+ * $Id: capi.c,v 1.30 2000/03/19 12:31:36 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.c,v $
+ * Revision 1.30 2000/03/19 12:31:36 calle
+ * PPP over CAPI raw driver disabled for now, ppp_generic has been changed.
+ *
+ * Revision 1.29 2000/03/13 17:48:13 calle
+ * removed unused variable.
+ *
+ * Revision 1.28 2000/03/08 17:06:33 calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.27 2000/03/06 18:00:23 calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
+ * Revision 1.26 2000/03/03 16:48:38 calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ * It is now possible to create a connection with a CAPI2.0 applikation
+ * and than to handle the data connection from /dev/capi/ (capifs) and also
+ * using async or sync PPP on this connection.
+ * The two major device number 190 and 191 are not confirmed yet,
+ * but I want to save the code in cvs, before I go on.
+ *
+ * Revision 1.25 2000/03/03 16:37:11 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.24 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.23 2000/02/26 01:00:53 keil
* changes from 2.3.47
*
@@ -114,6 +154,7 @@
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -126,52 +167,686 @@
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+#include <linux/tty.h>
+#ifdef CONFIG_PPP
+#include <linux/netdevice.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#undef CAPI_PPP_ON_RAW_DEVICE
+#endif /* CONFIG_PPP */
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/devfs_fs_kernel.h>
-
#include "capiutil.h"
#include "capicmd.h"
-#include "capidev.h"
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+#include "capifs.h"
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+#include <linux/slab.h>
+
+static char *revision = "$Revision: 1.30 $";
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
+#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */
+#undef _DEBUG_TTYFUNCS /* call to tty_driver */
+#undef _DEBUG_DATAFLOW /* data flow */
+
/* -------- driver information -------------------------------------- */
int capi_major = 68; /* allocated */
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+int capi_rawmajor = 190;
+int capi_ttymajor = 191;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
MODULE_PARM(capi_major, "i");
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+MODULE_PARM(capi_rawmajor, "i");
+MODULE_PARM(capi_ttymajor, "i");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- defines ------------------------------------------------- */
+
+#define CAPINC_MAX_RECVQUEUE 10
+#define CAPINC_MAX_SENDQUEUE 10
+#define CAPI_MAX_BLKSIZE 2048
+
+/* -------- data structures ----------------------------------------- */
+
+struct capidev;
+struct capincci;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+struct capiminor;
+
+struct capiminor {
+ struct capiminor *next;
+ struct capincci *nccip;
+ unsigned int minor;
+
+ __u16 applid;
+ __u32 ncci;
+ __u16 datahandle;
+ __u16 msgid;
+
+ struct file *file;
+ struct tty_struct *tty;
+ int ttyinstop;
+ int ttyoutstop;
+ struct sk_buff *ttyskb;
+ atomic_t ttyopencount;
+
+ struct sk_buff_head inqueue;
+ int inbytes;
+ struct sk_buff_head outqueue;
+ int outbytes;
+
+ /* for raw device */
+ struct sk_buff_head recvqueue;
+ wait_queue_head_t recvwait;
+ wait_queue_head_t sendwait;
+
+ /* transmit path */
+ struct datahandle_queue {
+ struct datahandle_queue *next;
+ __u16 datahandle;
+ } *ackqueue;
+ int nack;
+
+};
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+struct capincci {
+ struct capincci *next;
+ __u32 ncci;
+ struct capidev *cdev;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *minorp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+};
+
+struct capidev {
+ struct capidev *next;
+ struct file *file;
+ __u16 applid;
+ __u16 errcode;
+ unsigned int minor;
+ unsigned userflags;
+
+ struct sk_buff_head recvqueue;
+ wait_queue_head_t recvwait;
+
+ /* Statistic */
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
+
+ struct capincci *nccis;
+};
/* -------- global variables ---------------------------------------- */
-static struct capidev capidevs[CAPI_MAXMINOR + 1];
-struct capi_interface *capifuncs;
+static struct capi_interface *capifuncs = 0;
+static struct capidev *capidev_openlist = 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+static struct capiminor *minors = 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-/* -------- function called by lower level -------------------------- */
+static kmem_cache_t *capidev_cachep = 0;
+static kmem_cache_t *capincci_cachep = 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+static kmem_cache_t *capiminor_cachep = 0;
+static kmem_cache_t *capidh_cachep = 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- datahandles --------------------------------------------- */
+
+int capincci_add_ack(struct capiminor *mp, __u16 datahandle)
+{
+ struct datahandle_queue *n, **pp;
+
+ n = (struct datahandle_queue *)
+ kmem_cache_alloc(capidh_cachep, GFP_ATOMIC);
+ if (!n) {
+ printk(KERN_ERR "capi: alloc datahandle failed\n");
+ return -1;
+ }
+ n->next = 0;
+ n->datahandle = datahandle;
+ for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
+ *pp = n;
+ mp->nack++;
+ return 0;
+}
+
+int capiminor_del_ack(struct capiminor *mp, __u16 datahandle)
+{
+ struct datahandle_queue **pp, *p;
+
+ for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
+ if ((*pp)->datahandle == datahandle) {
+ p = *pp;
+ *pp = (*pp)->next;
+ kmem_cache_free(capidh_cachep, p);
+ mp->nack--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void capiminor_del_all_ack(struct capiminor *mp)
+{
+ struct datahandle_queue **pp, *p;
+
+ for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
+ p = *pp;
+ *pp = (*pp)->next;
+ kmem_cache_free(capidh_cachep, p);
+ mp->nack--;
+ }
+}
+
+
+/* -------- struct capiminor ---------------------------------------- */
+
+struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci)
+{
+ struct capiminor *mp, **pp;
+ unsigned int minor = 0;
+
+ mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC);
+ if (!mp) {
+ printk(KERN_ERR "capi: can't alloc capiminor\n");
+ return 0;
+ }
+ MOD_INC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ memset(mp, 0, sizeof(struct capiminor));
+ mp->applid = applid;
+ mp->ncci = ncci;
+ mp->msgid = 0;
+ atomic_set(&mp->ttyopencount,0);
+
+ skb_queue_head_init(&mp->inqueue);
+ skb_queue_head_init(&mp->outqueue);
+
+ skb_queue_head_init(&mp->recvqueue);
+ init_waitqueue_head(&mp->recvwait);
+ init_waitqueue_head(&mp->sendwait);
+
+ for (pp = &minors; *pp; pp = &(*pp)->next) {
+ if ((*pp)->minor < minor)
+ continue;
+ if ((*pp)->minor > minor)
+ break;
+ minor++;
+ }
+ mp->minor = minor;
+ mp->next = *pp;
+ *pp = mp;
+ return mp;
+}
+
+void capiminor_free(struct capiminor *mp)
+{
+ struct capiminor **pp;
+ struct sk_buff *skb;
+
+ pp = &minors;
+ while (*pp) {
+ if (*pp == mp) {
+ *pp = (*pp)->next;
+ if (mp->ttyskb) kfree_skb(mp->ttyskb);
+ mp->ttyskb = 0;
+ while ((skb = skb_dequeue(&mp->recvqueue)) != 0)
+ kfree_skb(skb);
+ while ((skb = skb_dequeue(&mp->inqueue)) != 0)
+ kfree_skb(skb);
+ while ((skb = skb_dequeue(&mp->outqueue)) != 0)
+ kfree_skb(skb);
+ capiminor_del_all_ack(mp);
+ kmem_cache_free(capiminor_cachep, mp);
+ MOD_DEC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ return;
+ } else {
+ pp = &(*pp)->next;
+ }
+ }
+}
+
+struct capiminor *capiminor_find(unsigned int minor)
+{
+ struct capiminor *p;
+ for (p = minors; p && p->minor != minor; p = p->next)
+ ;
+ return p;
+}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- struct capincci ----------------------------------------- */
+
+static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci)
+{
+ struct capincci *np, **pp;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp = 0;
+ kdev_t kdev;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+ np = (struct capincci *)kmem_cache_alloc(capincci_cachep, GFP_ATOMIC);
+ if (!np)
+ return 0;
+ memset(np, 0, sizeof(struct capincci));
+ np->ncci = ncci;
+ np->cdev = cdev;
+ for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
+ ;
+ *pp = np;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ mp = 0;
+ if (cdev->userflags & CAPIFLAG_HIGHJACKING)
+ mp = np->minorp = capiminor_alloc(cdev->applid, ncci);
+ if (mp) {
+ mp->nccip = np;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "set mp->nccip\n");
+#endif
+#ifdef CONFIG_ISDN_CAPIFS
+ kdev = MKDEV(capi_rawmajor, mp->minor);
+ capifs_new_ncci('r', mp->minor, kdev);
+ kdev = MKDEV(capi_ttymajor, mp->minor);
+ capifs_new_ncci(0, mp->minor, kdev);
+#endif
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ return np;
+}
+
+static void capincci_free(struct capidev *cdev, __u32 ncci)
+{
+ struct capincci *np, **pp;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+ pp=&cdev->nccis;
+ while (*pp) {
+ np = *pp;
+ if (ncci == 0xffffffff || np->ncci == ncci) {
+ *pp = (*pp)->next;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if ((mp = np->minorp) != 0) {
+#ifdef CONFIG_ISDN_CAPIFS
+ capifs_free_ncci('r', mp->minor);
+ capifs_free_ncci(0, mp->minor);
+#endif
+ if (mp->tty) {
+ mp->nccip = 0;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "reset mp->nccip\n");
+#endif
+ tty_hangup(mp->tty);
+ } else if (mp->file) {
+ mp->nccip = 0;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "reset mp->nccip\n");
+#endif
+ wake_up_interruptible(&mp->recvwait);
+ wake_up_interruptible(&mp->sendwait);
+ } else {
+ capiminor_free(mp);
+ }
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ kmem_cache_free(capincci_cachep, np);
+ if (*pp == 0) return;
+ } else {
+ pp = &(*pp)->next;
+ }
+ }
+}
+
+struct capincci *capincci_find(struct capidev *cdev, __u32 ncci)
+{
+ struct capincci *p;
+
+ for (p=cdev->nccis; p ; p = p->next) {
+ if (p->ncci == ncci)
+ break;
+ }
+ return p;
+}
+
+/* -------- struct capidev ------------------------------------------ */
-static void capi_signal(__u16 applid, __u32 minor)
+static struct capidev *capidev_alloc(struct file *file)
{
struct capidev *cdev;
+ struct capidev **pp;
+
+ cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL);
+ if (!cdev)
+ return 0;
+ memset(cdev, 0, sizeof(struct capidev));
+ cdev->file = file;
+ cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ skb_queue_head_init(&cdev->recvqueue);
+ init_waitqueue_head(&cdev->recvwait);
+ pp=&capidev_openlist;
+ while (*pp) pp = &(*pp)->next;
+ *pp = cdev;
+ return cdev;
+}
+
+static void capidev_free(struct capidev *cdev)
+{
+ struct capidev **pp;
+ struct sk_buff *skb;
+
+ if (cdev->applid)
+ (*capifuncs->capi_release) (cdev->applid);
+ cdev->applid = 0;
+
+ while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) {
+ kfree_skb(skb);
+ }
+
+ pp=&capidev_openlist;
+ while (*pp && *pp != cdev) pp = &(*pp)->next;
+ if (*pp)
+ *pp = cdev->next;
+
+ kmem_cache_free(capidev_cachep, cdev);
+}
+
+static struct capidev *capidev_find(__u16 applid)
+{
+ struct capidev *p;
+ for (p=capidev_openlist; p; p = p->next) {
+ if (p->applid == applid)
+ break;
+ }
+ return p;
+}
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- handle data queue --------------------------------------- */
+
+struct sk_buff *
+gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
+{
+ struct sk_buff *nskb;
+ nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);
+ if (nskb) {
+ __u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
+ unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
+ capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
+ capimsg_setu16(s, 2, mp->applid);
+ capimsg_setu8 (s, 4, CAPI_DATA_B3);
+ capimsg_setu8 (s, 5, CAPI_RESP);
+ capimsg_setu16(s, 6, mp->msgid++);
+ capimsg_setu32(s, 8, mp->ncci);
+ capimsg_setu16(s, 12, datahandle);
+ }
+ return nskb;
+}
+
+int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
+{
+ struct sk_buff *nskb;
+ unsigned int datalen;
+ __u16 errcode, datahandle;
+
+ datalen = skb->len - CAPIMSG_LEN(skb->data);
+ if (mp->tty) {
+ if (mp->tty->ldisc.receive_buf == 0) {
+ printk(KERN_ERR "capi: ldisc has no receive_buf function\n");
+ return -1;
+ }
+ if (mp->ttyinstop) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: recv tty throttled\n");
+#endif
+ return -1;
+ }
+ if (mp->tty->ldisc.receive_room &&
+ mp->tty->ldisc.receive_room(mp->tty) < datalen) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: no room in tty\n");
+#endif
+ return -1;
+ }
+ if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+ printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+ return -1;
+ }
+ datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+ errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+ errcode);
+ kfree_skb(nskb);
+ return -1;
+ }
+ (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
+ datahandle, skb->len);
+#endif
+ mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len);
+ return 0;
+
+ } else if (mp->file) {
+ if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: no room in raw queue\n");
+#endif
+ return -1;
+ }
+ if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+ printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+ return -1;
+ }
+ datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+ errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+ errcode);
+ kfree_skb(nskb);
+ return -1;
+ }
+ (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => raw\n",
+ datahandle, skb->len);
+#endif
+ skb_queue_tail(&mp->recvqueue, skb);
+ wake_up_interruptible(&mp->recvwait);
+ return 0;
+ }
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: currently no receiver\n");
+#endif
+ return -1;
+}
+
+void handle_minor_recv(struct capiminor *mp)
+{
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
+ unsigned int len = skb->len;
+ mp->inbytes -= len;
+ if (handle_recv_skb(mp, skb) < 0) {
+ skb_queue_head(&mp->inqueue, skb);
+ mp->inbytes += len;
+ return;
+ }
+ }
+}
+
+int handle_minor_send(struct capiminor *mp)
+{
+ struct sk_buff *skb;
+ __u16 len;
+ int count = 0;
+ __u16 errcode;
+ __u16 datahandle;
+
+ if (mp->tty && mp->ttyoutstop) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: send: tty stopped\n");
+#endif
+ return 0;
+ }
+
+ while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
+ datahandle = mp->datahandle;
+ len = (__u16)skb->len;
+ skb_push(skb, CAPI_DATA_B3_REQ_LEN);
+ memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+ capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+ capimsg_setu16(skb->data, 2, mp->applid);
+ capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
+ capimsg_setu8 (skb->data, 5, CAPI_REQ);
+ capimsg_setu16(skb->data, 6, mp->msgid++);
+ capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
+ capimsg_setu32(skb->data, 12, (__u32) skb->data); /* Data32 */
+ capimsg_setu16(skb->data, 16, len); /* Data length */
+ capimsg_setu16(skb->data, 18, datahandle);
+ capimsg_setu16(skb->data, 20, 0); /* Flags */
+
+ if (capincci_add_ack(mp, datahandle) < 0) {
+ skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
+ skb_queue_head(&mp->outqueue, skb);
+ return count;
+ }
+ errcode = (*capifuncs->capi_put_message) (mp->applid, skb);
+ if (errcode == CAPI_NOERROR) {
+ mp->datahandle++;
+ count++;
+ mp->outbytes -= len;
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n",
+ datahandle, len);
+#endif
+ continue;
+ }
+ capiminor_del_ack(mp, datahandle);
+
+ if (errcode == CAPI_SENDQUEUEFULL) {
+ skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
+ skb_queue_head(&mp->outqueue, skb);
+ break;
+ }
+
+ /* ups, drop packet */
+ printk(KERN_ERR "capi: put_message = %x\n", errcode);
+ mp->outbytes -= len;
+ kfree_skb(skb);
+ }
+ if (count)
+ wake_up_interruptible(&mp->sendwait);
+ return count;
+}
+
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+/* -------- function called by lower level -------------------------- */
+
+static void capi_signal(__u16 applid, void *param)
+{
+ struct capidev *cdev = (struct capidev *)param;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp;
+ __u16 datahandle;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ struct capincci *np;
struct sk_buff *skb = 0;
+ __u32 ncci;
- if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {
- printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);
+ (void) (*capifuncs->capi_get_message) (applid, &skb);
+ if (!skb) {
+ printk(KERN_ERR "BUG: capi_signal: no skb\n");
return;
}
- cdev = &capidevs[minor];
- (void) (*capifuncs->capi_get_message) (applid, &skb);
- if (skb) {
- skb_queue_tail(&cdev->recv_queue, skb);
- wake_up_interruptible(&cdev->recv_wait);
+
+ if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+ return;
+ }
+ ncci = CAPIMSG_CONTROL(skb->data);
+ for (np = cdev->nccis; np && np->ncci != ncci; np = np->next)
+ ;
+ if (!np) {
+ printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+ return;
+ }
+#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ mp = np->minorp;
+ if (!mp) {
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+ return;
+ }
+
+
+ if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
+
+ datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
+ datahandle, skb->len-CAPIMSG_LEN(skb->data));
+#endif
+ skb_queue_tail(&mp->inqueue, skb);
+ mp->inbytes += skb->len;
+ handle_minor_recv(mp);
+
+ } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
+
+ datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4);
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n",
+ datahandle,
+ CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
+#endif
+ kfree_skb(skb);
+ (void)capiminor_del_ack(mp, datahandle);
+ if (mp->tty) {
+ if (mp->tty->ldisc.write_wakeup)
+ mp->tty->ldisc.write_wakeup(mp->tty);
+ } else {
+ wake_up_interruptible(&mp->sendwait);
+ }
+ (void)handle_minor_send(mp);
+
} else {
- printk(KERN_ERR "BUG: capi_signal: no skb\n");
+ /* ups, let capi application handle it :-) */
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
}
-/* -------- file_operations ----------------------------------------- */
+/* -------- file_operations for capidev ----------------------------- */
static long long capi_llseek(struct file *file,
long long offset, int origin)
@@ -182,29 +857,25 @@ static long long capi_llseek(struct file *file,
static ssize_t capi_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ struct capidev *cdev = (struct capidev *)file->private_data;
struct sk_buff *skb;
int retval;
size_t copied;
- if (ppos != &file->f_pos)
+ if (ppos != &file->f_pos)
return -ESPIPE;
- if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ if (!cdev->applid)
return -ENODEV;
- cdev = &capidevs[minor];
-
- if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {
+ if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
for (;;) {
- interruptible_sleep_on(&cdev->recv_wait);
- if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+ interruptible_sleep_on(&cdev->recvwait);
+ if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
break;
if (signal_pending(current))
break;
@@ -213,20 +884,22 @@ static ssize_t capi_read(struct file *file, char *buf,
return -ERESTARTNOHAND;
}
if (skb->len > count) {
- skb_queue_head(&cdev->recv_queue, skb);
+ skb_queue_head(&cdev->recvqueue, skb);
return -EMSGSIZE;
}
retval = copy_to_user(buf, skb->data, skb->len);
if (retval) {
- skb_queue_head(&cdev->recv_queue, skb);
+ skb_queue_head(&cdev->recvqueue, skb);
return retval;
}
copied = skb->len;
- if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
- && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) {
cdev->nrecvdatapkt++;
- else cdev->nrecvctlpkt++;
+ } else {
+ cdev->nrecvctlpkt++;
+ }
+
kfree_skb(skb);
return copied;
@@ -235,41 +908,34 @@ static ssize_t capi_read(struct file *file, char *buf,
static ssize_t capi_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ struct capidev *cdev = (struct capidev *)file->private_data;
struct sk_buff *skb;
int retval;
- __u8 cmd;
- __u8 subcmd;
__u16 mlen;
- if (ppos != &file->f_pos)
+ if (ppos != &file->f_pos)
return -ESPIPE;
- if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ if (!cdev->applid)
return -ENODEV;
- cdev = &capidevs[minor];
-
skb = alloc_skb(count, GFP_USER);
if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
kfree_skb(skb);
return retval;
}
- cmd = CAPIMSG_COMMAND(skb->data);
- subcmd = CAPIMSG_SUBCOMMAND(skb->data);
mlen = CAPIMSG_LEN(skb->data);
- if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
- __u16 dlen = CAPIMSG_DATALEN(skb->data);
- if (mlen + dlen != count) {
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
+ if (mlen + CAPIMSG_DATALEN(skb->data) != count) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ } else {
+ if (mlen != count) {
kfree_skb(skb);
return -EINVAL;
}
- } else if (mlen != count) {
- kfree_skb(skb);
- return -EINVAL;
}
CAPIMSG_SETAPPID(skb->data, cdev->applid);
@@ -279,26 +945,26 @@ static ssize_t capi_write(struct file *file, const char *buf,
kfree_skb(skb);
return -EIO;
}
- if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ)
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
cdev->nsentdatapkt++;
- else cdev->nsentctlpkt++;
+ } else {
+ cdev->nsentctlpkt++;
+ }
return count;
}
static unsigned int
capi_poll(struct file *file, poll_table * wait)
{
+ struct capidev *cdev = (struct capidev *)file->private_data;
unsigned int mask = 0;
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct capidev *cdev;
- if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ if (!cdev->applid)
return POLLERR;
- cdev = &capidevs[minor];
- poll_wait(file, &(cdev->recv_wait), wait);
+ poll_wait(file, &(cdev->recvwait), wait);
mask = POLLOUT | POLLWRNORM;
- if (!skb_queue_empty(&cdev->recv_queue))
+ if (!skb_queue_empty(&cdev->recvqueue))
mask |= POLLIN | POLLRDNORM;
return mask;
}
@@ -306,36 +972,28 @@ capi_poll(struct file *file, poll_table * wait)
static int capi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ struct capidev *cdev = (struct capidev *)file->private_data;
capi_ioctl_struct data;
- int retval;
-
-
- if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)
- return -ENODEV;
-
- cdev = &capidevs[minor];
+ int retval = -EINVAL;
switch (cmd) {
case CAPI_REGISTER:
{
- if (!minor)
- return -EINVAL;
retval = copy_from_user((void *) &data.rparams,
(void *) arg, sizeof(struct capi_register_params));
if (retval)
return -EFAULT;
- if (cdev->is_registered)
+ if (cdev->applid)
return -EEXIST;
cdev->errcode = (*capifuncs->capi_register) (&data.rparams,
&cdev->applid);
- if (cdev->errcode)
+ if (cdev->errcode) {
+ cdev->applid = 0;
return -EIO;
- (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);
- cdev->is_registered = 1;
+ }
+ (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, cdev);
}
- return 0;
+ return (int)cdev->applid;
case CAPI_GET_VERSION:
{
@@ -441,8 +1099,6 @@ static int capi_ioctl(struct inode *inode, struct file *file,
case CAPI_MANUFACTURER_CMD:
{
struct capi_manufacturer_cmd mcmd;
- if (minor)
- return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
retval = copy_from_user((void *) &mcmd, (void *) arg,
@@ -452,102 +1108,721 @@ static int capi_ioctl(struct inode *inode, struct file *file,
return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);
}
return 0;
+
+ case CAPI_SET_FLAGS:
+ case CAPI_CLR_FLAGS:
+ {
+ unsigned userflags;
+ retval = copy_from_user((void *) &userflags,
+ (void *) arg,
+ sizeof(userflags));
+ if (retval)
+ return -EFAULT;
+ if (cmd == CAPI_SET_FLAGS)
+ cdev->userflags |= userflags;
+ else
+ cdev->userflags &= ~userflags;
+ }
+ return 0;
+
+ case CAPI_GET_FLAGS:
+ {
+ retval = copy_to_user((void *) arg,
+ (void *) &cdev->userflags,
+ sizeof(cdev->userflags));
+ if (retval)
+ return -EFAULT;
+ }
+ return 0;
+
+ case CAPI_NCCI_OPENCOUNT:
+ {
+ struct capincci *nccip;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ unsigned ncci;
+ int count = 0;
+ retval = copy_from_user((void *) &ncci,
+ (void *) arg,
+ sizeof(ncci));
+ if (retval)
+ return -EFAULT;
+ nccip = capincci_find(cdev, (__u32) ncci);
+ if (!nccip)
+ return 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if ((mp = nccip->minorp) != 0) {
+ count += atomic_read(&mp->ttyopencount);
+ if (mp->file)
+ count++;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ return count;
+ }
+ return 0;
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ case CAPI_NCCI_GETUNIT:
+ {
+ struct capincci *nccip;
+ struct capiminor *mp;
+ unsigned ncci;
+ retval = copy_from_user((void *) &ncci,
+ (void *) arg,
+ sizeof(ncci));
+ if (retval)
+ return -EFAULT;
+ nccip = capincci_find(cdev, (__u32) ncci);
+ if (!nccip || (mp = nccip->minorp) == 0)
+ return -ESRCH;
+ return mp->minor;
+ }
+ return 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
}
return -EINVAL;
}
static int capi_open(struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ if (file->private_data)
+ return -EEXIST;
+
+ if ((file->private_data = capidev_alloc(file)) == 0)
+ return -ENOMEM;
+
+ MOD_INC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ return 0;
+}
+
+static int capi_release(struct inode *inode, struct file *file)
+{
+ struct capidev *cdev = (struct capidev *)file->private_data;
+
+ capincci_free(cdev, 0xffffffff);
+ capidev_free(cdev);
+
+ MOD_DEC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ return 0;
+}
+
+static struct file_operations capi_fops =
+{
+ llseek: capi_llseek,
+ read: capi_read,
+ write: capi_write,
+ poll: capi_poll,
+ ioctl: capi_ioctl,
+ open: capi_open,
+ release: capi_release,
+};
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- file_operations for capincci ---------------------------- */
- if (minor >= CAPI_MAXMINOR)
+int capinc_raw_open(struct inode *inode, struct file *file)
+{
+ struct capiminor *mp;
+
+ if (file->private_data)
+ return -EEXIST;
+ if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+ return -ENXIO;
+ if (mp->nccip == 0)
return -ENXIO;
+ if (mp->file)
+ return -EBUSY;
- if (minor) {
- if (capidevs[minor].is_open)
- return -EEXIST;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
- capidevs[minor].is_open = 1;
- skb_queue_head_init(&capidevs[minor].recv_queue);
- MOD_INC_USE_COUNT;
- capidevs[minor].nopen++;
+ mp->datahandle = 0;
+ mp->file = file;
+ file->private_data = (void *)mp;
+ handle_minor_recv(mp);
+ return 0;
+}
- } else {
- capidevs[minor].is_open++;
- MOD_INC_USE_COUNT;
+long long capinc_raw_llseek(struct file *file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+ssize_t capinc_raw_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ struct sk_buff *skb;
+ int retval;
+ size_t copied = 0;
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if (!mp || !mp->nccip)
+ return -EINVAL;
+
+ if ((skb = skb_dequeue(&mp->recvqueue)) == 0) {
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ for (;;) {
+ interruptible_sleep_on(&mp->recvwait);
+ if (mp->nccip == 0)
+ return 0;
+ if ((skb = skb_dequeue(&mp->recvqueue)) != 0)
+ break;
+ if (signal_pending(current))
+ break;
+ }
+ if (skb == 0)
+ return -ERESTARTNOHAND;
}
+ do {
+ if (count < skb->len) {
+ retval = copy_to_user(buf, skb->data, count);
+ if (retval) {
+ skb_queue_head(&mp->recvqueue, skb);
+ return retval;
+ }
+ skb_pull(skb, count);
+ skb_queue_head(&mp->recvqueue, skb);
+ copied += count;
+ return copied;
+ } else {
+ retval = copy_to_user(buf, skb->data, skb->len);
+ if (retval) {
+ skb_queue_head(&mp->recvqueue, skb);
+ return copied;
+ }
+ copied += skb->len;
+ count -= skb->len;
+ buf += skb->len;
+ kfree_skb(skb);
+ }
+ } while ((skb = skb_dequeue(&mp->recvqueue)) != 0);
+
+ return copied;
+}
+
+ssize_t capinc_raw_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ struct sk_buff *skb;
+ int retval;
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if (!mp || !mp->nccip)
+ return -EINVAL;
+
+ skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER);
+
+ skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+ if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
+ kfree_skb(skb);
+ return retval;
+ }
+
+ while (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ interruptible_sleep_on(&mp->sendwait);
+ if (mp->nccip == 0) {
+ kfree_skb(skb);
+ return -EIO;
+ }
+ if (signal_pending(current))
+ return -ERESTARTNOHAND;
+ }
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ return count;
+}
+
+unsigned int
+capinc_raw_poll(struct file *file, poll_table * wait)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ unsigned int mask = 0;
+
+ if (!mp || !mp->nccip)
+ return POLLERR|POLLHUP;
+ poll_wait(file, &(mp->recvwait), wait);
+ if (!skb_queue_empty(&mp->recvqueue))
+ mask |= POLLIN | POLLRDNORM;
+ poll_wait(file, &(mp->sendwait), wait);
+ if (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE)
+ mask = POLLOUT | POLLWRNORM;
+ return mask;
+}
+
+int capinc_raw_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ if (!mp || !mp->nccip)
+ return -EINVAL;
+
+ switch (cmd) {
+ }
+ return -EINVAL;
+}
+
+int
+capinc_raw_release(struct inode *inode, struct file *file)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+
+ if (mp) {
+ mp->file = 0;
+ if (mp->nccip == 0)
+ capiminor_free(mp);
+ }
+
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
return 0;
}
-static int
-capi_release(struct inode *inode, struct file *file)
+struct file_operations capinc_raw_fops =
{
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ capinc_raw_llseek,
+ capinc_raw_read,
+ capinc_raw_write,
+ NULL, /* capi_readdir */
+ capinc_raw_poll,
+ capinc_raw_ioctl,
+ NULL, /* capi_mmap */
+ capinc_raw_open,
+ NULL, /* capi_flush */
+ capinc_raw_release,
+ NULL, /* capi_fsync */
+ NULL, /* capi_fasync */
+};
+
+/* -------- tty_operations for capincci ----------------------------- */
+
+int capinc_tty_open(struct tty_struct * tty, struct file * file)
+{
+ struct capiminor *mp;
+
+ if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+ return -ENXIO;
+ if (mp->nccip == 0)
+ return -ENXIO;
+ if (mp->file)
+ return -EBUSY;
+
+ skb_queue_head_init(&mp->recvqueue);
+ init_waitqueue_head(&mp->recvwait);
+ init_waitqueue_head(&mp->sendwait);
+ tty->driver_data = (void *)mp;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ if (atomic_read(&mp->ttyopencount) == 0)
+ mp->tty = tty;
+ atomic_inc(&mp->ttyopencount);
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
+#endif
+ handle_minor_recv(mp);
+ return 0;
+}
+
+void capinc_tty_close(struct tty_struct * tty, struct file * file)
+{
+ struct capiminor *mp;
+
+ mp = (struct capiminor *)tty->driver_data;
+ if (mp) {
+ if (atomic_dec_and_test(&mp->ttyopencount)) {
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_close lastclose\n");
+#endif
+ tty->driver_data = (void *)0;
+ mp->tty = 0;
+ }
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
+#endif
+ if (mp->nccip == 0)
+ capiminor_free(mp);
+ }
+
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_close\n");
+#endif
+}
+
+int capinc_tty_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
+ int retval;
- if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
- printk(KERN_ERR "capi20: release minor %d ???\n", minor);
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n",
+ from_user, count);
+#endif
+
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");
+#endif
return 0;
}
- cdev = &capidevs[minor];
- if (minor) {
-
- if (cdev->is_registered)
- (*capifuncs->capi_release) (cdev->applid);
+ skb = mp->ttyskb;
+ if (skb) {
+ mp->ttyskb = 0;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ }
- cdev->is_registered = 0;
- cdev->applid = 0;
+ skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
+ return -ENOMEM;
+ }
- while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) {
+ skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+ if (from_user) {
+ if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
kfree_skb(skb);
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval);
+#endif
+ return retval;
}
- cdev->is_open = 0;
} else {
- cdev->is_open--;
+ memcpy(skb_put(skb, count), buf, count);
}
- MOD_DEC_USE_COUNT;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ (void)handle_minor_recv(mp);
+ return count;
+}
+
+void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct sk_buff *skb;
+
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
+#endif
+
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
+#endif
+ return;
+ }
+
+ skb = mp->ttyskb;
+ if (skb) {
+ if (skb_tailroom(skb) > 0) {
+ *(skb_put(skb, 1)) = ch;
+ return;
+ }
+ mp->ttyskb = 0;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ }
+ skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC);
+ if (skb) {
+ skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+ *(skb_put(skb, 1)) = ch;
+ mp->ttyskb = skb;
+ } else {
+ printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
+ }
+}
+
+void capinc_tty_flush_chars(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct sk_buff *skb;
+
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_flush_chars\n");
+#endif
+
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");
+#endif
+ return;
+ }
+
+ skb = mp->ttyskb;
+ if (skb) {
+ mp->ttyskb = 0;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ }
+ (void)handle_minor_recv(mp);
+}
+
+int capinc_tty_write_room(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ int room;
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");
+#endif
+ return 0;
+ }
+ room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
+ room *= CAPI_MAX_BLKSIZE;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room);
+#endif
+ return room;
+}
+
+int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");
+#endif
+ return 0;
+ }
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
+ mp->outbytes, mp->nack,
+ skb_queue_len(&mp->outqueue),
+ skb_queue_len(&mp->inqueue));
+#endif
+ return mp->outbytes;
+}
+
+int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_set_termios\n");
+#endif
+}
+
+void capinc_tty_throttle(struct tty_struct * tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_throttle\n");
+#endif
+ if (mp)
+ mp->ttyinstop = 1;
+}
+
+void capinc_tty_unthrottle(struct tty_struct * tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_unthrottle\n");
+#endif
+ if (mp) {
+ mp->ttyinstop = 0;
+ handle_minor_recv(mp);
+ }
+}
+
+void capinc_tty_stop(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_stop\n");
+#endif
+ if (mp) {
+ mp->ttyoutstop = 1;
+ }
+}
+
+void capinc_tty_start(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_start\n");
+#endif
+ if (mp) {
+ mp->ttyoutstop = 0;
+ (void)handle_minor_send(mp);
+ }
+}
+
+void capinc_tty_hangup(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_hangup\n");
+#endif
+}
+
+void capinc_tty_break_ctl(struct tty_struct *tty, int state)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
+#endif
+}
+
+void capinc_tty_flush_buffer(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_flush_buffer\n");
+#endif
+}
+
+void capinc_tty_set_ldisc(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_set_ldisc\n");
+#endif
+}
+
+void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);
+#endif
+}
+
+int capinc_tty_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
return 0;
}
-static struct file_operations capi_fops =
+int capinc_write_proc(struct file *file, const char *buffer,
+ unsigned long count, void *data)
{
- llseek: capi_llseek,
- read: capi_read,
- write: capi_write,
- poll: capi_poll,
- ioctl: capi_ioctl,
- open: capi_open,
- release: capi_release,
-};
+ return 0;
+}
+
+#define CAPINC_NR_PORTS 256
+static struct tty_driver capinc_tty_driver;
+static int capinc_tty_refcount;
+static struct tty_struct *capinc_tty_table[CAPINC_NR_PORTS];
+static struct termios *capinc_tty_termios[CAPINC_NR_PORTS];
+static struct termios *capinc_tty_termios_locked[CAPINC_NR_PORTS];
+
+int capinc_tty_init(void)
+{
+ struct tty_driver *drv = &capinc_tty_driver;
+
+ /* Initialize the tty_driver structure */
+
+ memset(drv, 0, sizeof(struct tty_driver));
+ drv->magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
+ drv->driver_name = "capi_nc";
+#endif
+ drv->name = "capi/%d";
+ drv->major = capi_ttymajor;
+ drv->minor_start = 0;
+ drv->num = CAPINC_NR_PORTS;
+ drv->type = TTY_DRIVER_TYPE_SERIAL;
+ drv->subtype = SERIAL_TYPE_NORMAL;
+ drv->init_termios = tty_std_termios;
+ drv->init_termios.c_iflag = ICRNL;
+ drv->init_termios.c_oflag = OPOST | ONLCR;
+ drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ drv->init_termios.c_lflag = 0;
+ drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS;
+ drv->refcount = &capinc_tty_refcount;
+ drv->table = capinc_tty_table;
+ drv->termios = capinc_tty_termios;
+ drv->termios_locked = capinc_tty_termios_locked;
+
+ drv->open = capinc_tty_open;
+ drv->close = capinc_tty_close;
+ drv->write = capinc_tty_write;
+ drv->put_char = capinc_tty_put_char;
+ drv->flush_chars = capinc_tty_flush_chars;
+ drv->write_room = capinc_tty_write_room;
+ drv->chars_in_buffer = capinc_tty_chars_in_buffer;
+ drv->ioctl = capinc_tty_ioctl;
+ drv->set_termios = capinc_tty_set_termios;
+ drv->throttle = capinc_tty_throttle;
+ drv->unthrottle = capinc_tty_unthrottle;
+ drv->stop = capinc_tty_stop;
+ drv->start = capinc_tty_start;
+ drv->hangup = capinc_tty_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+ drv->break_ctl = capinc_tty_break_ctl;
+#endif
+ drv->flush_buffer = capinc_tty_flush_buffer;
+ drv->set_ldisc = capinc_tty_set_ldisc;
+#if (LINUX_VERSION_CODE >= 131343)
+ drv->send_xchar = capinc_tty_send_xchar;
+ drv->read_proc = capinc_tty_read_proc;
+#endif
+ if (tty_register_driver(drv)) {
+ printk(KERN_ERR "Couldn't register capi_nc driver\n");
+ return -1;
+ }
+ return 0;
+}
-/* -------- /proc functions ----------------------------------- */
+void capinc_tty_exit(void)
+{
+ struct tty_driver *drv = &capinc_tty_driver;
+ int retval;
+ if ((retval = tty_unregister_driver(drv)))
+ printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval);
+}
+
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- /proc functions ----------------------------------------- */
/*
* /proc/capi/capi20:
- * minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
+ * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
*/
static int proc_capidev_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- struct capidev *cp;
- int i;
+ struct capidev *cdev;
int len = 0;
off_t begin = 0;
- for (i=0; i < CAPI_MAXMINOR; i++) {
- cp = &capidevs[i+1];
- if (cp->nopen == 0) continue;
- len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n",
- i+1,
- cp->nopen,
- cp->nrecvctlpkt,
- cp->nrecvdatapkt,
- cp->nsentctlpkt,
- cp->nsentdatapkt);
+ for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+ len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n",
+ cdev->minor,
+ cdev->applid,
+ cdev->nrecvctlpkt,
+ cdev->nrecvdatapkt,
+ cdev->nsentctlpkt,
+ cdev->nsentdatapkt);
if (len+begin > off+count)
goto endloop;
if (len+begin < off) {
@@ -556,7 +1831,46 @@ static int proc_capidev_read_proc(char *page, char **start, off_t off,
}
}
endloop:
- if (i >= CAPI_MAXMINOR)
+ if (cdev == 0)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/capi20ncci:
+ * applid ncci
+ */
+static int proc_capincci_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capidev *cdev;
+ struct capincci *np;
+ int len = 0;
+ off_t begin = 0;
+
+ for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+ for (np=cdev->nccis; np; np = np->next) {
+ len += sprintf(page+len, "%d 0x%x%s\n",
+ cdev->applid,
+ np->ncci,
+#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
+ "");
+#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ np->minorp && np->minorp->file ? " open" : "");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ }
+endloop:
+ if (cdev == 0)
*eof = 1;
if (off >= len+begin)
return 0;
@@ -573,6 +1887,7 @@ static struct procfsentries {
} procfsentries[] = {
/* { "capi", S_IFDIR, 0 }, */
{ "capi/capi20", 0 , proc_capidev_read_proc },
+ { "capi/capi20ncci", 0 , proc_capincci_read_proc },
};
static void proc_init(void)
@@ -600,78 +1915,226 @@ static void proc_exit(void)
}
}
}
+
/* -------- init function and module interface ---------------------- */
+
+static void alloc_exit(void)
+{
+ if (capidev_cachep) {
+ (void)kmem_cache_destroy(capidev_cachep);
+ capidev_cachep = 0;
+ }
+ if (capincci_cachep) {
+ (void)kmem_cache_destroy(capincci_cachep);
+ capincci_cachep = 0;
+ }
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if (capidh_cachep) {
+ (void)kmem_cache_destroy(capidh_cachep);
+ capidh_cachep = 0;
+ }
+ if (capiminor_cachep) {
+ (void)kmem_cache_destroy(capiminor_cachep);
+ capiminor_cachep = 0;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+}
+
+static int alloc_init(void)
+{
+ capidev_cachep = kmem_cache_create("capi20_dev",
+ sizeof(struct capidev),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capidev_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+
+ capincci_cachep = kmem_cache_create("capi20_ncci",
+ sizeof(struct capincci),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capincci_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ capidh_cachep = kmem_cache_create("capi20_dh",
+ sizeof(struct datahandle_queue),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capidh_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+ capiminor_cachep = kmem_cache_create("capi20_minor",
+ sizeof(struct capiminor),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capiminor_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ return 0;
+}
+
+static void lower_callback(unsigned int cmd, __u32 contr, void *data)
+{
+ struct capi_ncciinfo *np;
+ struct capidev *cdev;
+
+ switch (cmd) {
+ case KCI_CONTRUP:
+ printk(KERN_INFO "capi: controller %hu up\n", contr);
+ break;
+ case KCI_CONTRDOWN:
+ printk(KERN_INFO "capi: controller %hu down\n", contr);
+ break;
+ case KCI_NCCIUP:
+ np = (struct capi_ncciinfo *)data;
+ if ((cdev = capidev_find(np->applid)) == 0)
+ return;
+ (void)capincci_alloc(cdev, np->ncci);
+ break;
+ case KCI_NCCIDOWN:
+ np = (struct capi_ncciinfo *)data;
+ if ((cdev = capidev_find(np->applid)) == 0)
+ return;
+ (void)capincci_free(cdev, np->ncci);
+ break;
+ }
+}
+
#ifdef MODULE
#define capi_init init_module
#endif
static struct capi_interface_user cuser = {
"capi20",
- 0,
+ lower_callback,
};
+static char rev[10];
+
int capi_init(void)
{
- int j;
-
- memset(capidevs, 0, sizeof(capidevs));
- for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) {
- init_waitqueue_head(&capidevs[j].recv_wait);
- }
+ char *p;
+
+ MOD_INC_USE_COUNT;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 2);
+ p = strchr(rev, '$');
+ *(p-1) = 0;
+ } else
+ strcpy(rev, "???");
if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) {
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if (devfs_register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) {
+ devfs_unregister_chrdev(capi_major, "capi20");
+ printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+ devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS,
+ DEVFS_FL_DEFAULT,
+ capi_rawmajor, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capinc_raw_fops, NULL);
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT,
capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
&capi_fops, NULL);
- devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT,
- capi_major, 1,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
- &capi_fops, NULL);
- devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT,
- capi_major, 11,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
- &capi_fops, NULL);
printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
+
+ MOD_DEC_USE_COUNT;
devfs_unregister_chrdev(capi_major, "capi20");
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
capi_major, 0,
DEVFS_SPECIAL_CHR, 0));
- for (j = 0; j < 10; j++) {
- char devname[32];
+ return -EIO;
+ }
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if (capinc_tty_init() < 0) {
+ (void) detach_capi_interface(&cuser);
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- sprintf(devname, "isdn/capi20.0%i", j);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0));
- sprintf (devname, "isdn/capi20.1%i", j);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0));
+ if (alloc_init() < 0) {
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ unsigned int j;
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ for (j = 0; j < CAPINC_NR_PORTS; j++) {
+ char devname[32];
+ sprintf(devname, "capi/r%u", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
}
- return -EIO;
+ capinc_tty_exit();
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ (void) detach_capi_interface(&cuser);
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
+ capi_major, 0,
+ DEVFS_SPECIAL_CHR, 0));
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
}
+
(void)proc_init();
+
+ printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n",
+ rev, capi_major);
+
+ MOD_DEC_USE_COUNT;
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
- int i;
- char devname[32];
-
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ unsigned int j;
+#endif
+ alloc_exit();
(void)proc_exit();
+
devfs_unregister_chrdev(capi_major, "capi20");
devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0));
- for (i = 0; i < 10; i++) {
- sprintf (devname, "isdn/capi20.0%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 1, DEVFS_SPECIAL_CHR, 0));
- sprintf (devname, "isdn/capi20.1%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 11, DEVFS_SPECIAL_CHR, 0));
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ capinc_tty_exit();
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ for (j = 0; j < CAPINC_NR_PORTS; j++) {
+ char devname[32];
+ sprintf(devname, "capi/r%u", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
}
+#endif
(void) detach_capi_interface(&cuser);
+ printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev);
}
#endif
diff --git a/drivers/isdn/avmb1/capicmd.h b/drivers/isdn/avmb1/capicmd.h
index 104ef824f..970365f7a 100644
--- a/drivers/isdn/avmb1/capicmd.h
+++ b/drivers/isdn/avmb1/capicmd.h
@@ -1,11 +1,22 @@
/*
- * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ * $Id: capicmd.h,v 1.2 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capicmd.h,v $
+ * Revision 1.2 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.1 1997/03/04 21:50:30 calle
* Frirst version in isdn4linux
*
@@ -20,6 +31,10 @@
#ifndef __CAPICMD_H__
#define __CAPICMD_H__
+#define CAPI_MSG_BASELEN 8
+#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2)
+#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2)
+
/*----- CAPI commands -----*/
#define CAPI_ALERT 0x01
#define CAPI_CONNECT 0x02
diff --git a/drivers/isdn/avmb1/capidev.h b/drivers/isdn/avmb1/capidev.h
index 96e37c1f4..6f1d9a42a 100644
--- a/drivers/isdn/avmb1/capidev.h
+++ b/drivers/isdn/avmb1/capidev.h
@@ -1,11 +1,22 @@
/*
- * $Id: capidev.h,v 1.4 1999/07/01 15:26:32 calle Exp $
+ * $Id: capidev.h,v 1.5 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidev.h,v $
+ * Revision 1.5 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.4 1999/07/01 15:26:32 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
@@ -40,18 +51,18 @@
*/
struct capidev {
- int is_open;
- int is_registered;
- __u16 applid;
+ struct capidev *next;
+ struct file *file;
+ __u16 applid;
+ __u16 errcode;
+ unsigned int minor;
+
struct sk_buff_head recv_queue;
wait_queue_head_t recv_wait;
- __u16 errcode;
+
/* Statistic */
- unsigned long nopen;
- unsigned long nrecvctlpkt;
- unsigned long nrecvdatapkt;
- unsigned long nsentctlpkt;
- unsigned long nsentdatapkt;
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
};
-
-#define CAPI_MAXMINOR CAPI_MAXAPPL
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index 79bb370d1..d35c21d77 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -1,11 +1,22 @@
/*
- * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $
+ * $Id: capidrv.c,v 1.30 2000/03/03 15:50:42 calle Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidrv.c,v $
+ * Revision 1.30 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.29 1999/12/06 17:13:06 calle
* Added controller watchdog.
*
@@ -171,7 +182,7 @@
#include "capicmd.h"
#include "capidrv.h"
-static char *revision = "$Revision: 1.29 $";
+static char *revision = "$Revision: 1.30 $";
int debugmode = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -440,25 +451,33 @@ static inline __u8 cip2si2(__u16 cipval)
static inline capidrv_contr *findcontrbydriverid(int driverid)
{
capidrv_contr *p = global.contr_list;
+ long flags;
+ save_flags(flags);
+ cli();
while (p) {
if (p->myid == driverid)
- return p;
+ break;
p = p->next;
}
- return (capidrv_contr *) 0;
+ restore_flags(flags);
+ return p;
}
static capidrv_contr *findcontrbynumber(__u32 contr)
{
capidrv_contr *p = global.contr_list;
+ long flags;
+ save_flags(flags);
+ cli();
while (p) {
if (p->contrnr == contr)
- return p;
+ break;
p = p->next;
}
- return (capidrv_contr *) 0;
+ restore_flags(flags);
+ return p;
}
@@ -1501,7 +1520,7 @@ static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
static _cmsg s_cmsg;
-static void capidrv_signal(__u16 applid, __u32 dummy)
+static void capidrv_signal(__u16 applid, void *dummy)
{
struct sk_buff *skb = 0;
@@ -2218,14 +2237,18 @@ static void listentimerfunc(unsigned long x)
static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
{
capidrv_contr *card;
+ long flags;
isdn_ctrl cmd;
char id[20];
int i;
+ MOD_INC_USE_COUNT;
+
sprintf(id, "capidrv-%d", contr);
if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
printk(KERN_WARNING
"capidrv: (%s) Could not allocate contr-struct.\n", id);
+ MOD_DEC_USE_COUNT;
return -1;
}
memset(card, 0, sizeof(capidrv_contr));
@@ -2238,6 +2261,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
printk(KERN_WARNING
"capidrv: (%s) Could not allocate bchan-structs.\n", id);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -1;
}
card->interface.channels = profp->nbchannel;
@@ -2258,29 +2282,35 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
ISDN_FEATURE_P_UNKNOWN;
card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
- card->next = global.contr_list;
- global.contr_list = card;
- global.ncontr++;
+
+
card->q931_read = card->q931_buf;
card->q931_write = card->q931_buf;
card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
if (!register_isdn(&card->interface)) {
- global.contr_list = global.contr_list->next;
printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
kfree(card->bchans);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -1;
}
card->myid = card->interface.channels;
+ save_flags(flags);
+ cli();
+ card->next = global.contr_list;
+ global.contr_list = card;
+ global.ncontr++;
+ restore_flags(flags);
+
memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
for (i = 0; i < card->nbchan; i++) {
card->bchans[i].contr = card;
}
- cmd.driver = card->myid;
cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
card->interface.statcallb(&cmd);
card->cipmask = 0x1FFF03FF; /* any */
@@ -2304,30 +2334,41 @@ static int capidrv_delcontr(__u16 contr)
{
capidrv_contr **pp, *card;
isdn_ctrl cmd;
+ long flags;
int i;
+ save_flags(flags);
+ cli();
for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
if ((*pp)->contrnr == contr)
break;
}
if (!*pp) {
+ restore_flags(flags);
printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
return -1;
}
card = *pp;
+ *pp = (*pp)->next;
+ global.ncontr--;
+ restore_flags(flags);
if (debugmode)
printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
card->contrnr, card->myid);
- cmd.command = ISDN_STAT_UNLOAD;
+ cmd.command = ISDN_STAT_STOP;
cmd.driver = card->myid;
card->interface.statcallb(&cmd);
- *pp = (*pp)->next;
- global.ncontr--;
-
for (i = 0; i < card->nbchan; i++) {
+
+ cmd.command = ISDN_STAT_DISCH;
+ cmd.driver = card->myid;
+ cmd.arg = i;
+ cmd.parm.num[0] = 0;
+ card->interface.statcallb(&cmd);
+
if (card->bchans[i].nccip)
free_ncci(card, card->bchans[i].nccip);
if (card->bchans[i].plcip)
@@ -2338,10 +2379,16 @@ static int capidrv_delcontr(__u16 contr)
kfree(card->bchans);
del_timer(&card->listentimer);
- printk(KERN_INFO "%s: now down.\n", card->name);
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
kfree(card);
+ printk(KERN_INFO "%s: now down.\n", card->name);
+
+ MOD_DEC_USE_COUNT;
+
return 0;
}
@@ -2438,10 +2485,14 @@ int capidrv_init(void)
__u32 ncontr, contr;
__u16 errcode;
+ MOD_INC_USE_COUNT;
+
capifuncs = attach_capi_interface(&cuser);
- if (!capifuncs)
+ if (!capifuncs) {
+ MOD_DEC_USE_COUNT;
return -EIO;
+ }
if ((p = strchr(revision, ':'))) {
strcpy(rev, p + 1);
@@ -2456,6 +2507,7 @@ int capidrv_init(void)
errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
if (errcode) {
detach_capi_interface(&cuser);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
@@ -2463,6 +2515,7 @@ int capidrv_init(void)
if (errcode != CAPI_NOERROR) {
(void) (*capifuncs->capi_release) (global.appid);
detach_capi_interface(&cuser);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
@@ -2477,6 +2530,9 @@ int capidrv_init(void)
}
proc_init();
+ printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev);
+ MOD_DEC_USE_COUNT;
+
return 0;
}
@@ -2484,6 +2540,7 @@ int capidrv_init(void)
void cleanup_module(void)
{
capidrv_contr *card, *next;
+ long flags;
char rev[10];
char *p;
@@ -2498,8 +2555,15 @@ void cleanup_module(void)
for (card = global.contr_list; card; card = next) {
next = card->next;
disable_dchannel_trace(card);
+ }
+
+ save_flags(flags);
+ cli();
+ for (card = global.contr_list; card; card = next) {
+ next = card->next;
capidrv_delcontr(card->contrnr);
}
+ restore_flags(flags);
(void) (*capifuncs->capi_release) (global.appid);
detach_capi_interface(&cuser);
diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
new file mode 100644
index 000000000..b869e6b5c
--- /dev/null
+++ b/drivers/isdn/avmb1/capifs.c
@@ -0,0 +1,595 @@
+/*
+ * $Id: capifs.c,v 1.5 2000/03/13 17:49:52 calle Exp $
+ *
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
+ *
+ * Heavily based on devpts filesystem from H. Peter Anvin
+ *
+ * $Log: capifs.c,v $
+ * Revision 1.5 2000/03/13 17:49:52 calle
+ * make it running with 2.3.51.
+ *
+ * Revision 1.4 2000/03/08 17:06:33 calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.3 2000/03/06 18:00:23 calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
+ * Revision 1.2 2000/03/06 09:17:07 calle
+ * - capifs: fileoperations now in inode (change for 2.3.49)
+ * - Config.in: Middleware extention not a tristate, uups.
+ *
+ * Revision 1.1 2000/03/03 16:48:38 calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ * It is now possible to create a connection with a CAPI2.0 applikation
+ * and than to handle the data connection from /dev/capi/ (capifs) and also
+ * using async or sync PPP on this connection.
+ * The two major device number 190 and 191 are not confirmed yet,
+ * but I want to save the code in cvs, before I go on.
+ *
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/param.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/locks.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/ctype.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
+
+static char *revision = "$Revision: 1.5 $";
+
+struct capifs_ncci {
+ struct inode *inode;
+ char used;
+ char type;
+ unsigned int num;
+ kdev_t kdev;
+};
+
+struct capifs_sb_info {
+ u32 magic;
+ struct super_block *next;
+ struct super_block **back;
+ int setuid;
+ int setgid;
+ uid_t uid;
+ gid_t gid;
+ umode_t mode;
+
+ unsigned int max_ncci;
+ struct capifs_ncci *nccis;
+};
+
+#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
+#define CAPIFS_SBI_MAGIC (('C'<<24)|('A'<<16)|('P'<<8)|'I')
+
+static inline struct capifs_sb_info *SBI(struct super_block *sb)
+{
+ return (struct capifs_sb_info *)(sb->u.generic_sbp);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int capifs_root_readdir(struct file *,void *,filldir_t);
+static struct dentry *capifs_root_lookup(struct inode *,struct dentry *);
+static int capifs_revalidate(struct dentry *, int);
+
+static struct file_operations capifs_root_operations = {
+ read: generic_read_dir,
+ readdir: capifs_root_readdir,
+};
+
+struct inode_operations capifs_root_inode_operations = {
+ lookup: capifs_root_lookup,
+};
+
+struct inode_operations capifs_inode_operations;
+
+static struct dentry_operations capifs_dentry_operations = {
+ d_revalidate: capifs_revalidate,
+};
+
+/*
+ * /dev/capi/%d
+ * /dev/capi/r%d
+ */
+
+static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct capifs_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb);
+ off_t nr;
+ char numbuf[32];
+
+ nr = filp->f_pos;
+
+ switch(nr)
+ {
+ case 0:
+ if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ default:
+ while (nr < sbi->max_ncci) {
+ int n = nr - 2;
+ struct capifs_ncci *np = &sbi->nccis[n];
+ if (np->inode && np->used) {
+ char *p = numbuf;
+ if (np->type) *p++ = np->type;
+ sprintf(p, "%u", np->num);
+ if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
+ return 0;
+ }
+ filp->f_pos = ++nr;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Revalidate is called on every cache lookup. We use it to check that
+ * the ncci really does still exist. Never revalidate negative dentries;
+ * for simplicity (fix later?)
+ */
+static int capifs_revalidate(struct dentry * dentry, int flags)
+{
+ struct capifs_sb_info *sbi;
+
+ if ( !dentry->d_inode )
+ return 0;
+
+ sbi = SBI(dentry->d_inode->i_sb);
+
+ return ( sbi->nccis[dentry->d_inode->i_ino - 2].inode == dentry->d_inode );
+}
+
+static struct dentry *capifs_root_lookup(struct inode * dir, struct dentry * dentry)
+{
+ struct capifs_sb_info *sbi = SBI(dir->i_sb);
+ struct capifs_ncci *np;
+ unsigned int i;
+ char numbuf[32];
+ char *p, *tmp;
+ unsigned int num;
+ char type = 0;
+
+ dentry->d_inode = NULL; /* Assume failure */
+ dentry->d_op = &capifs_dentry_operations;
+
+ if (dentry->d_name.len >= sizeof(numbuf) )
+ return NULL;
+ strncpy(numbuf, dentry->d_name.name, dentry->d_name.len);
+ numbuf[dentry->d_name.len] = 0;
+ p = numbuf;
+ if (!isdigit(*p)) type = *p++;
+ tmp = p;
+ num = (unsigned int)simple_strtoul(p, &tmp, 10);
+ if (tmp == p || *tmp)
+ return NULL;
+
+ for (i = 0, np = sbi->nccis ; i < sbi->max_ncci; i++, np++) {
+ if (np->used && np->num == num && np->type == type)
+ break;
+ }
+
+ if ( i >= sbi->max_ncci )
+ return NULL;
+
+ dentry->d_inode = np->inode;
+ if ( dentry->d_inode )
+ dentry->d_inode->i_count++;
+
+ d_add(dentry, dentry->d_inode);
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct super_block *mounts = NULL;
+
+static void capifs_put_super(struct super_block *sb)
+{
+ struct capifs_sb_info *sbi = SBI(sb);
+ struct inode *inode;
+ int i;
+
+ for ( i = 0 ; i < sbi->max_ncci ; i++ ) {
+ if ( (inode = sbi->nccis[i].inode) ) {
+ if ( inode->i_count != 1 )
+ printk("capifs_put_super: badness: entry %d count %d\n",
+ i, inode->i_count);
+ inode->i_nlink--;
+ iput(inode);
+ }
+ }
+
+ *sbi->back = sbi->next;
+ if ( sbi->next )
+ SBI(sbi->next)->back = sbi->back;
+
+ kfree(sbi->nccis);
+ kfree(sbi);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static void capifs_write_inode(struct inode *inode) { };
+#else
+static int capifs_statfs(struct super_block *sb, struct statfs *buf);
+#endif
+static void capifs_read_inode(struct inode *inode);
+
+static struct super_operations capifs_sops = {
+ read_inode: capifs_read_inode,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ write_inode: capifs_write_inode,
+#endif
+ put_super: capifs_put_super,
+ statfs: capifs_statfs,
+};
+
+static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
+{
+ int setuid = 0;
+ int setgid = 0;
+ uid_t uid = 0;
+ gid_t gid = 0;
+ umode_t mode = 0600;
+ unsigned int maxncci = 512;
+ char *this_char, *value;
+
+ this_char = NULL;
+ if ( options )
+ this_char = strtok(options,",");
+ for ( ; this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"uid")) {
+ if (!value || !*value)
+ return 1;
+ uid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ setuid = 1;
+ }
+ else if (!strcmp(this_char,"gid")) {
+ if (!value || !*value)
+ return 1;
+ gid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ setgid = 1;
+ }
+ else if (!strcmp(this_char,"mode")) {
+ if (!value || !*value)
+ return 1;
+ mode = simple_strtoul(value,&value,8);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"maxncci")) {
+ if (!value || !*value)
+ return 1;
+ maxncci = simple_strtoul(value,&value,8);
+ if (*value)
+ return 1;
+ }
+ else
+ return 1;
+ }
+ sbi->setuid = setuid;
+ sbi->setgid = setgid;
+ sbi->uid = uid;
+ sbi->gid = gid;
+ sbi->mode = mode & ~S_IFMT;
+ sbi->max_ncci = maxncci;
+
+ return 0;
+}
+
+struct super_block *capifs_read_super(struct super_block *s, void *data,
+ int silent)
+{
+ struct inode * root_inode;
+ struct dentry * root;
+ struct capifs_sb_info *sbi;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ MOD_INC_USE_COUNT;
+ lock_super(s);
+#endif
+ /* Super block already completed? */
+ if (s->s_root)
+ goto out;
+
+ sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL);
+ if ( !sbi )
+ goto fail;
+
+ memset(sbi, 0, sizeof(struct capifs_sb_info));
+ sbi->magic = CAPIFS_SBI_MAGIC;
+
+ if ( capifs_parse_options(data,sbi) ) {
+ kfree(sbi);
+ printk("capifs: called with bogus options\n");
+ goto fail;
+ }
+
+ sbi->nccis = kmalloc(sizeof(struct capifs_ncci) * sbi->max_ncci, GFP_KERNEL);
+ if ( !sbi->nccis ) {
+ kfree(sbi);
+ goto fail;
+ }
+ memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci);
+
+ s->u.generic_sbp = (void *) sbi;
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = CAPIFS_SUPER_MAGIC;
+ s->s_op = &capifs_sops;
+ s->s_root = NULL;
+
+ /*
+ * Get the root inode and dentry, but defer checking for errors.
+ */
+ root_inode = iget(s, 1); /* inode 1 == root directory */
+ root = d_alloc_root(root_inode);
+
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root) {
+ if (root) dput(root);
+ else iput(root_inode);
+ goto out;
+ }
+
+ if (!root) {
+ printk("capifs: get root dentry failed\n");
+ /*
+ * iput() can block, so we clear the super block first.
+ */
+ iput(root_inode);
+ kfree(sbi->nccis);
+ kfree(sbi);
+ goto fail;
+ }
+
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out;
+
+ /*
+ * Success! Install the root dentry now to indicate completion.
+ */
+ s->s_root = root;
+
+ sbi->next = mounts;
+ if ( sbi->next )
+ SBI(sbi->next)->back = &(sbi->next);
+ sbi->back = &mounts;
+ mounts = s;
+
+out: /* Success ... somebody else completed the super block for us. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ unlock_super(s);
+#endif
+ return s;
+fail:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+#endif
+ return NULL;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = CAPIFS_SUPER_MAGIC;
+ tmp.f_bsize = 1024;
+ tmp.f_blocks = 0;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+#else
+static int capifs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ buf->f_type = CAPIFS_SUPER_MAGIC;
+ buf->f_bsize = 1024;
+ buf->f_blocks = 0;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_files = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
+}
+#endif
+
+static void capifs_read_inode(struct inode *inode)
+{
+ ino_t ino = inode->i_ino;
+ struct capifs_sb_info *sbi = SBI(inode->i_sb);
+
+ inode->i_op = NULL;
+ inode->i_mode = 0;
+ inode->i_nlink = 0;
+ inode->i_size = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+ inode->i_blksize = 1024;
+ inode->i_uid = inode->i_gid = 0;
+
+ if ( ino == 1 ) {
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+ inode->i_op = &capifs_root_inode_operations;
+ inode->i_fop = &capifs_root_operations;
+ inode->i_nlink = 2;
+ return;
+ }
+
+ /* need dummy inode operations .... */
+ inode->i_op = &capifs_inode_operations;
+
+ ino -= 2;
+ if ( ino >= sbi->max_ncci )
+ return; /* Bogus */
+
+ init_special_inode(inode, S_IFCHR, 0);
+
+ return;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static struct file_system_type capifs_fs_type = {
+ "capifs",
+ 0,
+ capifs_read_super,
+ NULL
+};
+#else
+static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0);
+#endif
+
+void capifs_new_ncci(char type, unsigned int num, kdev_t device)
+{
+ struct super_block *sb;
+ struct capifs_sb_info *sbi;
+ struct capifs_ncci *np;
+ ino_t ino;
+
+ for ( sb = mounts ; sb ; sb = sbi->next ) {
+ sbi = SBI(sb);
+
+ for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
+ if (np->used == 0) {
+ np->used = 1;
+ np->type = type;
+ np->num = num;
+ np->kdev = device;
+ break;
+ }
+ }
+
+ if ((np->inode = iget(sb, ino+2)) != 0) {
+ struct inode *inode = np->inode;
+ inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
+ inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
+ inode->i_mode = sbi->mode | S_IFCHR;
+ inode->i_rdev = np->kdev;
+ inode->i_nlink++;
+ }
+ }
+}
+
+void capifs_free_ncci(char type, unsigned int num)
+{
+ struct super_block *sb;
+ struct capifs_sb_info *sbi;
+ struct inode *inode;
+ struct capifs_ncci *np;
+ ino_t ino;
+
+ for ( sb = mounts ; sb ; sb = sbi->next ) {
+ sbi = SBI(sb);
+
+ for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
+ if (!np->used || np->type != type || np->num != num)
+ continue;
+ if (np->inode) {
+ inode = np->inode;
+ np->used = 0;
+ inode->i_nlink--;
+ iput(inode);
+ break;
+ }
+ }
+ }
+}
+
+int __init capifs_init(void)
+{
+ char rev[10];
+ char *p;
+ int err;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, "1.0");
+
+ err = register_filesystem(&capifs_fs_type);
+ if (err)
+ return err;
+#ifdef MODULE
+ printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev);
+#else
+ printk(KERN_NOTICE "capifs: Rev%s: started\n", rev);
+#endif
+ return 0;
+}
+
+void capifs_exit(void)
+{
+ unregister_filesystem(&capifs_fs_type);
+}
+
+EXPORT_SYMBOL(capifs_new_ncci);
+EXPORT_SYMBOL(capifs_free_ncci);
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ return capifs_init();
+}
+
+void cleanup_module(void)
+{
+ capifs_exit();
+}
+
+#endif
diff --git a/drivers/isdn/avmb1/capifs.h b/drivers/isdn/avmb1/capifs.h
new file mode 100644
index 000000000..f6b8072ed
--- /dev/null
+++ b/drivers/isdn/avmb1/capifs.h
@@ -0,0 +1,25 @@
+/*
+ * $Id: capifs.h,v 1.2 2000/03/08 17:06:33 calle Exp $
+ *
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
+ *
+ * $Log: capifs.h,v $
+ * Revision 1.2 2000/03/08 17:06:33 calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.1 2000/03/03 16:48:38 calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ * It is now possible to create a connection with a CAPI2.0 applikation
+ * and than to handle the data connection from /dev/capi/ (capifs) and also
+ * using async or sync PPP on this connection.
+ * The two major device number 190 and 191 are not confirmed yet,
+ * but I want to save the code in cvs, before I go on.
+ *
+ *
+ */
+
+void capifs_new_ncci(char type, unsigned int num, kdev_t device);
+void capifs_free_ncci(char type, unsigned int num);
diff --git a/drivers/isdn/avmb1/capiutil.c b/drivers/isdn/avmb1/capiutil.c
index 3482f2a97..6f10025f5 100644
--- a/drivers/isdn/avmb1/capiutil.c
+++ b/drivers/isdn/avmb1/capiutil.c
@@ -1,5 +1,5 @@
/*
- * $Id: capiutil.c,v 1.10 1999/08/31 11:19:54 paul Exp $
+ * $Id: capiutil.c,v 1.11 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 convert capi message to capi message struct
*
@@ -7,6 +7,17 @@
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capiutil.c,v $
+ * Revision 1.11 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.10 1999/08/31 11:19:54 paul
* various spelling corrections (new checksums may be needed, Karsten!)
*
@@ -794,7 +805,7 @@ static char *pnames[] =
/*15 */ "Class",
/*16 */ "ConnectedNumber",
/*17 */ "ConnectedSubaddress",
- /*18 */ "Data",
+ /*18 */ "Data32",
/*19 */ "DataHandle",
/*1a */ "DataLength",
/*1b */ "FacilityConfirmationParameter",
@@ -892,13 +903,7 @@ static void protocol_message_2_pars(_cmsg * cmsg, int level)
cmsg->l += 2;
break;
case _CDWORD:
- if (strcmp(NAME, "Data") == 0) {
- bufprint("%-*s = ", slen, NAME);
- printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l),
- *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32)));
- bufprint("\n");
- } else
- bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
+ bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
cmsg->l += 4;
break;
case _CSTRUCT:
diff --git a/drivers/isdn/avmb1/capiutil.h b/drivers/isdn/avmb1/capiutil.h
index 3825ac308..8435ede45 100644
--- a/drivers/isdn/avmb1/capiutil.h
+++ b/drivers/isdn/avmb1/capiutil.h
@@ -1,5 +1,5 @@
/*
- * $Id: capiutil.h,v 1.4 1999/09/15 08:16:03 calle Exp $
+ * $Id: capiutil.h,v 1.5 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 defines & types
*
@@ -7,6 +7,17 @@
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capiutil.h,v $
+ * Revision 1.5 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.4 1999/09/15 08:16:03 calle
* Implementation of 64Bit extention complete.
*
@@ -36,28 +47,47 @@
#include <asm/types.h>
-#define CAPIMSG_LEN(m) (m[0] | (m[1] << 8))
-#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8))
-#define CAPIMSG_COMMAND(m) (m[4])
-#define CAPIMSG_SUBCOMMAND(m) (m[5])
-#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8))
+#define CAPIMSG_BASELEN 8
+#define CAPIMSG_U8(m, off) (m[off])
+#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8))
+#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24))
+#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0)
+#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2)
+#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4)
+#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5)
+#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5]))
+#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6)
#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
-#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24))
+#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8)
#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
-#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24))
-#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8))
-
-#define CAPIMSG_SETAPPID(m, applid) \
- do { \
- ((__u8 *)m)[2] = (__u16)(applid) & 0xff; \
- ((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \
- } while (0)
-
-#define CAPIMSG_SETLEN(m, len) \
- do { \
- ((__u8 *)m)[0] = (__u16)(len) & 0xff; \
- ((__u8 *)m)[1] = ((__u16)(len) >> 8) & 0xff; \
- } while (0)
+#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */
+
+static inline void capimsg_setu8(void *m, int off, __u8 val)
+{
+ ((__u8 *)m)[off] = val;
+}
+
+static inline void capimsg_setu16(void *m, int off, __u16 val)
+{
+ ((__u8 *)m)[off] = val & 0xff;
+ ((__u8 *)m)[off+1] = (val >> 8) & 0xff;
+}
+
+static inline void capimsg_setu32(void *m, int off, __u32 val)
+{
+ ((__u8 *)m)[off] = val & 0xff;
+ ((__u8 *)m)[off+1] = (val >> 8) & 0xff;
+ ((__u8 *)m)[off+2] = (val >> 16) & 0xff;
+ ((__u8 *)m)[off+3] = (val >> 24) & 0xff;
+}
+
+#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len)
+#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid)
+#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd)
+#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd)
+#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid)
+#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr)
+#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len)
/*----- basic-type definitions -----*/
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
index d82fbc496..d678a8ad7 100644
--- a/drivers/isdn/avmb1/kcapi.c
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -1,11 +1,22 @@
/*
- * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $
+ * $Id: kcapi.c,v 1.13 2000/03/03 15:50:42 calle Exp $
*
* Kernel CAPI 2.0 Module
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: kcapi.c,v $
+ * Revision 1.13 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.12 2000/01/28 16:45:39 calle
* new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
* will search named driver and call the add_card function if one exist.
@@ -78,6 +89,7 @@
#include <linux/tqueue.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
+#include <linux/locks.h>
#include <asm/uaccess.h>
#include "capicmd.h"
#include "capiutil.h"
@@ -86,7 +98,7 @@
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.12 $";
+static char *revision = "$Revision: 1.13 $";
/* ------------------------------------------------------------- */
@@ -125,8 +137,8 @@ struct capi_appl {
__u16 applid;
capi_register_params rparam;
int releasing;
- __u32 param;
- void (*signal) (__u16 applid, __u32 param);
+ void *param;
+ void (*signal) (__u16 applid, void *param);
struct sk_buff_head recv_queue;
int nncci;
struct capi_ncci *nccilist;
@@ -137,6 +149,14 @@ struct capi_appl {
unsigned long nsentdatapkt;
};
+struct capi_notifier {
+ struct capi_notifier *next;
+ unsigned int cmd;
+ __u32 controller;
+ __u16 applid;
+ __u32 ncci;
+};
+
/* ------------------------------------------------------------- */
static struct capi_version driver_version = {2, 0, 1, 1<<4};
@@ -160,9 +180,9 @@ static struct capi_ctr cards[CAPI_MAXCONTR];
static int ncards = 0;
static struct sk_buff_head recv_queue;
static struct capi_interface_user *capi_users = 0;
+static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;
static struct capi_driver *drivers;
-static long notify_up_set = 0;
-static long notify_down_set = 0;
+static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
static struct tq_struct tq_state_notify;
static struct tq_struct tq_recv_notify;
@@ -304,6 +324,7 @@ static int proc_driver_read_proc(char *page, char **start, off_t off,
int len = 0;
off_t begin = 0;
+ spin_lock(&drivers_lock);
for (driver = drivers; driver; driver = driver->next) {
len += sprintf(page+len, "%-32s %d %s\n",
driver->name,
@@ -317,6 +338,7 @@ static int proc_driver_read_proc(char *page, char **start, off_t off,
}
}
endloop:
+ spin_unlock(&drivers_lock);
if (!driver)
*eof = 1;
if (off >= len+begin)
@@ -336,6 +358,7 @@ static int proc_users_read_proc(char *page, char **start, off_t off,
int len = 0;
off_t begin = 0;
+ spin_lock(&capi_users_lock);
for (cp = capi_users; cp ; cp = cp->next) {
len += sprintf(page+len, "%s\n", cp->name);
if (len+begin > off+count)
@@ -346,6 +369,7 @@ static int proc_users_read_proc(char *page, char **start, off_t off,
}
}
endloop:
+ spin_unlock(&capi_users_lock);
if (cp == 0)
*eof = 1;
if (off >= len+begin)
@@ -510,6 +534,161 @@ static void proc_capi_exit(void)
}
}
+/* -------- Notifier handling --------------------------------- */
+
+static struct capi_notifier_list{
+ struct capi_notifier *head;
+ struct capi_notifier *tail;
+} notifier_list;
+
+static inline void notify_enqueue(struct capi_notifier *np)
+{
+ struct capi_notifier_list *q = &notifier_list;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (q->tail) {
+ q->tail->next = np;
+ q->tail = np;
+ } else {
+ q->head = q->tail = np;
+ }
+ restore_flags(flags);
+}
+
+static inline struct capi_notifier *notify_dequeue(void)
+{
+ struct capi_notifier_list *q = &notifier_list;
+ struct capi_notifier *np = 0;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (q->head) {
+ np = q->head;
+ if ((q->head = np->next) == 0)
+ q->tail = 0;
+ np->next = 0;
+ }
+ restore_flags(flags);
+ return np;
+}
+
+static int notify_push(unsigned int cmd, __u32 controller,
+ __u16 applid, __u32 ncci)
+{
+ struct capi_notifier *np;
+
+ np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
+ if (!np)
+ return -1;
+ memset(np, 0, sizeof(struct capi_notifier));
+ np->cmd = cmd;
+ np->controller = controller;
+ np->applid = applid;
+ np->ncci = ncci;
+ notify_enqueue(np);
+ MOD_INC_USE_COUNT;
+ queue_task(&tq_state_notify, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return 0;
+}
+
+/* -------- KCI_CONTRUP --------------------------------------- */
+
+static void notify_up(__u32 contr)
+{
+ struct capi_interface_user *p;
+
+ printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
+ }
+ spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_CONTRDOWN ------------------------------------- */
+
+static void notify_down(__u32 contr)
+{
+ struct capi_interface_user *p;
+ printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRDOWN, contr, 0);
+ }
+ spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_NCCIUP ---------------------------------------- */
+
+static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci)
+{
+ struct capi_interface_user *p;
+ struct capi_ncciinfo n;
+ n.applid = applid;
+ n.ncci = ncci;
+ /*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_NCCIUP, contr, &n);
+ }
+ spin_unlock(&capi_users_lock);
+};
+
+/* -------- KCI_NCCIDOWN -------------------------------------- */
+
+static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci)
+{
+ struct capi_interface_user *p;
+ struct capi_ncciinfo n;
+ n.applid = applid;
+ n.ncci = ncci;
+ /*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_NCCIDOWN, contr, &n);
+ }
+ spin_unlock(&capi_users_lock);
+};
+
+/* ------------------------------------------------------------ */
+
+static void inline notify_doit(struct capi_notifier *np)
+{
+ switch (np->cmd) {
+ case KCI_CONTRUP:
+ notify_up(np->controller);
+ break;
+ case KCI_CONTRDOWN:
+ notify_down(np->controller);
+ break;
+ case KCI_NCCIUP:
+ notify_ncciup(np->controller, np->applid, np->ncci);
+ break;
+ case KCI_NCCIDOWN:
+ notify_nccidown(np->controller, np->applid, np->ncci);
+ break;
+ }
+}
+
+static void notify_handler(void *dummy)
+{
+ struct capi_notifier *np;
+
+ while ((np = notify_dequeue()) != 0) {
+ notify_doit(np);
+ kfree(np);
+ MOD_DEC_USE_COUNT;
+ }
+}
+
/* -------- NCCI Handling ------------------------------------- */
static inline void mq_init(struct capi_ncci * np)
@@ -617,6 +796,7 @@ static void controllercb_new_ncci(struct capi_ctr * card,
APPL(appl)->nncci++;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
+ notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci);
}
static void controllercb_free_ncci(struct capi_ctr * card,
@@ -634,6 +814,7 @@ static void controllercb_free_ncci(struct capi_ctr * card,
kfree(np);
APPL(appl)->nncci--;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
+ notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci);
return;
}
}
@@ -734,42 +915,6 @@ error:
kfree_skb(skb);
}
-/* -------- Notifier ------------------------------------------ */
-
-static void notify_up(__u32 contr)
-{
- struct capi_interface_user *p;
-
- printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
- for (p = capi_users; p; p = p->next) {
- if (!p->callback) continue;
- (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
- }
-}
-
-static void notify_down(__u32 contr)
-{
- struct capi_interface_user *p;
- printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
- for (p = capi_users; p; p = p->next) {
- if (!p->callback) continue;
- (*p->callback) (KCI_CONTRDOWN, contr, 0);
- }
-}
-
-static void notify_handler(void *dummy)
-{
- __u32 contr;
-
- for (contr=1; VALID_CARD(contr); contr++)
- if (test_and_clear_bit(contr, &notify_up_set))
- notify_up(contr);
- for (contr=1; VALID_CARD(contr); contr++)
- if (test_and_clear_bit(contr, &notify_down_set))
- notify_down(contr);
-}
-
-
static void controllercb_ready(struct capi_ctr * card)
{
__u16 appl;
@@ -782,11 +927,10 @@ static void controllercb_ready(struct capi_ctr * card)
card->driver->register_appl(card, appl, &APPL(appl)->rparam);
}
- set_bit(CARDNR(card), &notify_up_set);
- queue_task(&tq_state_notify, &tq_scheduler);
-
printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
CARDNR(card), card->name);
+
+ notify_push(KCI_CONTRUP, CARDNR(card), 0, 0);
}
static void controllercb_reseted(struct capi_ctr * card)
@@ -812,6 +956,7 @@ static void controllercb_reseted(struct capi_ctr * card)
struct capi_ncci *np = *pp;
*pp = np->next;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
+ notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci);
kfree(np);
nextpp = pp;
} else {
@@ -819,9 +964,10 @@ static void controllercb_reseted(struct capi_ctr * card)
}
}
}
- set_bit(CARDNR(card), &notify_down_set);
- queue_task(&tq_state_notify, &tq_scheduler);
+
printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card));
+
+ notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0);
}
static void controllercb_suspend_output(struct capi_ctr *card)
@@ -952,9 +1098,12 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
{
struct capi_driver **pp;
+ MOD_INC_USE_COUNT;
+ spin_lock(&drivers_lock);
for (pp = &drivers; *pp; pp = &(*pp)->next) ;
driver->next = 0;
*pp = driver;
+ spin_unlock(&drivers_lock);
printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
sprintf(driver->procfn, "capi/drivers/%s", driver->name);
driver->procent = create_proc_entry(driver->procfn, 0, 0);
@@ -974,6 +1123,7 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
void detach_capi_driver(struct capi_driver *driver)
{
struct capi_driver **pp;
+ spin_lock(&drivers_lock);
for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
if (*pp) {
*pp = (*pp)->next;
@@ -981,10 +1131,12 @@ void detach_capi_driver(struct capi_driver *driver)
} else {
printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
}
+ spin_unlock(&drivers_lock);
if (driver->procent) {
remove_proc_entry(driver->procfn, 0);
driver->procent = 0;
}
+ MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
@@ -1041,6 +1193,7 @@ static __u16 capi_release(__u16 applid)
if (!VALID_APPLID(applid) || APPL(applid)->releasing)
return CAPI_ILLAPPNR;
+ APPL(applid)->releasing++;
while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
kfree_skb(skb);
for (i = 0; i < CAPI_MAXCONTR; i++) {
@@ -1049,6 +1202,7 @@ static __u16 capi_release(__u16 applid)
APPL(applid)->releasing++;
cards[i].driver->release_appl(&cards[i], applid);
}
+ APPL(applid)->releasing--;
if (APPL(applid)->releasing <= 0) {
APPL(applid)->signal = 0;
APPL_MARK_FREE(applid);
@@ -1128,8 +1282,8 @@ static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
}
static __u16 capi_set_signal(__u16 applid,
- void (*signal) (__u16 applid, __u32 param),
- __u32 param)
+ void (*signal) (__u16 applid, void *param),
+ void *param)
{
if (!VALID_APPLID(applid))
return CAPI_ILLAPPNR;
@@ -1194,10 +1348,12 @@ static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp)
static struct capi_driver *find_driver(char *name)
{
struct capi_driver *dp;
+ spin_lock(&drivers_lock);
for (dp = drivers; dp; dp = dp->next)
if (strcmp(dp->name, name) == 0)
- return dp;
- return 0;
+ break;
+ spin_unlock(&drivers_lock);
+ return dp;
}
#ifdef CONFIG_AVMB1_COMPAT
@@ -1272,6 +1428,10 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
card = CARD(ldef.contr);
if (card->cardstate == CARD_FREE)
return -ESRCH;
+ if (card->driver->load_firmware == 0) {
+ printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
+ return -ESRCH;
+ }
if (ldef.t4file.len <= 0) {
printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
@@ -1490,16 +1650,20 @@ struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
{
struct capi_interface_user *p;
+ MOD_INC_USE_COUNT;
+ spin_lock(&capi_users_lock);
for (p = capi_users; p; p = p->next) {
if (p == userp) {
+ spin_unlock(&capi_users_lock);
printk(KERN_ERR "kcapi: double attach from %s\n",
userp->name);
+ MOD_DEC_USE_COUNT;
return 0;
}
}
userp->next = capi_users;
capi_users = userp;
- MOD_INC_USE_COUNT;
+ spin_unlock(&capi_users_lock);
printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);
return &avmb1_interface;
@@ -1509,15 +1673,18 @@ int detach_capi_interface(struct capi_interface_user *userp)
{
struct capi_interface_user **pp;
+ spin_lock(&capi_users_lock);
for (pp = &capi_users; *pp; pp = &(*pp)->next) {
if (*pp == userp) {
*pp = userp->next;
+ spin_unlock(&capi_users_lock);
userp->next = 0;
- MOD_DEC_USE_COUNT;
printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
+ MOD_DEC_USE_COUNT;
return 0;
}
}
+ spin_unlock(&capi_users_lock);
printk(KERN_ERR "kcapi: double detach from %s\n", userp->name);
return -1;
}
@@ -1623,7 +1790,6 @@ void cleanup_module(void)
strcpy(rev, "1.0");
}
- schedule(); /* execute queued tasks .... */
proc_capi_exit();
printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
}
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 5dc6924e1..f8e7b418c 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -1,5 +1,5 @@
/*
- * $Id: divert_procfs.c,v 1.6 2000/02/14 19:23:03 werner Exp $
+ * $Id: divert_procfs.c,v 1.8 2000/03/03 16:37:11 kai Exp $
*
* Filesystem handling for the diversion supplementary services.
*
@@ -20,6 +20,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: divert_procfs.c,v $
+ * Revision 1.8 2000/03/03 16:37:11 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.7 2000/03/02 00:11:06 werner
+ *
+ * Changes related to procfs for 2.3.48
+ *
* Revision 1.6 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
@@ -302,13 +310,13 @@ isdn_divert_lseek(struct file *file, loff_t offset, int orig)
static struct file_operations isdn_fops =
{
- llseek: isdn_divert_lseek,
- read: isdn_divert_read,
- write: isdn_divert_write,
- poll: isdn_divert_poll,
- ioctl: isdn_divert_ioctl,
- open: isdn_divert_open,
- release: isdn_divert_close,
+ llseek: isdn_divert_lseek,
+ read: isdn_divert_read,
+ write: isdn_divert_write,
+ poll: isdn_divert_poll,
+ ioctl: isdn_divert_ioctl,
+ open: isdn_divert_open,
+ release: isdn_divert_close,
};
/****************************/
@@ -336,7 +344,7 @@ divert_dev_init(void)
remove_proc_entry("isdn", proc_net);
return (-1);
}
- isdn_divert_entry->proc_fops = &isdn_fops;
+ isdn_divert_entry->proc_fops = &isdn_fops;
#endif /* CONFIG_PROC_FS */
return (0);
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index eb3590069..9cef520bc 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.31 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* IDI interface
@@ -26,6 +26,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * Revision 1.33 2000/03/06 15:45:17 armin
+ * Fixed incomplete number handling with BRI PtP connection.
+ *
+ * Revision 1.32 2000/03/04 17:04:21 armin
+ * Fix of statemachine, B-connect before D-connect,
+ * thanks to Helmut Adams <adams@ipcon.de>
+ * Minor change in send-data packet handling.
+ *
* Revision 1.31 2000/02/22 16:26:40 armin
* Fixed membase error message.
* Fixed missing log buffer struct.
@@ -156,7 +164,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.31 $";
+char *eicon_idi_revision = "$Revision: 1.33 $";
eicon_manifbuf *manbuf;
@@ -2515,15 +2523,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
break;
case 3: /* incomplete number */
eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No);
- switch(ccard->type) {
- case EICON_CTYPE_MAESTRAP:
- case EICON_CTYPE_S2M:
- /* TODO (other protocols) */
- chan->fsm_state = EICON_STATE_ICALLW;
- break;
- default:
- idi_do_req(ccard, chan, HANGUP, 0);
- }
+ chan->fsm_state = EICON_STATE_ICALLW;
break;
}
break;
@@ -2560,8 +2560,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
/* On most incoming calls we use automatic connect */
/* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */
}
- } else
- idi_hangup(ccard, chan);
+ } else {
+ if (chan->fsm_state != EICON_STATE_ACTIVE)
+ idi_hangup(ccard, chan);
+ }
break;
case CALL_CON:
eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
@@ -3012,11 +3014,13 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
if (((len - offset) > 270) &&
+ (chan->l2prot != ISDN_PROTO_L2_MODEM) &&
+ (chan->l2prot != ISDN_PROTO_L2_FAX) &&
(chan->l2prot != ISDN_PROTO_L2_TRANS)) {
reqbuf->Req = IDI_N_MDATA;
} else {
reqbuf->Req = IDI_N_DATA;
- if (ack) reqbuf->Req |= N_D_BIT;
+ /* if (ack) reqbuf->Req |= N_D_BIT; */
}
reqbuf->ReqCh = chan->e.IndCh;
reqbuf->ReqId = 1;
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 4a01218c3..7c5163f82 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $
+/* $Id: callc.c,v 2.41 2000/03/17 07:07:42 kai Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,9 @@
* Fritz Elfert
*
* $Log: callc.c,v $
+ * Revision 2.41 2000/03/17 07:07:42 kai
+ * fixed oops when dialing out without l3 protocol selected
+ *
* Revision 2.40 1999/12/19 12:59:56 keil
* fix leased line handling
* and cosmetics
@@ -167,7 +170,7 @@
#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
#endif /* MODULE */
-const char *lli_revision = "$Revision: 2.40 $";
+const char *lli_revision = "$Revision: 2.41 $";
extern struct IsdnCard cards[];
extern int nrcards;
@@ -349,6 +352,8 @@ lli_deliver_cause(struct Channel *chanp)
{
isdn_ctrl ic;
+ if (!chanp->proc)
+ return;
if (chanp->proc->para.cause == NO_CAUSE)
return;
ic.driver = chanp->cs->myid;
@@ -641,7 +646,8 @@ lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
lli_leased_hup(fi, chanp);
} else {
FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
+ if (chanp->proc)
+ chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
chanp->proc);
}
@@ -656,7 +662,8 @@ lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
lli_leased_hup(fi, chanp);
} else {
FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->proc->para.cause = 0x15; /* Call Rejected */
+ if (chanp->proc)
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
chanp->proc);
}
@@ -688,7 +695,8 @@ lli_reject_req(struct FsmInst *fi, int event, void *arg)
return;
}
#ifndef ALERT_REJECT
- chanp->proc->para.cause = 0x15; /* Call Rejected */
+ if (chanp->proc)
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
lli_dhup_close(fi, event, arg);
#else
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 2b0451a0a..5c36458ff 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $
+/* $Id: l3dss1.c,v 2.24 2000/03/19 15:26:35 kai Exp $
* EURO/DSS1 D-channel protocol
*
@@ -13,6 +13,9 @@
* Fritz Elfert
*
* $Log: l3dss1.c,v $
+ * Revision 2.24 2000/03/19 15:26:35 kai
+ * changed keypad to use specified bearer, instead of always a-law
+ *
* Revision 2.23 2000/02/26 01:38:14 keil
* Fixes for V.110 encoding LLC from Jens Jakobsen
*
@@ -107,7 +110,7 @@
#include <linux/config.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.23 $";
+const char *dss1_revision = "$Revision: 2.24 $";
#define EXT_BEARER_CAPS 1
@@ -1313,39 +1316,31 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
/*
* Set Bearer Capability, Map info from 1TR6-convention to EDSS1
*/
- if (!send_keypad)
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
- else { *p++ = 0x4; /* assumptions for bearer services with keypad */
- *p++ = 0x3;
- *p++ = 0x80;
- *p++ = 0x90;
- *p++ = 0xa3;
- *p++ = 0x18; /* no specific channel */
- *p++ = 0x01;
- *p++ = 0x83;
- *p++ = 0x2C; /* IE keypad */
+ switch (pc->para.setup.si1) {
+ case 1: /* Telephony */
+ *p++ = IE_BEARER;
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
+ break;
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
+ default:
+ *p++ = IE_BEARER;
+ *p++ = 0x2; /* Length */
+ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ break;
+ }
+
+ if (send_keypad) {
+ *p++ = IE_KEYPAD;
*p++ = strlen(teln);
while (*teln)
- *p++ = (*teln++) & 0x7F;
- }
+ *p++ = (*teln++) & 0x7F;
+ }
-
/*
* What about info2? Mapping to High-Layer-Compatibility?
*/
@@ -1394,7 +1389,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
sp++;
}
if (*msn) {
- *p++ = 0x6c;
+ *p++ = IE_CALLING_PN;
*p++ = strlen(msn) + (screen ? 2 : 1);
/* Classify as AnyPref. */
if (screen) {
@@ -1407,7 +1402,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
}
if (sub) {
*sub++ = '.';
- *p++ = 0x6d; /* Calling party subaddress */
+ *p++ = IE_CALLING_SUB;
*p++ = strlen(sub) + 2;
*p++ = 0x80; /* NSAP coded */
*p++ = 0x50; /* local IDI format */
@@ -1425,33 +1420,27 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
}
if (!send_keypad) {
- *p++ = 0x70;
- *p++ = strlen(teln) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
- if (sub) {
- *sub++ = '.';
- *p++ = 0x71; /* Called party subaddress */
- *p++ = strlen(sub) + 2;
- *p++ = 0x80; /* NSAP coded */
- *p++ = 0x50; /* local IDI format */
- while (*sub)
- *p++ = *sub++ & 0x7f;
- }
+ *p++ = IE_CALLED_PN;
+ *p++ = strlen(teln) + 1;
+ /* Classify as AnyPref. */
+ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+ while (*teln)
+ *p++ = *teln++ & 0x7f;
+
+ if (sub) {
+ *sub++ = '.';
+ *p++ = IE_CALLED_SUB;
+ *p++ = strlen(sub) + 2;
+ *p++ = 0x80; /* NSAP coded */
+ *p++ = 0x50; /* local IDI format */
+ while (*sub)
+ *p++ = *sub++ & 0x7f;
+ }
}
#if EXT_BEARER_CAPS
- if (send_keypad) { /* special handling independant of si2 */
- *p++ = 0x7c;
- *p++ = 0x03;
- *p++ = 0x80;
- *p++ = 0x90;
- *p++ = 0xa3;
- } else if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
-
- *p++ = 0x7c;
+ if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
+
+ *p++ = IE_LLC;
*p++ = 0x04;
*p++ = 0x88;
*p++ = 0x90;
@@ -1459,7 +1448,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
*p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
} else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
- *p++ = 0x7c;
+ *p++ = IE_LLC;
*p++ = 0x05;
*p++ = 0x88;
*p++ = 0x90;
@@ -1468,7 +1457,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
*p++ = 0x82;
} else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
- *p++ = 0x7c;
+ *p++ = IE_LLC;
*p++ = 0x06;
*p++ = 0x88;
*p++ = 0x90;
@@ -1477,18 +1466,18 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
#ifndef CONFIG_HISAX_NO_LLC
} else {
switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = 0x7c; /* BC-IE-code */
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
+ case 1: /* Telephony */
+ *p++ = IE_LLC;
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
default:
- *p++ = 0x7c; /* BC-IE-code */
- *p++ = 0x2; /* Length */
+ *p++ = IE_LLC;
+ *p++ = 0x2; /* Length */
*p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
*p++ = 0x90; /* Circuit-Mode 64kbps */
break;
diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc
index afb83e1c8..ec21e78c7 100644
--- a/drivers/isdn/hisax/md5sums.asc
+++ b/drivers/isdn/hisax/md5sums.asc
@@ -11,9 +11,9 @@ dd3955847bbf680b41233478fe521d88 isdnl1.c
bb51bd223040b511c18f091da5ab6456 isdnl2.c
b7aa7f97b2374967a4aca7c52991142c isdnl3.c
a23fbf8879c1432b04640b8b04bdf419 tei.c
-ce248e56c2e1326012d0b25f92bbf99b callc.c
+838791b14269ec94c74ba4ae89c022e6 callc.c
bf9605b36429898f7be6630034e83230 cert.c
-6ce0a184127be1a44747e2017ed24ad9 l3dss1.c
+a30e6253837739f6f54d9dadcd42d9f2 l3dss1.c
a3a570781f828b6d59e6b231653133de l3_1tr6.c
4aeba32c4c3480d2a6b9af34600b974f elsa.c
a296edc459b508bf0346c3132815a4db diva.c
@@ -23,9 +23,9 @@ a296edc459b508bf0346c3132815a4db diva.c
Version: 2.6.3i
Charset: noconv
-iQCVAwUBOLcvXDpxHvX/mS9tAQGPWAP9Fg14RXcAwjCy4VeFoDBMOFpxllvG7xZR
-HQKENCYIzXKPb6I/IBUv3+BhL8Lnhjw8a2DXz6c6u+0nmUIFnzyt1BfzT70P9rKd
-BBN7f1KdIiQEmv0fZwd79Rz5PYvRDbY520bNTJZhorwqGI/qc3gGgHVtSR8OHhuS
-ZMQ1pb9W6jE=
-=CA5N
+iQCVAwUBONlcejpxHvX/mS9tAQFWYAP/WmxgwQ7W6gVnsMkUlwzE1TKGWVJdGUTC
+7WrKEtdweuzW3/7WEzjBoZgUEcpugJYK3JENby1xjh3yIHfws4HqLme1yXAmkYUK
+6LmW96HC2g4wj7PH0hvLnzTOtXDGTppU7KJibbB+ziyhBbs6SGXOD4zHrCWmT9ld
+CURhfNgftIs=
+=AA+Q
-----END PGP SIGNATURE-----
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index d3c269a04..aa6776d3b 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $
+/* $Id: q931.c,v 1.8 2000/03/21 23:53:22 kai Exp $
* q931.c code to decode ITU Q.931 call control messages
*
@@ -14,6 +14,9 @@
*
*
* $Log: q931.c,v $
+ * Revision 1.8 2000/03/21 23:53:22 kai
+ * fix backwards compatibility
+ *
* Revision 1.7 1998/11/15 23:55:17 keil
* changes from 2.0
*
@@ -201,29 +204,6 @@ struct MessageType mt_n1[] =
#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
-static struct MessageType fac_1tr6[] =
-{
- {FAC_Sperre, "Sperre"},
- {FAC_Forward1, "Forward 1"},
- {FAC_Forward2, "Forward 2"},
- {FAC_Konferenz, "Konferenz"},
- {FAC_GrabBchan, "Grab Bchannel"},
- {FAC_Reactivate, "Reactivate"},
- {FAC_Konferenz3, "Dreier Konferenz"},
- {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
- {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
- {FAC_NummernIdent, "Rufnummer-Identifizierung"},
- {FAC_GBG, "GBG"},
- {FAC_DisplayUebergeben, "Display Uebergeben"},
- {FAC_DisplayUmgeleitet, "Display Umgeleitet"},
- {FAC_Unterdruecke, "Unterdruecke Rufnummer"},
- {FAC_Deactivate, "Deactivate"},
- {FAC_Activate, "Activate"},
- {FAC_SPV, "SPV"},
- {FAC_Rueckwechsel, "Rueckwechsel"},
- {FAC_Umleitung, "Umleitung"}
-};
-#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType))
static int
prbits(char *dest, u_char b, int start, int len)
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index c6fe2acdd..f9ce17675 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1,4 +1,4 @@
-/* $Id: w6692.c,v 1.2 2000/02/26 00:35:13 keil Exp $
+/* $Id: w6692.c,v 1.4 2000/03/16 23:24:11 werner Exp $
* w6692.c Winbond W6692 specific routines
*
@@ -8,6 +8,14 @@
* This file is (c) under GNU PUBLIC LICENSE
*
* $Log: w6692.c,v $
+ * Revision 1.4 2000/03/16 23:24:11 werner
+ *
+ * Fixed an additional location
+ *
+ * Revision 1.3 2000/03/16 22:41:36 werner
+ *
+ * Tried to fix second B-channel problem (still not tested)
+ *
* Revision 1.2 2000/02/26 00:35:13 keil
* Fix skb freeing in interrupt context
*
@@ -50,7 +58,7 @@ static const PCI_ENTRY id_list[] =
extern const char *CardType[];
-const char *w6692_revision = "$Revision: 1.2 $";
+const char *w6692_revision = "$Revision: 1.4 $";
#define DBUSY_TIMER_VALUE 80
@@ -317,10 +325,13 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
{
u_char val;
u_char r;
- struct BCState *bcs = cs->bcs + bchan;
+ struct BCState *bcs = cs->bcs;
struct sk_buff *skb;
int count;
+ if (bcs->channel != bchan)
+ bcs++; /* hardware bchan must match ! */
+
val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
@@ -724,7 +735,9 @@ static void
W6692Bmode(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
- int bchan = bcs->hw.w6692.bchan;
+ int bchan = bc;
+
+ bcs->hw.w6692.bchan = bc;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "w6692 %c mode %d ichan %d",
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 20d69e32f..ac67610f7 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_procconf.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+/* $Id: hysdn_procconf.c,v 1.4 2000/03/03 16:37:12 kai Exp $
* Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_procconf.c,v $
+ * Revision 1.4 2000/03/03 16:37:12 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.3 2000/03/02 00:11:07 werner
+ *
+ * Changes related to procfs for 2.3.48
+ *
* Revision 1.2 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
@@ -40,7 +48,7 @@
#include "hysdn_defs.h"
-static char *hysdn_procconf_revision = "$Revision: 1.2 $";
+static char *hysdn_procconf_revision = "$Revision: 1.4 $";
#define INFO_OUT_LEN 80 /* length of info line including lf */
@@ -403,11 +411,11 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
/******************************************************/
static struct file_operations conf_fops =
{
- llseek: hysdn_dummy_lseek,
- read: hysdn_conf_read,
- write: hysdn_conf_write,
- open: hysdn_conf_open,
- release: hysdn_conf_close,
+ llseek: hysdn_dummy_lseek,
+ read: hysdn_conf_read,
+ write: hysdn_conf_write,
+ open: hysdn_conf_open,
+ release: hysdn_conf_close,
};
/*****************************/
@@ -438,7 +446,6 @@ hysdn_procconf_init(void)
if ((card->procconf = (void *) create_proc_entry(conf_name,
S_IFREG | S_IRUGO | S_IWUSR,
hysdn_proc_entry)) != NULL) {
-
((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
hysdn_proclog_init(card); /* init the log file entry */
}
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 4a585053a..d93b59995 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_proclog.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+/* $Id: hysdn_proclog.c,v 1.4 2000/03/03 16:37:12 kai Exp $
* Linux driver for HYSDN cards, /proc/net filesystem log functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_proclog.c,v $
+ * Revision 1.4 2000/03/03 16:37:12 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.3 2000/03/02 00:11:07 werner
+ *
+ * Changes related to procfs for 2.3.48
+ *
* Revision 1.2 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
@@ -40,7 +48,7 @@
#include "hysdn_defs.h"
-static char *hysdn_proclog_revision = "$Revision: 1.2 $";
+static char *hysdn_proclog_revision = "$Revision: 1.4 $";
/* the proc subdir for the interface is defined in the procconf module */
extern struct proc_dir_entry *hysdn_proc_entry;
@@ -420,14 +428,15 @@ hysdn_log_poll(struct file *file, poll_table * wait)
/**************************************************/
static struct file_operations log_fops =
{
- llseek: hysdn_dummy_lseek,
- read: hysdn_log_read,
- write: hysdn_log_write,
- poll: hysdn_log_poll,
- open: hysdn_log_open,
- release: hysdn_log_close,
+ llseek: hysdn_dummy_lseek,
+ read: hysdn_log_read,
+ write: hysdn_log_write,
+ poll: hysdn_log_poll,
+ open: hysdn_log_open,
+ release: hysdn_log_close,
};
+
/***********************************************************************************/
/* hysdn_proclog_init is called when the module is loaded after creating the cards */
/* conf files. */
@@ -441,10 +450,9 @@ hysdn_proclog_init(hysdn_card * card)
if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
memset(pd, 0, sizeof(struct procdata));
-
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
- pd->log->proc_fops = &log_fops; /* set new operations table */
+ pd->log->proc_fops = &log_fops;
init_waitqueue_head(&(pd->rd_queue));
diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c
index 3599d2ada..2be90eb6f 100644
--- a/drivers/isdn/isdn_audio.c
+++ b/drivers/isdn/isdn_audio.c
@@ -292,38 +292,25 @@ static char dtmf_matrix[4][4] =
{'*', '0', '#', 'D'}
};
-
-/*
- * egcs 2.95 complain about invalid asm statement:
- * "fixed or forbidden register 2 (cx) was spilled for class CREG."
- */
-#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__)
-#if __GNUC__ == 2 && __GNUC_MINOR__ < 95
-#define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
-#endif
-#endif
-
-#ifdef ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
static inline void
isdn_audio_tlookup(const void *table, void *buff, unsigned long n)
{
- __asm__("cld\n"
+#ifdef __i386__
+ unsigned long d0, d1, d2, d3;
+ __asm__ __volatile__(
+ "cld\n"
"1:\tlodsb\n\t"
"xlatb\n\t"
"stosb\n\t"
"loop 1b\n\t"
- : : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
- : "bx", "cx", "di", "si", "ax");
-}
-
+ : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
+ : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
+ : "memory", "ax");
#else
-static inline void
-isdn_audio_tlookup(const char *table, char *buff, unsigned long n)
-{
while (n--)
*buff++ = table[*(unsigned char *)buff];
-}
#endif
+}
void
isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index b8e9efa0f..e9c3ce50b 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.99 2000/02/26 01:00:52 keil Exp $
+/* $Id: isdn_common.c,v 1.100 2000/03/03 16:37:11 kai Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.100 2000/03/03 16:37:11 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
* Revision 1.99 2000/02/26 01:00:52 keil
* changes from 2.3.47
*
@@ -449,7 +453,7 @@
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.99 $";
+static char *isdn_revision = "$Revision: 1.100 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
diff --git a/drivers/isdn/isdn_concap.c b/drivers/isdn/isdn_concap.c
index ca05f8bf3..07722dbb1 100644
--- a/drivers/isdn/isdn_concap.c
+++ b/drivers/isdn/isdn_concap.c
@@ -1,10 +1,13 @@
-/* $Id: isdn_concap.c,v 1.6 1999/08/22 20:26:01 calle Exp $
+/* $Id: isdn_concap.c,v 1.7 2000/03/21 23:53:22 kai Exp $
* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
* stuff goes here. Stuff that depends only on the concap protocol goes to
* another -- protocol specific -- source file.
*
* $Log: isdn_concap.c,v $
+ * Revision 1.7 2000/03/21 23:53:22 kai
+ * fix backwards compatibility
+ *
* Revision 1.6 1999/08/22 20:26:01 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -58,15 +61,20 @@
int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
{
- int tmp;
struct net_device *ndev = concap -> net_dev;
- isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
+ isdn_net_local *lp = isdn_net_get_locked_lp(nd);
IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
+ if (!lp) {
+ IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 1);
+ return 1;
+ }
lp->huptimer = 0;
- tmp=isdn_net_send_skb(ndev, lp, skb);
- IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp);
- return tmp;
+ isdn_net_writebuf_skb(lp, skb);
+ spin_unlock_bh(&lp->xmit_lock);
+ IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 0);
+ return 0;
}
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index ee3af91fa..8948e43f5 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.110 2000/02/26 01:00:53 keil Exp $
+/* $Id: isdn_net.c,v 1.122 2000/03/20 22:37:46 detabc Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,50 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.122 2000/03/20 22:37:46 detabc
+ * modify abc-extension to work together with the new LL.
+ * remove abc frame-counter (is obsolete now).
+ * use the new lp->super_tx_queue for internal queueing (bsd-rawip-compress).
+ * modify isdn_net_xmit() and isdn_net_write_super().
+ * -- Kai, please have a look to this two function's. Thank's.
+ *
+ * Revision 1.121 2000/03/19 15:27:53 kai
+ * no known bugs left...
+ *
+ * Revision 1.120 2000/03/18 16:20:25 kai
+ * cosmetics / renaming
+ *
+ * Revision 1.118 2000/03/17 18:20:46 kai
+ * moved to frame_cnt based flow control
+ * some races still need to be fixed
+ *
+ * Revision 1.117 2000/03/17 17:01:00 kai
+ * cleanup
+ *
+ * Revision 1.116 2000/03/17 16:22:55 kai
+ * we keep track of outstanding packets (given to HL, but not confirmed yet)
+ * now, but we don't use it for flow control yet.
+ *
+ * Revision 1.115 2000/03/17 12:49:42 kai
+ * calling statcallb with ISDN_STAT_BSENT in hard-IRQ context is now
+ * officially allowed. writebuf_skb() will never be called in hard-IRQ context
+ * anymore.
+ *
+ * Revision 1.114 2000/03/16 16:37:41 kai
+ * Allow phone numbers starting with "*" as outgoing numbers for
+ * networking interface. Some PBX's need this to allow dialing internal
+ * numbers (mine, for example ;-)
+ *
+ * Revision 1.113 2000/03/16 15:46:37 kai
+ * a little bugfix and cosmetic changes
+ *
+ * Revision 1.112 2000/03/04 16:20:42 detabc
+ * copy frames before rewriting frame's saddr
+ *
+ * Revision 1.111 2000/02/28 22:28:24 he
+ * moved tx_timeout warning messages in old (2.2.x) branch where it really only
+ * indicates problems.
+ *
* Revision 1.110 2000/02/26 01:00:53 keil
* changes from 2.3.47
*
@@ -487,19 +531,6 @@
* the network layer, and therefore, it only makes sense to call netif_*
* functions on them.
*
- * The old code abused the slaves dev->start to remember the corresponding
- * master's interface state (ifup'ed or not). This does not work with SOFTNET
- * any more, because there's now dev->start anymore.
- * Instead I chose to add isdn_net_started() which gives the state of the
- * master in case of slaves.
- * I'm still not sure if this is how it's supposed to be done this way
- * because it uses netif_running(dev) which might be
- * considered private to the network layer. However, it works for now.
- * Alternative: set a flag in _open() and clear it in _close()
- *
- * I left some dead code around in #if 0 which I'm not absolutely sure about.
- * If no problems turn up, it should be removed later
- *
* --KG
*/
@@ -507,7 +538,7 @@
* Find out if the netdevice has been ifup-ed yet.
* For slaves, look at the corresponding master.
*/
-static int __inline__ isdn_net_started(isdn_net_dev *n)
+static __inline__ int isdn_net_device_started(isdn_net_dev *n)
{
isdn_net_local *lp = n->local;
struct net_device *dev;
@@ -523,7 +554,7 @@ static int __inline__ isdn_net_started(isdn_net_dev *n)
* wake up the network -> net_device queue.
* For slaves, wake the corresponding master interface.
*/
-static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
{
if (lp->master)
netif_wake_queue(lp->master);
@@ -531,6 +562,75 @@ static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
netif_wake_queue(&lp->netdev->dev);
}
+/*
+ * stop the network -> net_device queue.
+ * For slaves, stop the corresponding master interface.
+ */
+static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
+{
+ if (lp->master)
+ netif_stop_queue(lp->master);
+ else
+ netif_stop_queue(&lp->netdev->dev);
+}
+
+/*
+ * find out if the net_device which this lp belongs to (lp can be
+ * master or slave) is busy. It's busy iff all (master and slave)
+ * queues are busy
+ */
+static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
+{
+ isdn_net_local *nlp;
+ isdn_net_dev *nd;
+ unsigned long flags;
+
+ if (!isdn_net_lp_busy(lp))
+ return 0;
+
+ if (lp->master)
+ nd = ((isdn_net_local *) lp->master->priv)->netdev;
+ else
+ nd = lp->netdev;
+
+ spin_lock_irqsave(&nd->queue_lock, flags);
+ nlp = lp->next;
+ while (nlp != lp) {
+ if (!isdn_net_lp_busy(nlp)) {
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+ return 0;
+ }
+ nlp = nlp->next;
+ }
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+ return 1;
+}
+
+static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
+{
+ atomic_inc(&lp->frame_cnt);
+ if (isdn_net_device_busy(lp))
+ isdn_net_device_stop_queue(lp);
+}
+
+static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
+{
+ atomic_dec(&lp->frame_cnt);
+
+ if (!(isdn_net_device_busy(lp))) {
+ if (!skb_queue_empty(&lp->super_tx_queue)) {
+ queue_task(&lp->tqueue, &tq_immediate);
+ } else {
+ isdn_net_device_wake_queue(lp);
+ }
+ }
+}
+
+static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
+{
+ atomic_set(&lp->frame_cnt, 0);
+}
+
/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
* to be safe.
* For 2.3.x we push it up to 20 secs, because call establishment
@@ -546,9 +646,8 @@ static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
-static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *);
-char *isdn_net_revision = "$Revision: 1.110 $";
+char *isdn_net_revision = "$Revision: 1.122 $";
/*
* Code for raw-networking over ISDN
@@ -660,16 +759,12 @@ static void
isdn_net_unbind_channel(isdn_net_local * lp)
{
ulong flags;
+ struct sk_buff *skb;
save_flags(flags);
cli();
- if (lp->first_skb) {
- dev_kfree_skb(lp->first_skb);
- lp->first_skb = NULL;
- }
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- lp->sav_skb = NULL;
+ while ((skb = skb_dequeue(&lp->super_tx_queue))) {
+ kfree_skb(skb);
}
if (!lp->master) { /* reset only master device */
/* Moral equivalent of dev_purge_queues():
@@ -766,6 +861,11 @@ isdn_net_autohup()
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
}
+static void isdn_net_lp_disconnected(isdn_net_local *lp)
+{
+ isdn_net_rm_from_bundle(lp);
+}
+
/*
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
@@ -789,28 +889,9 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
/* A packet has successfully been sent out */
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
+ isdn_net_dec_frame_cnt(lp);
lp->stats.tx_packets++;
lp->stats.tx_bytes += c->parm.length;
- /* some HL drivers deliver
- ISDN_STAT_BSENT from hw interrupt.
- Output routines in isdn_ppp are now
- called with irq disabled such that
- dequeueing the sav_skb while another
- frame is sent will not occur.
- */
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
- struct net_device *mdev;
- if (lp->master)
- mdev = lp->master;
- else
- mdev = &lp->netdev->dev;
- if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
- lp->sav_skb = NULL;
- } else {
- return 1;
- }
- }
- isdn_net_lp_xon(lp);
}
return 1;
case ISDN_STAT_DCONN:
@@ -842,6 +923,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
#ifdef CONFIG_ISDN_PPP
isdn_ppp_free(lp);
#endif
+ isdn_net_lp_disconnected(lp);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
@@ -864,6 +946,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
#endif /* CONFIG_ISDN_X25 */
case ISDN_STAT_BCONN:
/* B-Channel is up */
+ isdn_net_zero_frame_cnt(lp);
switch (lp->dialstate) {
case 5:
case 6:
@@ -881,13 +964,17 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1);
+ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
+ if (lp->master) { /* is lp a slave? */
+ isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
+ isdn_net_add_to_bundle(nd, lp);
+ }
+ }
printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
*/
lp->chargetime = jiffies;
- printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n",
- lp->name, lp->chargetime);
/* reset dial-timeout */
lp->dialstarted = 0;
@@ -903,13 +990,9 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
if( pops->connect_ind)
pops->connect_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
- /* Immediately send first skb to speed up arp */
- if (lp->first_skb) {
-
- if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
- lp->first_skb = NULL;
- }
- if(! lp->first_skb) isdn_net_lp_xon(lp);
+ /* ppp needs to do negotiations first */
+ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
+ isdn_net_device_wake_queue(lp);
return 1;
}
break;
@@ -942,20 +1025,6 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
}
/*
- * Check, if a number contains wildcard-characters, in which case it
- * is for incoming purposes only.
- */
-static int
-isdn_net_checkwild(char *num)
-{
- return ((strchr(num, '?')) ||
- (strchr(num, '*')) ||
- (strchr(num, '[')) ||
- (strchr(num, ']')) ||
- (strchr(num, '^')));
-}
-
-/*
* Perform dialout for net-interfaces and timeout-handling for
* D-Channel-up and B-Channel-up Messages.
* This function is initially called from within isdn_net_start_xmit() or
@@ -1033,7 +1102,7 @@ isdn_net_dial(void)
s = "dial suppressed: isdn system stopped";
else
s = "dial suppressed: dialmode `off'";
- isdn_net_unreachable(&p->dev, lp->first_skb, s);
+ isdn_net_unreachable(&p->dev, 0, s);
isdn_net_hangup(&p->dev);
break;
}
@@ -1066,7 +1135,7 @@ isdn_net_dial(void)
restore_flags(flags);
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out");
+ isdn_net_unreachable(&p->dev, 0, "dial: timed out");
isdn_net_hangup(&p->dev);
break;
}
@@ -1084,7 +1153,7 @@ isdn_net_dial(void)
if (lp->dialtimeout == 0) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times");
+ isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times");
}
isdn_net_hangup(&p->dev);
break;
@@ -1248,6 +1317,7 @@ isdn_net_hangup(struct net_device *d)
#ifdef CONFIG_ISDN_PPP
isdn_ppp_free(lp);
#endif
+ isdn_net_lp_disconnected(lp);
#ifdef CONFIG_ISDN_X25
/* try if there are generic encap protocol
receiver routines and signal the closure of
@@ -1360,31 +1430,83 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
}
/*
- * Generic routine to send out an skbuf.
- * If lowlevel-device does not support support skbufs, use
- * standard send-routine, else send directly.
- *
- * Return: 0 on success, !0 on failure.
+ * this function is used to send supervisory data, i.e. data which was
+ * not received from the network layer, but e.g. frames from ipppd, CCP
+ * reset frames etc.
*/
-int isdn_net_send_skb
- (struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb)
+void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
+{
+ if (in_interrupt()) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ return;
+ }
+
+ spin_lock_bh(&lp->xmit_lock);
+ if (!isdn_net_lp_busy(lp)) {
+ isdn_net_writebuf_skb(lp, skb);
+ } else {
+ skb_queue_tail(&lp->super_tx_queue, skb);
+ }
+ spin_unlock_bh(&lp->xmit_lock);
+}
+
+/*
+ * called from tq_immediate
+ */
+static void
+isdn_net_softint(void *private)
+{
+ isdn_net_local *lp = private;
+ struct sk_buff *skb;
+
+ spin_lock_bh(&lp->xmit_lock);
+ while (!isdn_net_lp_busy(lp)) {
+ skb = skb_dequeue(&lp->super_tx_queue);
+ if (!skb)
+ break;
+ isdn_net_writebuf_skb(lp, skb);
+ }
+ spin_unlock_bh(&lp->xmit_lock);
+}
+
+/*
+ * all frames sent from the (net) LL to a HL driver should go via this function
+ * it's serialized by the caller holding the lp->xmit_lock spinlock
+ */
+void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
{
int ret;
int len = skb->len; /* save len */
- ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
- if (ret == len) {
- lp->transcount += len;
- return 0;
+ /* before obtaining the lock the caller should have checked that
+ the lp isn't busy */
+ if (isdn_net_lp_busy(lp)) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ goto error;
}
- if (ret < 0) {
- dev_kfree_skb(skb);
- lp->stats.tx_errors++;
- return 0;
+
+ if (!(lp->flags & ISDN_NET_CONNECTED)) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ goto error;
}
- return 1;
+ ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
+ if (ret != len) {
+ /* we should never get here */
+ printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+ goto error;
+ }
+
+ lp->transcount += len;
+ isdn_net_inc_frame_cnt(lp);
+ return;
+
+ error:
+ dev_kfree_skb(skb);
+ lp->stats.tx_errors++;
+
}
+
/*
* Helper function for isdn_net_start_xmit.
* When called, the connection is already established.
@@ -1397,9 +1519,18 @@ int isdn_net_send_skb
*/
static int
-isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
+isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
{
- int ret;
+ isdn_net_dev *nd;
+ isdn_net_local *slp;
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ int retv = 0;
+
+ if (((isdn_net_local *) (ndev->priv))->master) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ dev_kfree_skb(skb);
+ return 0;
+ }
/* For the other encaps the header has already been built */
#ifdef CONFIG_ISDN_PPP
@@ -1407,31 +1538,27 @@ isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
return isdn_ppp_xmit(skb, ndev);
}
#endif
+
+ nd = ((isdn_net_local *) ndev->priv)->netdev;
+
+ lp = isdn_net_get_locked_lp(nd);
+ if (!lp) {
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name);
+ return 1;
+ }
+ /* we have our lp locked from now on */
+
/* Reset hangup-timeout */
- lp->huptimer = 0;
+ lp->huptimer = 0; // FIXME?
+ isdn_net_writebuf_skb(lp, skb);
+ spin_unlock_bh(&lp->xmit_lock);
+
+ /* the following stuff is here for backwards compatibility.
+ * in future, start-up and hangup of slaves (based on current load)
+ * should move to userspace and get based on an overall cps
+ * calculation
+ */
if (lp->cps > lp->triggercps) {
- /* Device overloaded */
-
- /*
- * Packet-delivery via round-robin over master
- * and all connected slaves.
- */
- if (lp->master)
- /* Slaves always deliver themselves */
- ret = isdn_net_send_skb(ndev, lp, skb);
- else {
- isdn_net_local *slp = (isdn_net_local *) (lp->srobin->priv);
- /* Master delivers via srobin and maintains srobin */
- if (lp->srobin == ndev)
- ret = isdn_net_send_skb(ndev, lp, skb);
- else
- ret = isdn_net_start_xmit(skb, lp->srobin);
- lp->srobin = (slp->slave) ? slp->slave : ndev;
- slp = (isdn_net_local *) (lp->srobin->priv);
- if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
- lp->srobin = ndev;
- }
- /* Slave-startup using delay-variable */
if (lp->slave) {
if (!lp->sqfull) {
/* First time overload: set timestamp only */
@@ -1439,17 +1566,24 @@ isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
lp->sqfull_stamp = jiffies;
} else {
/* subsequent overload: if slavedelay exceeded, start dialing */
- if ((jiffies - lp->sqfull_stamp) > lp->slavedelay)
- isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+ if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) {
+ slp = lp->slave->priv;
+ if (!(slp->flags & ISDN_NET_CONNECTED)) {
+ isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+ }
+ }
}
}
} else {
- /* Not overloaded, deliver locally */
- ret = isdn_net_send_skb(ndev, lp, skb);
- if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ))))
+ if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) {
lp->sqfull = 0;
+ }
+ /* this is a hack to allow auto-hangup for slaves on moderate loads */
+ nd->queue = nd->local;
}
- return ret;
+
+ return retv;
+
}
static void
@@ -1489,7 +1623,7 @@ void isdn_net_tx_timeout(struct net_device * ndev)
* actually, this may not matter at all, because ISDN hardware
* should not see transmitter hangs at all IMO
* changed KERN_DEBUG to KERN_WARNING to find out if this is
- * ever called
+ * ever called --KG
*/
}
ndev->trans_start = jiffies;
@@ -1608,19 +1742,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return 1; /* let upper layer requeue skb packet */
}
#endif
- /* remember first skb to speed up arp
- * when using encap ETHER
- */
- if (lp->first_skb) {
- printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
- dev_kfree_skb(lp->first_skb);
- lp->first_skb = NULL;
- }
- lp->first_skb = skb;
/* Initiate dialing */
restore_flags(flags);
isdn_net_dial();
- return 0;
+ isdn_net_device_stop_queue(lp);
+ return 1;
} else {
isdn_net_unreachable(ndev, skb,
"No phone number");
@@ -1633,14 +1759,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (!lp->dialstate) {
/* ISDN connection is established, try sending */
int ret;
- if (lp->first_skb) {
- if (isdn_net_xmit(ndev, lp, lp->first_skb)){
- netif_stop_queue(ndev);
- return 1;
-}
- lp->first_skb = NULL;
- }
- ret = (isdn_net_xmit(ndev, lp, skb));
+ ret = (isdn_net_xmit(ndev, skb));
if(ret) netif_stop_queue(ndev);
return ret;
} else
@@ -1754,7 +1873,6 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC);
unsigned long t = (jiffies / HZ * 1000000);
- int len;
cisco_hdr *ch;
cisco_slarp *s;
@@ -1782,9 +1900,7 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
s->rel = 0xffff;
s->t1 = t >> 16;
s->t0 = t & 0xffff;
- len = skb->len;
- if (isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 0, skb) != len)
- dev_kfree_skb(skb);
+ isdn_net_write_super(lp, skb);
}
static void
@@ -2417,7 +2533,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
* Is the interface up?
* If not, reject the call actively.
*/
- if (!isdn_net_started(p)) {
+ if (!isdn_net_device_started(p)) {
restore_flags(flags);
printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
lp->name);
@@ -2508,6 +2624,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
#endif
+ isdn_net_lp_disconnected(lp);
isdn_free_channel(lp->isdn_device, lp->isdn_channel,
ISDN_USAGE_NET);
}
@@ -2707,10 +2824,17 @@ isdn_net_new(char *name, struct net_device *master)
netdev->ib.last = NULL;
#endif
netdev->queue = netdev->local;
+ spin_lock_init(&netdev->queue_lock);
+
netdev->local->last = netdev->local;
netdev->local->netdev = netdev;
netdev->local->next = netdev->local;
+ memset(&netdev->local->tqueue, 0, sizeof(struct tq_struct));
+ netdev->local->tqueue.routine = isdn_net_softint;
+ netdev->local->tqueue.data = netdev->local;
+ spin_lock_init(&netdev->local->xmit_lock);
+
netdev->local->isdn_device = -1;
netdev->local->isdn_channel = -1;
netdev->local->pre_device = -1;
@@ -2718,13 +2842,11 @@ isdn_net_new(char *name, struct net_device *master)
netdev->local->exclusive = -1;
netdev->local->ppp_slot = -1;
netdev->local->pppbind = -1;
- netdev->local->sav_skb = NULL;
- netdev->local->first_skb = NULL;
+ skb_queue_head_init(&netdev->local->super_tx_queue);
netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
netdev->local->triggercps = 6000;
netdev->local->slavedelay = 10 * HZ;
- netdev->local->srobin = &netdev->dev;
netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
netdev->local->onhtime = 10; /* Default hangup-time for saving costs
of those who forget configuring this */
@@ -2762,7 +2884,7 @@ isdn_net_newslave(char *parm)
if (n->local->master)
return NULL;
/* Master must not be started yet */
- if (isdn_net_started(n))
+ if (isdn_net_device_started(n))
return NULL;
return (isdn_net_new(newname, &(n->dev)));
}
@@ -2805,7 +2927,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = p -> cprot;
#endif
- if (isdn_net_started(p)) {
+ if (isdn_net_device_started(p)) {
printk(KERN_WARNING "%s: cannot change encap when if is up\n",
lp->name);
return -EBUSY;
@@ -3066,8 +3188,6 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
isdn_net_dev *p = isdn_net_findif(phone->name);
isdn_net_phone *n;
- if (isdn_net_checkwild(phone->phone) && (phone->outgoing & 1))
- return -EINVAL;
if (p) {
if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
return -ENOMEM;
@@ -3240,7 +3360,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
save_flags(flags);
cli();
- if (isdn_net_started(p)) {
+ if (isdn_net_device_started(p)) {
restore_flags(flags);
return -EBUSY;
}
diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h
index bd48c592c..5012ea772 100644
--- a/drivers/isdn/isdn_net.h
+++ b/drivers/isdn/isdn_net.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.10 1999/08/22 20:26:06 calle Exp $
+/* $Id: isdn_net.h,v 1.16 2000/03/21 23:53:22 kai Exp $
* header for Linux ISDN subsystem, network related functions (linklevel).
*
@@ -21,6 +21,26 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.h,v $
+ * Revision 1.16 2000/03/21 23:53:22 kai
+ * fix backwards compatibility
+ *
+ * Revision 1.15 2000/03/19 15:27:53 kai
+ * no known bugs left...
+ *
+ * Revision 1.14 2000/03/18 16:20:25 kai
+ * cosmetics / renaming
+ *
+ * Revision 1.13 2000/03/17 18:20:46 kai
+ * moved to frame_cnt based flow control
+ * some races still need to be fixed
+ *
+ * Revision 1.12 2000/03/17 17:01:00 kai
+ * cleanup
+ *
+ * Revision 1.11 2000/03/17 16:22:55 kai
+ * we keep track of outstanding packets (given to HL, but not confirmed yet)
+ * now, but we don't use it for flow control yet.
+ *
* Revision 1.10 1999/08/22 20:26:06 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -124,8 +144,88 @@ extern void isdn_net_autohup(void);
extern int isdn_net_force_hangup(char *);
extern int isdn_net_force_dial(char *);
extern isdn_net_dev *isdn_net_findif(char *);
-extern int isdn_net_send_skb(struct net_device *, isdn_net_local *,
- struct sk_buff *);
extern int isdn_net_rcv_skb(int, struct sk_buff *);
extern void isdn_net_slarp_out(void);
extern int isdn_net_dial_req(isdn_net_local *);
+extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
+extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
+
+#define ISDN_NET_MAX_QUEUE_LENGTH 2
+
+/*
+ * is this particular channel busy?
+ */
+static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
+{
+ if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * For the given net device, this will get a non-busy channel out of the
+ * corresponding bundle. The returned channel is locked.
+ */
+static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
+{
+ unsigned long flags;
+ isdn_net_local *lp;
+
+ spin_lock_irqsave(&nd->queue_lock, flags);
+ lp = nd->queue; /* get lp on top of queue */
+ spin_lock_bh(&nd->queue->xmit_lock);
+ while (isdn_net_lp_busy(nd->queue)) {
+ spin_unlock_bh(&nd->queue->xmit_lock);
+ nd->queue = nd->queue->next;
+ if (nd->queue == lp) /* not found -- should never happen */
+ return 0;
+ spin_lock_bh(&nd->queue->xmit_lock);
+ }
+ lp = nd->queue;
+
+ nd->queue = nd->queue->next;
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+ return lp;
+}
+
+/*
+ * add a channel to a bundle
+ */
+static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
+{
+ isdn_net_local *lp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nd->queue_lock, flags);
+
+ lp = nd->queue;
+ nlp->last = lp->last;
+ lp->last->next = nlp;
+ lp->last = nlp;
+ nlp->next = lp;
+ nd->queue = nlp;
+
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+}
+/*
+ * remove a channel from the bundle it belongs to
+ */
+static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
+{
+ isdn_net_local *master_lp = lp;
+ unsigned long flags;
+
+ if (lp->master)
+ master_lp = (isdn_net_local *) lp->master->priv;
+
+ spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
+ lp->last->next = lp->next;
+ lp->next->last = lp->last;
+ if (master_lp->netdev->queue == lp)
+ master_lp->netdev->queue = lp->next;
+ lp->next = lp->last = lp; /* (re)set own pointers */
+ spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+}
+
+
diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c
index 2551dc344..8a3ccce5f 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.62 2000/02/12 19:26:55 kai Exp $
+/* $Id: isdn_ppp.c,v 1.69 2000/03/19 15:27:53 kai Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.69 2000/03/19 15:27:53 kai
+ * no known bugs left...
+ *
+ * Revision 1.67 2000/03/17 18:20:46 kai
+ * moved to frame_cnt based flow control
+ * some races still need to be fixed
+ *
+ * Revision 1.66 2000/03/17 17:01:00 kai
+ * cleanup
+ *
+ * Revision 1.65 2000/03/17 16:22:55 kai
+ * we keep track of outstanding packets (given to HL, but not confirmed yet)
+ * now, but we don't use it for flow control yet.
+ *
+ * Revision 1.64 2000/03/17 10:43:56 kai
+ * 2.3.99 contains MPPP constants which cause a warning because we
+ * redefine them in include/linux/isdn_ppp.h
+ *
+ * So from now on we use the generic PPP constants, change is backwards
+ * compatible, though
+ *
+ * Revision 1.63 2000/03/16 15:46:37 kai
+ * a little bugfix and cosmetic changes
+ *
* Revision 1.62 2000/02/12 19:26:55 kai
* adopted to latest 2.3 softnet changes.
*
@@ -263,10 +287,6 @@
*
*/
-/* TODO: right tbusy handling when using MP */
-
-#define CONFIG_ISDN_CCP 1
-
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@@ -331,7 +351,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
static void isdn_ppp_free_mpqueue(isdn_net_dev *);
#endif
-char *isdn_ppp_revision = "$Revision: 1.62 $";
+char *isdn_ppp_revision = "$Revision: 1.69 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
@@ -366,36 +386,28 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
int
isdn_ppp_free(isdn_net_local * lp)
{
-#ifdef CONFIG_ISDN_MPP
isdn_net_local *master_lp = lp;
-#endif
unsigned long flags;
struct ippp_struct *is;
if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
return 0;
- is = ippp_table[lp->ppp_slot];
-
save_flags(flags);
cli();
+
#ifdef CONFIG_ISDN_MPP
- if (lp->master)
- master_lp = (isdn_net_local *) lp->master->priv;
-
- lp->last->next = lp->next;
- lp->next->last = lp->last;
- if (master_lp->netdev->queue == lp) {
- master_lp->netdev->queue = lp->next;
- if (lp->next == lp) { /* last link in queue? */
- master_lp->netdev->ib.bundled = 0;
- isdn_ppp_free_mpqueue(master_lp->netdev);
- isdn_ppp_free_sqqueue(master_lp->netdev);
- }
+ if (lp->next == lp) { /* last link in queue? */
+ master_lp->netdev->ib.bundled = 0;
+ isdn_ppp_free_mpqueue(master_lp->netdev);
+ isdn_ppp_free_sqqueue(master_lp->netdev);
}
- lp->next = lp->last = lp; /* (re)set own pointers */
#endif
+ isdn_net_rm_from_bundle(lp);
+
+ is = ippp_table[lp->ppp_slot];
+
if ((is->state & IPPP_CONNECT))
isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
else if (is->state & IPPP_ASSIGNED)
@@ -406,6 +418,7 @@ isdn_ppp_free(isdn_net_local * lp)
is->lp = NULL; /* link is down .. set lp to NULL */
lp->ppp_slot = -1; /* is this OK ?? */
+
restore_flags(flags);
return 0;
@@ -422,9 +435,6 @@ isdn_ppp_bind(isdn_net_local * lp)
long flags;
struct ippp_struct *is;
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- return -1;
-
save_flags(flags);
cli();
@@ -1030,8 +1040,6 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
unsigned short hl;
- unsigned long flags;
- int cnt;
struct sk_buff *skb;
/*
* we need to reserve enought space in front of
@@ -1054,17 +1062,7 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
- save_flags(flags);
- cli();
- if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
- } else
- printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count);
- lp->sav_skb = skb;
- }
- restore_flags(flags);
+ isdn_net_write_super(lp, skb);
}
}
return count;
@@ -1162,7 +1160,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
int sqno_end;
if(is->compflags & SC_LINK_DECOMP_ON) {
- if(proto == PPP_LINK_COMP) {
+ if(proto == PPP_COMPFRAG) {
if(is->debug & 0x10)
printk(KERN_DEBUG "received single link compressed frame\n");
skb = isdn_ppp_decompress(skb,is,NULL,proto);
@@ -1425,7 +1423,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
#endif
break;
case PPP_CCP:
- case PPP_LINK_CCP:
+ case PPP_CCPFRAG:
isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
/* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */
@@ -1484,19 +1482,13 @@ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
int
isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
{
- struct net_device *mdev = ((isdn_net_local *) (netdev->priv))->master; /* get master (for redundancy) */
isdn_net_local *lp,*mlp;
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
- unsigned long flags;
- if (mdev)
- mlp = (isdn_net_local *) (mdev->priv);
- else {
- mdev = netdev;
- mlp = (isdn_net_local *) (netdev->priv);
- }
+ mlp = (isdn_net_local *) (netdev->priv);
+
nd = mlp->netdev; /* get master lp */
ipts = ippp_table[mlp->ppp_slot];
@@ -1515,21 +1507,18 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
break;
default:
dev_kfree_skb(skb);
- printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol);
+ printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
+ skb->protocol);
return 0;
}
- lp = nd->queue; /* get lp on top of queue */
-
- if (lp->sav_skb) { /* find a non-busy device */
- isdn_net_local *nlp = lp->next;
- while (lp->sav_skb) {
- if (lp == nlp)
- return 1;
- nlp = nd->queue = nd->queue->next;
- }
- lp = nlp;
+ lp = isdn_net_get_locked_lp(nd);
+ if (!lp) {
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name);
+ return 1;
}
+ /* we have our lp locked from now on */
+
ipt = ippp_table[lp->ppp_slot];
lp->huptimer = 0;
@@ -1538,8 +1527,8 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
*/
/* Pull off the fake header we stuck on earlier to keep
- * the fragemntation code happy.
- */
+ * the fragmentation code happy.
+ */
skb_pull(skb,IPPP_MAX_HEADER);
if (ipt->debug & 0x4)
@@ -1612,11 +1601,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
/* we get mp_seqno from static isdn_net_local */
long mp_seqno = ipts->mp_seqno;
ipts->mp_seqno++;
- nd->queue = nd->queue->next;
if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
unsigned char *data = isdn_ppp_skb_push(&skb, 3);
if(!data)
- return 0;
+ goto unlock;
mp_seqno &= 0xfff;
data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
data[1] = mp_seqno & 0xff;
@@ -1624,7 +1612,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
} else {
unsigned char *data = isdn_ppp_skb_push(&skb, 5);
if(!data)
- return 0;
+ goto unlock;
data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
data[2] = (mp_seqno >> 8) & 0xff;
@@ -1644,20 +1632,20 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
unsigned char *data = isdn_ppp_skb_push(&skb,1);
if(!data)
- return 0;
+ goto unlock;
data[0] = proto & 0xff;
}
else {
unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data)
- return 0;
+ goto unlock;
data[0] = (proto >> 8) & 0xff;
data[1] = proto & 0xff;
}
if(!(ipt->pppcfg & SC_COMP_AC)) {
unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data)
- return 0;
+ goto unlock;
data[0] = 0xff; /* All Stations */
data[1] = 0x03; /* Unnumbered information */
}
@@ -1668,16 +1656,11 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
}
- save_flags(flags);
- cli();
- if (isdn_net_send_skb(netdev, lp, skb)) {
- if (lp->sav_skb) { /* should never happen as sav_skb are sent with disabled IRQs) */
- printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name);
- dev_kfree_skb(skb);
- } else
- lp->sav_skb = skb;
- }
- restore_flags(flags);
+
+ isdn_net_writebuf_skb(lp, skb);
+
+ unlock:
+ spin_unlock_bh(&lp->xmit_lock);
return 0;
}
@@ -1731,28 +1714,21 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
char ifn[IFNAMSIZ + 1];
long flags;
isdn_net_dev *p;
- isdn_net_local *lp,
- *nlp;
+ isdn_net_local *lp, *nlp;
sprintf(ifn, "ippp%d", unit);
p = isdn_net_findif(ifn);
if (!p)
return -1;
- isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */
-
save_flags(flags);
cli();
+ isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */
nlp = is->lp;
-
lp = p->queue;
+ isdn_net_add_to_bundle(p, nlp);
p->ib.bundled = 1;
- nlp->last = lp->last;
- lp->last->next = nlp;
- lp->last = nlp;
- nlp->next = lp;
- p->queue = nlp;
ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
/* maybe also SC_CCP stuff */
@@ -1761,7 +1737,6 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
-
restore_flags(flags);
return 0;
}
@@ -1949,12 +1924,14 @@ isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
#ifdef CONFIG_ISDN_PPP_VJ
int toss = 0;
#endif
-/* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
- eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
- wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
- bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete
- groesser als mrru ist: raus damit , Pakete muessen allerdings zusammenhaengen sonst koennte
- ja ein Paket mit B und eins mit E dazwischenpassen */
+ /* currently we just discard ancient packets.
+ To do:
+ Maybe, as long as there's no B-packet in front and sqno <= min_sqno: discard.
+ If sqno < min_sqno and there are gaps: discard (the gaps won't be filled anyway).
+ Packets with sqno > min_sqno: Larger than mp_mrru: If sum of all pktlen of pending
+ packets large than mrru: discard - packets need to be consecutive, though, if not
+ there could be an B and an E-packet in between.
+ */
struct mpqueue *ql,
*q = dev->mp_last;
@@ -2249,8 +2226,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
{
struct sk_buff *skb;
unsigned char *p;
- int count, hl;
- unsigned long flags;
+ int hl;
int cnt = 0;
isdn_net_local *lp = is->lp;
@@ -2291,26 +2267,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
printk(KERN_DEBUG "Sending CCP Frame:\n");
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
- /* Just ripped from isdn_ppp_write. Dunno whether it makes sense,
- especially dunno what the sav_skb stuff is good for. */
-
- count = skb->len;
- save_flags(flags);
- cli();
- if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel,
- 1, skb)) != count) {
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- printk(KERN_INFO
- "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",
- cnt, count);
- } else
- printk(KERN_INFO
- "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",
- cnt, count);
- lp->sav_skb = skb;
- }
- restore_flags(flags);
+ isdn_net_write_super(lp, skb);
}
/* Allocate the reset state vector */
@@ -2560,14 +2517,6 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
int proto)
{
-#ifndef CONFIG_ISDN_CCP
- if(proto == PPP_COMP || proto == PPP_LINK_COMP) {
- printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- return skb;
-#else
void *stat = NULL;
struct isdn_ppp_compressor *ipc = NULL;
struct sk_buff *skb_out;
@@ -2617,7 +2566,7 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc
printk(KERN_DEBUG "ippp: Decompress valid!\n");
*/
- if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) {
+ if((master && proto == PPP_COMP) || (!master && proto == PPP_COMPFRAG) ) {
/* Set up reset params for the decompressor */
memset(&rsparm, 0, sizeof(rsparm));
rsparm.data = rsdata;
@@ -2657,7 +2606,6 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc
ipc->incomp(stat,skb,proto);
return skb;
}
-#endif
}
/*
@@ -2676,13 +2624,9 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
void *stat;
struct sk_buff *skb_out;
-#ifdef CONFIG_ISDN_CCP
/* we do not compress control protocols */
if(*proto < 0 || *proto > 0x3fff) {
-#else
- {
-#endif
- return skb_in;
+ return skb_in;
}
if(type) { /* type=1 => Link compression */
@@ -2883,7 +2827,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
}
proto = ((int)data[0]<<8)+data[1];
- if(proto != PPP_CCP && proto != PPP_LINK_CCP)
+ if(proto != PPP_CCP && proto != PPP_CCPFRAG)
return;
printk(KERN_DEBUG "Received CCP frame from daemon:\n");
diff --git a/drivers/isdn/isdn_v110.c b/drivers/isdn/isdn_v110.c
index a3ac19caf..22863e208 100644
--- a/drivers/isdn/isdn_v110.c
+++ b/drivers/isdn/isdn_v110.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.3 1999/10/30 09:49:28 keil Exp $
+/* $Id: isdn_v110.c,v 1.4 2000/03/16 16:34:12 kai Exp $
* Linux ISDN subsystem, V.110 related functions (linklevel).
*
@@ -19,6 +19,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_v110.c,v $
+ * Revision 1.4 2000/03/16 16:34:12 kai
+ * some translation work
+ *
+ * there shouldn't be any German comments lurking around anymore ;-)
+ *
* Revision 1.3 1999/10/30 09:49:28 keil
* Reinit of v110 structs
*
@@ -39,14 +44,15 @@
#undef ISDN_V110_DEBUG
-char *isdn_v110_revision = "$Revision: 1.3 $";
+char *isdn_v110_revision = "$Revision: 1.4 $";
#define V110_38400 255
#define V110_19200 15
#define V110_9600 3
-/* Die folgenden Daten sind fertig kodierte Matrizen, jeweils
- als online und offline matrix für 9600, 19200 und 38400
+/*
+ * The following data are precoded matrices, online and offline matrix
+ * for 9600, 19200 und 38400, respectively
*/
static unsigned char V110_OnMatrix_9600[] =
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
@@ -74,13 +80,12 @@ static unsigned char V110_OnMatrix_38400[] =
static unsigned char V110_OffMatrix_38400[] =
{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
-
-/* FlipBits dreht die Reihenfolge von jeweils keylen bits in einem byte um.
- Aus der Bitreihenfolge 76543210 werden bei keylen=4 die bits 45670123,
- bei keylen=2 die bits 67452301. Dies ist notwendig, weil die reihenfolge
- auf der isdn-leitung falsch herum ist.
+/*
+ * FlipBits reorders sequences of keylen bits in one byte.
+ * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
+ * and to 67452301 when keylen = 2. This is necessary because ordering on
+ * the isdn line is the the other way.
*/
-
static __inline unsigned char
FlipBits(unsigned char c, int keylen)
{
@@ -164,8 +169,9 @@ isdn_v110_close(isdn_v110_stream * v)
}
-/* ValidHeaderBytes prüft, wieviele bytes in v->decodebuf gültig sind */
-
+/*
+ * ValidHeaderBytes return the number of valid bytes in v->decodebuf
+ */
static int
ValidHeaderBytes(isdn_v110_stream * v)
{
@@ -176,8 +182,9 @@ ValidHeaderBytes(isdn_v110_stream * v)
return i;
}
-/* SyncHeader schiebt den decodebuf pointer auf den nächsten gültigen header */
-
+/*
+ * SyncHeader moves the decodebuf ptr to the next valid header
+ */
static void
SyncHeader(isdn_v110_stream * v)
{
@@ -214,68 +221,60 @@ DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf
int dbit = v->dbit;
unsigned char b = v->b;
- while (line < len) { /* sind schon alle matrizenzeilen abgearbeitet? */
- if ((line % 10) == 0) { /* die 0. zeile der matrix ist immer null ! */
- if (m[line] != 0x00) { /* nicht 0 ? dann fehler! */
+ while (line < len) { /* Are we done with all lines of the matrix? */
+ if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
+ if (m[line] != 0x00) { /* not 0 ? -> error! */
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
+ /* returning now is not the right thing, though :-( */
#endif
-
-/*
- dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
- v->introducer = 0; v->dbit = 1; v->b = 0;
- return buflen; anzahl schon erzeugter daten zurückgeben!
- */
- }
- line++; /* sonst die nächste matrixzeile nehmen */
+ }
+ line++; /* next line of matrix */
continue;
- } else if ((line % 10) == 5) { /* in zeile 5 stehen nur e-bits ! */
- if ((m[line] & 0x70) != 0x30) { /* 011 muß am anfang stehen! */
+ } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
+ if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
+ /* returning now is not the right thing, though :-( */
#endif
-/* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
- v->introducer = 0; v->dbit = 1; v->b = 0;
- return buflen;
- */
}
- line++; /* alles klar, nächste zeile */
+ line++; /* next line */
continue;
} else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
- introducer = (m[line] & mbit) ? 0 : 1; /* aktuelles bit der matrix */
+ introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
next_byte:
- if (mbit > 2) { /* war es das letzte bit dieser matrixzeile ? */
- mbit >>= 1; /* nein, nimm das nächste in dieser zeile */
+ if (mbit > 2) { /* was it the last bit in this line ? */
+ mbit >>= 1; /* no -> take next */
continue;
- } /* sonst links in der nächsten zeile anfangen */
+ } /* otherwise start with leftmost bit in the next line */
mbit = 64;
line++;
continue;
- } else { /* sonst müssen wir ein datenbit setzen */
- if (m[line] & mbit) /* war das bit in der matrix gesetzt ? */
- b |= dbit; /* ja, dann setz es auch im datenbyte */
+ } else { /* otherwise we need to set a data bit */
+ if (m[line] & mbit) /* was that bit set in the matrix ? */
+ b |= dbit; /* yes -> set it in the data byte */
else
- b &= dbit - 1; /* nein, lösch bit im datenbyte */
- if (dbit < 128) /* haben wir schon ein ganzes byte voll ? */
- dbit <<= 1; /* nein, auf zum nächsten datenbit */
- else { /* ein ganzes datenbyte ist voll */
- buf[buflen++] = b; /* byte in den output buffer kopieren */
- introducer = b = 0; /* Init der Introsequenz und des datenbytes */
- dbit = 1; /* als nächstes suchen wir das nullte bit */
+ b &= dbit - 1; /* no -> clear it in the data byte */
+ if (dbit < 128) /* is that data byte done ? */
+ dbit <<= 1; /* no, got the next bit */
+ else { /* data byte is done */
+ buf[buflen++] = b; /* copy byte into the output buffer */
+ introducer = b = 0; /* init of the intro sequence and of the data byte */
+ dbit = 1; /* next we look for the 0th bit */
}
- goto next_byte; /* suche das nächste bit in der matrix */
+ goto next_byte; /* look for next bit in the matrix */
}
}
v->introducer = introducer;
v->dbit = dbit;
v->b = b;
- return buflen; /* return anzahl der bytes im output buffer */
+ return buflen; /* return number of bytes in the output buffer */
}
-/* DecodeStream erhält vom input stream V110 kodierte Daten, die zu den
- V110 frames zusammengepackt werden müssen. Die Daten können an diese
- Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne
- darauf achten zu müssen, das frames usw. eingehalten werden.
+/*
+ * DecodeStream receives V.110 coded data from the input stream. It recovers the
+ * original frames.
+ * The input stream doesn't need to be framed
*/
struct sk_buff *
isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
@@ -314,8 +313,8 @@ isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
dev_kfree_skb(skb);
return NULL; /* no, try later */
}
- if (ValidHeaderBytes(v) != v->nbytes) { /* ist es ein ungültiger header ? */
- SyncHeader(v); /* nein, such einen header */
+ if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
+ SyncHeader(v); /* no -> look for header */
goto ReSync;
}
len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
@@ -357,15 +356,15 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
int introducer = 3;
int ibit[] = {0, 1, 1};
- while ((i < len) && (line < mlen)) { /* solange noch input da ist */
- switch (line % 10) { /* in welcher matrixzeile sind wir ? */
+ while ((i < len) && (line < mlen)) { /* while we still have input data */
+ switch (line % 10) { /* in which line of the matrix are we? */
case 0:
- m[line++] = 0x00; /* zeile 0 ist immer 0 */
- mbit = 128; /* und es geht mit dem 7. bit weiter */
+ m[line++] = 0x00; /* line 0 is always 0 */
+ mbit = 128; /* go on with the 7th bit */
break;
case 5:
- m[line++] = 0xbf; /* zeile 5 ist immer 10111111 */
- mbit = 128; /* und es geht mit dem 7. bit weiter */
+ m[line++] = 0xbf; /* line 5 is always 10111111 */
+ mbit = 128; /* go on with the 7th bit */
break;
}
if (line >= mlen) {
@@ -373,41 +372,41 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
return line;
}
next_bit:
- switch (mbit) { /* ganz linkes oder rechtes bit ? */
+ switch (mbit) { /* leftmost or rightmost bit ? */
case 1:
- line++; /* ganz rechts ! dann in die nächste */
+ line++; /* rightmost -> go to next line */
if (line >= mlen) {
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
return line;
}
case 128:
- m[line] = 128; /* ganz links byte auf 1000000 setzen */
- mbit = 64; /* aktuelles bit in der matrixzeile */
+ m[line] = 128; /* leftmost -> set byte to 1000000 */
+ mbit = 64; /* current bit in the matrix line */
continue;
}
- if (introducer) { /* 110 sequenz setzen ? */
- introducer--; /* ein digit weniger setzen */
- m[line] |= ibit[introducer] ? mbit : 0; /* entsprechendes bit setzen */
- mbit >>= 1; /* bit der matrixzeile >> 1 */
- goto next_bit; /* und dort weiter machen */
- } /* else datenbits in die matrix packen! */
- m[line] |= (buf[i] & dbit) ? mbit : 0; /* datenbit in matrix setzen */
- if (dbit == 128) { /* war es das letzte datenbit ? */
- dbit = 1; /* dann mach beim nächsten weiter */
- i++; /* nächste datenbyte des input buffers */
- if (i < len) /* war es schon das letzte ? */
- introducer = 3; /* nein, schreib den introducer 110 */
- else { /* war das letzte datenbyte ! */
- m[line] |= (mbit - 1) & 0xfe; /* setz restliche bits der zeile auf 1 */
+ if (introducer) { /* set 110 sequence ? */
+ introducer--; /* set on digit less */
+ m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
+ mbit >>= 1; /* bit of matrix line >> 1 */
+ goto next_bit; /* and go on there */
+ } /* else push data bits into the matrix! */
+ m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
+ if (dbit == 128) { /* was it the last one? */
+ dbit = 1; /* then go on with first bit of */
+ i++; /* next byte in input buffer */
+ if (i < len) /* input buffer done ? */
+ introducer = 3; /* no, write introducer 110 */
+ else { /* input buffer done ! */
+ m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
break;
}
- } else /* nicht das letzte datenbit */
- dbit <<= 1; /* dann gehe zum nächsten datenbit */
- mbit >>= 1; /* und setz bit der matrix weiter */
+ } else /* not the last data bit */
+ dbit <<= 1; /* then go to next data bit */
+ mbit >>= 1; /* go to next bit of matrix */
goto next_bit;
}
- /* evtl. noch restliche zeilen in der matrix generieren... */
+ /* if necessary, generate remaining lines of the matrix... */
if ((line) && ((line + 10) < mlen))
switch (++line % 10) {
case 1:
@@ -429,7 +428,7 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
case 9:
m[line++] = 0xfe;
}
- return line; /* soviele matrixzeilen sind es */
+ return line; /* that's how many lines we have */
}
/*
@@ -517,7 +516,7 @@ isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
return nskb;
}
mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
- /* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */
+ /* now distribute 2 or 4 bits each to the output stream! */
rbuf = skb_put(nskb, size);
olen = 0;
sval1 = 8 - v->nbits;
diff --git a/drivers/isdn/isdn_v110.h b/drivers/isdn/isdn_v110.h
index 4bb694849..de6f9f6e1 100644
--- a/drivers/isdn/isdn_v110.h
+++ b/drivers/isdn/isdn_v110.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.h,v 1.2 1999/10/30 09:49:28 keil Exp $
+/* $Id: isdn_v110.h,v 1.3 2000/03/16 16:34:12 kai Exp $
* Linux ISDN subsystem, V.110 related functions (linklevel).
*
@@ -19,6 +19,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_v110.h,v $
+ * Revision 1.3 2000/03/16 16:34:12 kai
+ * some translation work
+ *
+ * there shouldn't be any German comments lurking around anymore ;-)
+ *
* Revision 1.2 1999/10/30 09:49:28 keil
* Reinit of v110 structs
*
@@ -29,17 +34,14 @@
#ifndef _isdn_v110_h_
#define _isdn_v110_h_
-/* isdn_v110_encode erhält len Nettodaten in buf, kodiert diese und liefert
- das Ergebnis wieder in buf. Wieviele Bytes kodiert wurden wird als
- return zurück gegeben. Diese Daten können dann 1:1 auf die Leitung
- gegeben werden.
-*/
+/*
+ * isdn_v110_encode will take raw data and encode it using V.110
+ */
extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
-/* isdn_v110_decode erhält vom input stream V110 kodierte Daten, die zu den
- V110 frames zusammengepackt werden müssen. Die Daten können an diese
- Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne
- darauf achten zu müssen, das frames usw. eingehalten werden.
+/*
+ * isdn_v110_decode receives V.110 coded data from the stream and rebuilds
+ * frames from them. The source stream doesn't need to be framed.
*/
extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 08c92ace9..da4e4bfe4 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -310,9 +310,11 @@ int el3_probe(struct net_device *dev)
with "nopnp=1" before, does not harm if not. */
idev->deactivate(idev);
idev->activate(idev);
- if (!idev->resource[0].start || check_region(idev->resource[0].start,16))
+ if (!idev->resource[0].start || check_region(idev->resource[0].start, EL3_IO_EXTENT))
continue;
ioaddr = idev->resource[0].start;
+ if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509 PnP"))
+ return -EBUSY;
irq = idev->irq_resource[0].start;
if (el3_debug > 3)
printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n",
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index d8a5e12af..4aeee0a2e 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -490,7 +490,7 @@ static int corkscrew_scan(struct net_device *dev)
if (inw(ioaddr + Wn0EepromData) != 0x6d50)
continue;
}
- printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n",
+ printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
/* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr;
@@ -533,7 +533,7 @@ no_pnp:
if (inw(ioaddr + Wn0EepromData) != 0x6d50)
continue;
}
- printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n",
+ printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
irq = inw(ioaddr + 0x2002) & 15;
corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 31e8c79b8..ebaeb68ba 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -21,8 +21,6 @@
*/
-static char *version =
-"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -85,6 +83,9 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#define PCI_SUPPORT_VER2
#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
+static char *version __initdata =
+"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
MODULE_PARM(debug, "i");
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 6169eb742..336a66949 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1838,7 +1838,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev)
void *ioaddr = tp->mmio_addr;
u32 mc_filter[2]; /* Multicast hash filter */
int i, rx_mode;
- unsigned long flags;
+ unsigned long flags=0;
DPRINTK ("ENTER\n");
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 65246369c..9ce1cf4af 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -114,8 +114,8 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
static void set_multicast_list(struct net_device *dev);
static void do_set_multicast_list(struct net_device *dev);
-/*
- * SMP and the 8390 setup.
+/**
+ * DOC: SMP and the 8390 setup.
*
* The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
* a page register that controls bank and packet buffer access. We guard
@@ -142,10 +142,14 @@ static void do_set_multicast_list(struct net_device *dev);
-/* Open/initialize the board. This routine goes all-out, setting everything
- up anew at each open, even though many of these registers should only
- need to be set once at boot.
- */
+/**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+ *
+ * This routine goes all-out, setting everything
+ * up anew at each open, even though many of these registers should only
+ * need to be set once at boot.
+ */
int ei_open(struct net_device *dev)
{
unsigned long flags;
@@ -173,7 +177,12 @@ int ei_open(struct net_device *dev)
return 0;
}
-/* Opposite of above. Only used when "ifconfig <devname> down" is done. */
+/**
+ * ei_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ei_open. Only used when "ifconfig <devname> down" is done.
+ */
int ei_close(struct net_device *dev)
{
struct ei_device *ei_local = (struct ei_device *) dev->priv;
@@ -190,6 +199,14 @@ int ei_close(struct net_device *dev)
return 0;
}
+/**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+ * @dev: network device to which packet is sent
+ *
+ * Sends a packet to an 8390 network device.
+ */
+
static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
long e8390_base = dev->base_addr;
@@ -389,8 +406,15 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-/* The typical workload of the driver:
- Handle the ether interface interrupts. */
+/**
+ * ei_interrupt -
+ * @irq:
+ * @dev_id:
+ * @regs:
+ *
+ * The typical workload of the driver:
+ * Handle the ether interface interrupts.
+ */
void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
@@ -492,7 +516,10 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
return;
}
-/*
+/**
+ * ei_tx_err - handle transmitter error
+ * @dev: network device which threw the exception
+ *
* A transmitter error has happened. Most likely excess collisions (which
* is a fairly normal condition). If the error is one where the Tx will
* have been aborted, we try and send another one right away, instead of
@@ -538,8 +565,13 @@ static void ei_tx_err(struct net_device *dev)
}
}
-/* We have finished a transmit: check for errors and then trigger the next
- packet to be sent. Called with lock held */
+/**
+ * ei_tx_intr - transmit interrupt handler
+ * @dev: network device for which tx intr is handled
+ *
+ * We have finished a transmit: check for errors and then trigger the next
+ * packet to be sent. Called with lock held
+ */
static void ei_tx_intr(struct net_device *dev)
{
@@ -625,8 +657,13 @@ static void ei_tx_intr(struct net_device *dev)
netif_wake_queue(dev);
}
-/* We have a good packet(s), get it/them out of the buffers.
- Called with lock held */
+/**
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+ * We have a good packet(s), get it/them out of the buffers.
+ * Called with lock held
+ */
static void ei_receive(struct net_device *dev)
{
@@ -751,7 +788,10 @@ static void ei_receive(struct net_device *dev)
return;
}
-/*
+/**
+ * ei_rx_overrun - handle receiver overrun
+ * @dev: network device which threw exception
+ *
* We have a receiver overrun: we have to kick the 8390 to get it started
* again. Problem is that you have to kick it exactly as NS prescribes in
* the updated datasheets, or "the NIC may act in an unpredictable manner."
@@ -900,7 +940,10 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev)
}
}
-/*
+/**
+ * do_set_multicast_list - set/clear multicast filter
+ * @dev: net device for which multicast filter is adjusted
+ *
* Set or clear the multicast filter for this adaptor. May be called
* from a BH in 2.1.x. Must be called with lock held.
*/
@@ -970,7 +1013,10 @@ static void set_multicast_list(struct net_device *dev)
spin_unlock_irqrestore(&ei_local->page_lock, flags);
}
-/*
+/**
+ * ethdev_init - init rest of 8390 device struct
+ * @dev: network device structure to init
+ *
* Initialize the rest of the 8390 device structure. Do NOT __init
* this, as it is used by 8390 based modular drivers too.
*/
@@ -1006,7 +1052,11 @@ int ethdev_init(struct net_device *dev)
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
-/*
+/**
+ * NS8390_init - initialize 8390 hardware
+ * @dev: network device to initialize
+ * @startp: boolean. non-zero value to initiate chip processing
+ *
* Must be called with lock held.
*/
@@ -1066,7 +1116,6 @@ void NS8390_init(struct net_device *dev, int startp)
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
do_set_multicast_list(dev); /* (re)load the mcast table */
}
- return;
}
/* Trigger a transmit start, assuming the length is valid.
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index b62986f83..057f2f704 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -124,9 +124,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
if [ "$CONFIG_NET_PCI" = "y" ]; then
tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
- fi
+ dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
fi
@@ -134,12 +132,12 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT
tristate ' CS89x0 support' CONFIG_CS89x0
tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
- tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
+ dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
fi
- tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100
+ dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then
bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM
@@ -147,7 +145,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
fi
- tristate ' PCI NE2000 support' CONFIG_NE2K_PCI
+ dep_tristate ' PCI NE2000 support' CONFIG_NE2K_PCI $CONFIG_PCI
# tristate ' Sundance Alta support' CONFIG_ALTA
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129
@@ -166,7 +164,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
bool ' Pocket and portable adapters' CONFIG_NET_POCKET
if [ "$CONFIG_NET_POCKET" = "y" ]; then
- tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+ if [ "$CONFIG_X86" = "y" ]; then
+ tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+ fi
tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600
tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620
fi
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index b3851ef09..91aeaced9 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3495,6 +3495,6 @@ void dfx_xmt_flush(
/*
* Local variables:
- * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 -c defxx.c"
+ * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c"
* End:
*/
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index f855d1978..2832775ae 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1099,6 +1099,12 @@ static int __devinit epic100_init_one (struct pci_dev *pdev,
struct net_device *dev;
long ioaddr;
static int card_idx = -1;
+ static int printed_version = 0;
+
+ if (!printed_version) {
+ printk (KERN_INFO "%s", version);
+ printed_version = 1;
+ }
chip_idx = ent->driver_data;
@@ -1280,13 +1286,7 @@ static struct pci_driver epic100_driver = {
static int __init epic100_init (void)
{
- printk (KERN_INFO "%s", version);
-
- if (pci_register_driver (&epic100_driver) > 0)
- return 0;
-
- pci_unregister_driver (&epic100_driver);
- return -ENODEV;
+ return pci_module_init (&epic100_driver);
}
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index bf001d83d..03944f066 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -941,10 +941,14 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_task_execute(self, __irport_change_speed, NULL, NULL,
(void *) irq->ifr_baudrate);
break;
case SIOCSDONGLE: /* Set dongle */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
/* Initialize dongle */
dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
if (!dongle)
@@ -965,12 +969,16 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
NULL);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
irq->ifr_receiving = irport_is_receiving(self);
break;
case SIOCSDTRRTS:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
break;
default:
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index 931ae9c4c..1fd3acda9 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
- * Modified at: Fri Jan 14 21:02:27 2000
+ * Modified at: Sat Mar 11 07:43:30 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -962,10 +962,14 @@ static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_task_execute(self, irtty_change_speed, NULL, NULL,
(void *) irq->ifr_baudrate);
break;
case SIOCSDONGLE: /* Set dongle */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
/* Initialize dongle */
dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
if (!dongle)
@@ -986,15 +990,21 @@ static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
NULL);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
irq->ifr_receiving = irtty_is_receiving(self);
break;
case SIOCSDTRRTS:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
break;
case SIOCSMODE:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irtty_set_mode(dev, irq->ifr_mode);
break;
default:
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 2dd149bf1..df9c63621 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1947,9 +1947,13 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
nsc_ircc_change_speed(self, irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
index 951b08d8f..387208e2f 100644
--- a/drivers/net/irda/toshoboe.c
+++ b/drivers/net/irda/toshoboe.c
@@ -603,11 +603,15 @@ static int toshoboe_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
/* toshoboe_setbaud(self, irq->ifr_baudrate); */
/* Just change speed once - inserted by Paul Bristow */
self->new_speed = irq->ifr_baudrate;
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 239120e51..2456e012d 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -1332,9 +1332,13 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
w83977af_change_speed(self, irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index f6929905e..743812346 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -71,28 +71,55 @@ enum {
STOP_PG_0x60=0x100,
};
-/* This will eventually be converted to the standard PCI probe table. */
+
+enum ne2k_pci_chipsets {
+ CH_RealTek_RTL_8029 = 0,
+ CH_Winbond_89C940,
+ CH_Compex_RL2000,
+ CH_KTI_ET32P2,
+ CH_NetVin_NV5000SC,
+ CH_Via_86C926,
+ CH_SureCom_NE34,
+ CH_Winbond_W89C940F,
+ CH_Holtek_HT80232,
+ CH_Holtek_HT80229,
+};
+
static struct {
- unsigned short vendor, dev_id;
char *name;
int flags;
-}
-pci_clone_list[] __initdata = {
- {0x10ec, 0x8029, "RealTek RTL-8029", 0},
- {0x1050, 0x0940, "Winbond 89C940", 0},
- {0x11f6, 0x1401, "Compex RL2000", 0},
- {0x8e2e, 0x3000, "KTI ET32P2", 0},
- {0x4a14, 0x5000, "NetVin NV5000SC", 0},
- {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
- {0x10bd, 0x0e34, "SureCom NE34", 0},
- {0x1050, 0x5a5a, "Winbond W89C940F", 0},
- {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
- {0x12c3, 0x5598, "Holtek HT80229",
- ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
+} pci_clone_list[] __devinitdata = {
+ {"RealTek RTL-8029", 0},
+ {"Winbond 89C940", 0},
+ {"Compex RL2000", 0},
+ {"KTI ET32P2", 0},
+ {"NetVin NV5000SC", 0},
+ {"Via 86C926", ONLY_16BIT_IO},
+ {"SureCom NE34", 0},
+ {"Winbond W89C940F", 0},
+ {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
+ {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
{0,}
};
+
+static struct pci_device_id ne2k_pci_tbl[] __devinitdata = {
+ { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 },
+ { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 },
+ { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 },
+ { 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 },
+ { 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC },
+ { 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 },
+ { 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 },
+ { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F },
+ { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 },
+ { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl);
+
+
/* ---- No user-serviceable parts below ---- */
#define NE_BASE (dev->base_addr)
@@ -104,8 +131,6 @@ pci_clone_list[] __initdata = {
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
-static int ne2k_pci_probe(void);
-static struct net_device *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx);
static int ne2k_pci_open(struct net_device *dev);
static int ne2k_pci_close(struct net_device *dev);
@@ -122,47 +147,11 @@ static void ne2k_pci_block_output(struct net_device *dev, const int count,
/* No room in the standard 8390 structure for extra info we need. */
struct ne2k_pci_card {
- struct ne2k_pci_card *next;
struct net_device *dev;
struct pci_dev *pci_dev;
};
-/* A list of all installed devices, for removing the driver module. */
-static struct ne2k_pci_card *ne2k_card_list = NULL;
-static int __init ne2k_pci_init_module(void)
-{
- /* We must emit version information. */
- if (debug)
- printk(KERN_INFO "%s", version);
- if (ne2k_pci_probe()) {
- printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n");
- return -ENODEV;
- }
- lock_8390_module();
- return 0;
-}
-
-static void __exit ne2k_pci_cleanup_module(void)
-{
- struct net_device *dev;
- struct ne2k_pci_card *this_card;
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (ne2k_card_list) {
- dev = ne2k_card_list->dev;
- unregister_netdev(dev);
- release_region(dev->base_addr, NE_IO_EXTENT);
- kfree(dev);
- this_card = ne2k_card_list;
- ne2k_card_list = ne2k_card_list->next;
- kfree(this_card);
- }
- unlock_8390_module();
-}
-
-module_init(ne2k_pci_init_module);
-module_exit(ne2k_pci_cleanup_module);
/*
NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet
@@ -177,96 +166,42 @@ module_exit(ne2k_pci_cleanup_module);
in the 'dev' and 'ei_status' structures.
*/
-#ifdef HAVE_DEVLIST
-struct netdev_entry netcard_drv =
-{"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0};
-#endif
-static int __init ne2k_pci_probe(void)
+static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- struct pci_dev *pdev = NULL;
- int cards_found = 0;
- int i;
struct net_device *dev;
+ int i, irq, reg0, start_page, stop_page;
+ unsigned char SA_prom[32];
+ int chip_idx = ent->driver_data;
+ static unsigned version_printed = 0;
+ long ioaddr;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
- if ( ! pci_present())
+ ioaddr = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
+
+ if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
+ printk (KERN_ERR "ne2k-pci: no I/O resource at PCI BAR #0\n");
return -ENODEV;
-
- while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)) != NULL) {
- int pci_irq_line;
- u16 pci_command, new_command;
- unsigned long pci_ioaddr;
-
- /* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */
- for (i = 0; pci_clone_list[i].vendor != 0; i++)
- if (pci_clone_list[i].vendor == pdev->vendor
- && pci_clone_list[i].dev_id == pdev->device)
- break;
- if (pci_clone_list[i].vendor == 0)
- continue;
-
- pci_ioaddr = pdev->resource[0].start;
- pci_irq_line = pdev->irq;
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-
- /* Avoid already found cards from previous calls */
- if (check_region(pci_ioaddr, NE_IO_EXTENT))
- continue;
-
- {
- static unsigned version_printed = 0;
- if (version_printed++ == 0)
- printk(KERN_INFO "%s", version);
- }
-
- /* Activate the card: fix for brain-damaged Win98 BIOSes. */
- new_command = pci_command | PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled this"
- " NE2k clone! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
-#ifndef __sparc__
- if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS)
- printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k"
- " card to IRQ %d, which is unlikely to work!.\n"
- KERN_WARNING " You should use the PCI BIOS setup to assign"
- " a valid IRQ line.\n", pci_irq_line);
-#endif
- printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#lx, IRQ %d.\n",
- pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
- dev = ne2k_pci_probe1(pci_ioaddr, pci_irq_line, i);
- if (dev == 0) {
- /* Should not happen. */
- printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#lx failed.\n",
- pci_ioaddr);
- continue;
- } else {
- struct ne2k_pci_card *ne2k_card =
- kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL);
- ne2k_card->next = ne2k_card_list;
- ne2k_card_list = ne2k_card;
- ne2k_card->dev = dev;
- ne2k_card->pci_dev = pdev;
- }
-
- cards_found++;
}
-
- return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx)
-{
- struct net_device *dev;
- int i;
- unsigned char SA_prom[32];
- int start_page, stop_page;
- int reg0 = inb(ioaddr);
-
+
+ if (pci_enable_device (pdev)) {
+ printk (KERN_ERR "ne2k-pci: cannot enable device\n");
+ return -EIO;
+ }
+
+ if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
+ printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n",
+ NE_IO_EXTENT, ioaddr);
+ return -EBUSY;
+ }
+
+ reg0 = inb(ioaddr);
if (reg0 == 0xFF)
- return 0;
+ goto err_out_free_res;
/* Do a preliminary verification that we have a 8390. */
{
@@ -279,12 +214,16 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
if (inb(ioaddr + EN0_COUNTER0) != 0) {
outb(reg0, ioaddr);
outb(regd, ioaddr + 0x0d); /* Restore the old values. */
- return 0;
+ goto err_out_free_res;
}
}
dev = init_etherdev(NULL, 0);
-
+ if (!dev) {
+ printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n");
+ goto err_out_free_res;
+ }
+
/* Reset card. Who knows what dain-bramaged state it was left in. */
{
unsigned long reset_start_time = jiffies;
@@ -298,14 +237,15 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
/* Limit wait: '2' avoids jiffy roll-over. */
if (jiffies - reset_start_time > 2) {
printk("ne2k-pci: Card failure (no reset ack).\n");
- return 0;
+ goto err_out_free_netdev;
}
outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
}
if (load_8390_module("ne2k-pci.c")) {
- return 0;
+ printk (KERN_ERR "ne2k-pci: cannot load 8390 module\n");
+ goto err_out_free_netdev;
}
/* Read the 16 bytes of station address PROM.
@@ -355,12 +295,10 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
- printk ("%s: unable to get memory for dev->priv.\n", dev->name);
- return 0;
+ printk (KERN_ERR "%s: unable to get memory for dev->priv.\n", dev->name);
+ goto err_out_free_netdev;
}
- request_region(ioaddr, NE_IO_EXTENT, dev->name);
-
printk("%s: %s found at %#lx, IRQ %d, ",
dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
for(i = 0; i < 6; i++) {
@@ -387,16 +325,26 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
dev->open = &ne2k_pci_open;
dev->stop = &ne2k_pci_close;
NS8390_init(dev, 0);
- return dev;
+ return 0;
+
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+err_out_free_res:
+ release_region (ioaddr, NE_IO_EXTENT);
+ return -ENODEV;
+
}
static int
ne2k_pci_open(struct net_device *dev)
{
- if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev))
+ MOD_INC_USE_COUNT;
+ if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
return -EAGAIN;
+ }
ei_open(dev);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -589,6 +537,58 @@ ne2k_pci_block_output(struct net_device *dev, int count,
return;
}
+
+static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+
+ if (!dev) {
+ printk (KERN_ERR "bug! ne2k_pci_remove_one called w/o net_device\n");
+ return;
+ }
+
+ unregister_netdev (dev);
+ release_region (dev->base_addr, NE_IO_EXTENT);
+ kfree (dev);
+}
+
+
+static struct pci_driver ne2k_driver = {
+ name: "ne2k-pci",
+ probe: ne2k_pci_init_one,
+ remove: ne2k_pci_remove_one,
+ id_table: ne2k_pci_tbl,
+};
+
+
+static int __init ne2k_pci_init(void)
+{
+ int rc;
+
+ MOD_INC_USE_COUNT;
+ lock_8390_module();
+
+ rc = pci_module_init (&ne2k_driver);
+
+ /* XXX should this test CONFIG_HOTPLUG like pci_module_init? */
+ if (rc <= 0)
+ unlock_8390_module();
+
+ MOD_DEC_USE_COUNT;
+
+ return rc;
+}
+
+
+static void __exit ne2k_pci_cleanup(void)
+{
+ pci_unregister_driver (&ne2k_driver);
+ unlock_8390_module();
+}
+
+module_init(ne2k_pci_init);
+module_exit(ne2k_pci_cleanup);
+
/*
* Local variables:
diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c
index f2976e562..214341b53 100644
--- a/drivers/net/net_init.c
+++ b/drivers/net/net_init.c
@@ -1,4 +1,4 @@
-/* netdrv_init.c: Initialization for network devices. */
+/* net_init.c: Initialization for network devices. */
/*
Written 1993,1994,1995 by Donald Becker.
@@ -27,6 +27,8 @@
08/11/99 - Alan Cox: Got fed up of the mess in this file and cleaned it
up. We now share common code and have regularised name
allocation setups. Abolished the 16 card limits.
+ 03/19/2000 - jgarzik and Urban Widmark: init_etherdev 32-byte align
+
*/
#include <linux/config.h>
@@ -139,14 +141,22 @@ static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv, c
return dev;
}
-/* Fill in the fields of the device structure with ethernet-generic values.
-
- If no device structure is passed, a new one is constructed, complete with
- a SIZEOF_PRIVATE private data area.
-
- If an empty string area is passed as dev->name, or a new structure is made,
- a new name string is constructed. The passed string area should be 8 bytes
- long.
+/**
+ * init_etherdev - Register ethernet device
+ * @dev: An ethernet device structure to be filled in, or %NULL if a new
+ * struct should be allocated.
+ * @sizeof_priv: Size of additional driver-private structure to be allocated
+ * for this ethernet device
+ *
+ * Fill in the fields of the device structure with ethernet-generic values.
+ *
+ * If no device structure is passed, a new one is constructed, complete with
+ * a private data area of size @sizeof_priv. A 32-byte (not bit)
+ * alignment is enforced for this private data area.
+ *
+ * If an empty string area is passed as dev->name, or a new structure is made,
+ * a new name string is constructed. The passed string area should be 8 bytes
+ * long.
*/
struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv)
diff --git a/drivers/net/pcmcia/3c575_cb.c b/drivers/net/pcmcia/3c575_cb.c
index e98e1eda8..bff7bc9ed 100644
--- a/drivers/net/pcmcia/3c575_cb.c
+++ b/drivers/net/pcmcia/3c575_cb.c
@@ -12,10 +12,16 @@
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Linux Kernel Additions:
+
+ LK1.1.2 (March 19, 2000)
+ * New PCI interface (jgarzik)
+
*/
static char *version =
-"3c59x.c:v0.99L 5/28/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c575_cb.c:v0.99L+LK1.1.2 3/19/2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -64,6 +70,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -85,9 +92,6 @@ MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(compaq_ioaddr, "i");
-MODULE_PARM(compaq_irq, "i");
-MODULE_PARM(compaq_device_id, "i");
/* Operational parameter that usually are not changed. */
@@ -103,6 +107,10 @@ MODULE_PARM(compaq_device_id, "i");
code size of a per-interface flag is not worthwhile. */
static char mii_preamble_required = 0;
+#define PFX "3c575_cb: "
+
+
+
/*
Theory of Operation
@@ -186,76 +194,134 @@ enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, flags;
- int drv_flags, io_size;
- struct net_device *(*probe1)(struct pci_dev *pdev, struct net_device *dev,
- long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-static struct net_device *vortex_probe1(struct pci_dev *pdev,
- struct net_device *dev, long ioaddr,
- int irq, int dev_id, int card_idx);
-static struct pci_id_info pci_tbl[] = {
- {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3Com Vortex", 0x10B7, 0x5900, 0xff00,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
- {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
- {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c905C Tornado", 0x10B7, 0x9200, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3CCFE575CT Cyclone CardBus", 0x10B7, 0x5257, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3CCFEM656 Cyclone CardBus", 0x10B7, 0x6562, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+
+
+enum vortex_chips {
+ CH_3C590 = 0,
+ CH_3C595_1,
+ CH_3C595_2,
+ CH_3C595_3,
+ CH_VORTEX,
+ CH_3C900_1,
+ CH_3C900_2,
+ CH_3C900_3,
+ CH_3C900B_FL,
+ CH_3C905_1,
+ CH_3C905_2,
+ CH_3C905B_1,
+ CH_3C905B_2,
+ CH_3C905B_FX,
+ CH_3C905C,
+ CH_3C980,
+ CH_3CSOHO100_TX,
+ CH_3C555,
+ CH_3C575_1,
+ CH_3CCFE575,
+ CH_3CCFE575CT,
+ CH_3CCFE656,
+ CH_3CCFEM656,
+ CH_3C575_2,
+ CH_BOOMERANG,
+};
+
+
+/* note: this array directly indexed by above enums, and MUST
+ * be kept in sync with both the enums above, and the PCI device
+ * table below
+ */
+static struct vortex_chip_info {
+ const char *name;
+ int flags;
+ int drv_flags;
+ int io_size;
+} vortex_info_tbl[] = {
+ {"3c590 Vortex 10Mbps",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3c595 Vortex 100baseTx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3c595 Vortex 100baseT4",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3c595 Vortex 100base-MII",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3Com Vortex",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {"3c900 Boomerang 10baseT",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {"3c900 Boomerang 10Mbps Combo",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {"3c900 Cyclone 10Mbps Combo",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c900B-FL Cyclone 10base-FL",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c905 Boomerang 100baseTx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3c905 Boomerang 100baseT4",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3c905B Cyclone 100baseTx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ {"3c905B Cyclone 10/100/BNC",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ {"3c905B-FX Cyclone 100baseFx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c905C Tornado",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c980 Cyclone",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3cSOHO100-TX Hurricane",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c555 Laptop Hurricane",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c575 Boomerang CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3CCFE575 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3CCFE575CT Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3CCFE656 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3CCFEM656 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3c575 series CardBus (unknown version)",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3Com Boomerang (unknown version)",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {0,}, /* 0 terminated list. */
+};
+
+
+static struct pci_device_id vortex_pci_tbl[] __devinit = {
+ { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
+ { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 },
+ { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 },
+ { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 },
+ { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX },
+ { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 },
+ { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 },
+ { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
+ { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL },
+ { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 },
+ { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 },
+ { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 },
+ { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
+ { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
+ { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
+ { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
+ { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
+ { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
+ { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
+ { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
+ { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
+ { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
+ { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
+ { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_2 },
+ { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_BOOMERANG },
{0,}, /* 0 terminated list. */
};
+MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
+
/* Operational definitions.
These are not used by other compilation units and thus are not
@@ -400,7 +466,7 @@ struct vortex_private {
/* The addresses of transmit- and receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
struct sk_buff* tx_skbuff[TX_RING_SIZE];
- struct net_device *next_module;
+ struct net_device *next_module; /* NULL if PCI device */
void *priv_addr;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
@@ -463,9 +529,8 @@ static struct media_table {
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
-#ifndef CARDBUS
-static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[]);
-#endif
+static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq,
+ int chip_idx, int card_idx);
static void vortex_up(struct net_device *dev);
static void vortex_down(struct net_device *dev);
static int vortex_open(struct net_device *dev);
@@ -484,7 +549,6 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void vortex_tx_timeout(struct net_device *dev);
-static void acpi_wake(struct pci_dev *pdev);
static void acpi_set_WOL(struct net_device *dev);
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
@@ -492,280 +556,181 @@ static void acpi_set_WOL(struct net_device *dev);
#define MAX_UNITS 8
static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct net_device *root_vortex_dev = NULL;
-#ifdef MODULE
-#ifndef CARDBUS
-/* Variables to work-around the Compaq PCI BIOS32 problem. */
-static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-#endif
-#ifdef CARDBUS
+/* A list of all installed Vortex EISA devices, for removing the driver module. */
+static struct net_device *root_vortex_eisa_dev = NULL;
-#include <pcmcia/driver_ops.h>
+static int vortex_cards_found = 0;
-static void vortex_reap(void)
-{
- struct net_device **devp, **next;
- printk(KERN_DEBUG "vortex_reap()\n");
- for (devp = &root_vortex_dev; *devp; devp = next) {
- struct vortex_private *vp = (*devp)->priv;
- next = &vp->next_module;
- if (vp->open || !vp->reap) continue;
- unregister_netdev(*devp);
- if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
- kfree(*devp);
- kfree(vp->priv_addr);
- *devp = *next; next = devp;
- }
-}
-static dev_node_t *vortex_attach(dev_locator_t *loc)
-{
- u16 dev_id, vendor_id;
- u32 io;
- u8 irq;
- struct net_device *dev;
- int chip_idx;
- struct pci_dev *pdev;
- vortex_reap();
- if (loc->bus != LOC_PCI) return NULL;
- pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
- if (!pdev) return NULL;
- io = pci_resource_start (pdev, 0);
- irq = pdev->irq;
- vendor_id = pdev->vendor;
- dev_id = pdev->device;
- printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
- pdev->bus->number, pdev->devfn, dev_id);
- if (io == 0 || irq == 0) {
- printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
- "assigned an %s.\n" KERN_ERR " It will not be activated.\n",
- io == 0 ? "I/O address" : "IRQ");
- return NULL;
- }
- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor_id == pci_tbl[chip_idx].vendor_id
- && (dev_id & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */
- printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
- "vortex_attach().\n", vendor_id, dev_id);
- return NULL;
- }
- dev = vortex_probe1(pdev, NULL, io, irq, chip_idx, MAX_UNITS+1);
- if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
- node->major = node->minor = 0;
- node->next = NULL;
- MOD_INC_USE_COUNT;
- return node;
- }
- return NULL;
-}
-static void vortex_detach(dev_node_t *node)
+static void vortex_suspend (struct pci_dev *pdev)
{
- struct net_device *dev, *next;
- printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name);
- for (dev = root_vortex_dev; dev; dev = next) {
- next = ((struct vortex_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
- if (dev && dev->priv) {
- struct vortex_private *vp = dev->priv;
- if (vp->open) vortex_down(dev);
- vp->reap = 1;
- kfree(node);
- MOD_DEC_USE_COUNT;
- }
-}
+ struct net_device *dev = pdev->driver_data;
+
+ printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
-static void vortex_suspend(dev_node_t *node)
-{
- struct net_device *dev, *next;
- printk(KERN_DEBUG "vortex_suspend(%s)\n", node->dev_name);
- for (dev = root_vortex_dev; dev; dev = next) {
- next = ((struct vortex_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
if (dev && dev->priv) {
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- if (vp->open) vortex_down(dev);
+ if (vp->open) {
+ netif_device_detach(dev);
+ vortex_down(dev);
+ }
}
}
-static void vortex_resume(dev_node_t *node)
+
+static void vortex_resume (struct pci_dev *pdev)
{
- struct net_device *dev, *next;
- printk(KERN_DEBUG "vortex_resume(%s)\n", node->dev_name);
- for (dev = root_vortex_dev; dev; dev = next) {
- next = ((struct vortex_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
+ struct net_device *dev = pdev->driver_data;
+
+ printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name);
+
if (dev && dev->priv) {
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- if (vp->open) vortex_up(dev);
+ if (vp->open) {
+ vortex_up(dev);
+ netif_device_attach(dev);
+ }
}
}
-struct driver_operations vortex_ops = {
- "3c575_cb", vortex_attach, vortex_suspend, vortex_resume, vortex_detach
-};
-#endif /* Cardbus support */
-
-int init_module(void)
+/* returns count found (>= 0), or negative on error */
+static int __init vortex_eisa_init (void)
{
- if (vortex_debug)
- printk(KERN_INFO "%s", version);
-#ifdef CARDBUS
- register_driver(&vortex_ops);
- return 0;
-#else
- return vortex_scan(0, pci_tbl);
-#endif
-}
-
-#else
-int tc59x_probe(struct net_device *dev)
-{
- static int did_version = -1;
- if (++did_version <= 0)
- printk(KERN_INFO "%s", version);
- return vortex_scan(dev, pci_tbl);
-}
-#endif /* not MODULE */
-
-#ifndef CARDBUS
-static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[])
-{
- int cards_found = 0;
+ long ioaddr;
+ int rc;
+ int orig_cards_found = vortex_cards_found;
- /* Allow an EISA-only driver. */
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->base_address[0] & ~3;
- irq = pdev->irq;
- }
+ /* Now check all slots of the EISA bus. */
+ if (!EISA_bus)
+ return 0;
- if (ioaddr == 0) {
- printk(KERN_WARNING " A 3Com network adapter has been found, "
- "however it has not been assigned an I/O address.\n"
- " You may need to power-cycle the machine for this "
- "device to work!\n");
- continue;
- }
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+ int device_id;
- /* Activate the card. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled the device "
- "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",
- pci_bus, pci_device_fn, pci_command, new_command);
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
- }
+ if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
+ continue;
- dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq,
- chip_idx, cards_found);
-
- if (dev) {
- /* Get and check the latency values. On the 3c590 series
- the latency timer must be set to the maximum value to avoid
- data corruption that occurs when the timer expires during
- a transfer -- a bug in the Vortex chip only. */
- u8 pci_latency;
- u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
-
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < new_latency) {
- printk(KERN_INFO "%s: Overriding PCI latency"
- " timer (CFLT) setting of %d, new value is %d.\n",
- dev->name, pci_latency, new_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, new_latency);
- }
- dev = 0;
- cards_found++;
- }
+ /* Check the standard EISA ID register for an encoded '3Com'. */
+ if (inw(ioaddr + 0xC80) != 0x6d50) {
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+ continue;
}
- }
- /* Now check all slots of the EISA bus. */
- if (EISA_bus) {
- static long ioaddr = 0x1000;
- for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
- int device_id;
- if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
- continue;
- /* Check the standard EISA ID register for an encoded '3Com'. */
- if (inw(ioaddr + 0xC80) != 0x6d50)
- continue;
- /* Check for a product that we support, 3c59{2,7} any rev. */
- device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
- if ((device_id & 0xFF00) != 0x5900)
- continue;
- vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
- 4, cards_found);
- dev = 0;
- cards_found++;
+ /* Check for a product that we support, 3c59{2,7} any rev. */
+ device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
+ if ((device_id & 0xFF00) != 0x5900) {
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+ continue;
}
- }
-#ifdef MODULE
- /* Special code to work-around the Compaq PCI BIOS32 problem. */
- if (compaq_ioaddr) {
- vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,
- compaq_device_id, cards_found++);
- dev = 0;
+ rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
+ 4, /* XXX is 4 correct eisa idx? */
+ vortex_cards_found);
+ if (rc == 0)
+ vortex_cards_found++;
+ else
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
}
-#endif
- return cards_found ? 0 : -ENODEV;
+ return vortex_cards_found - orig_cards_found;
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int __devinit vortex_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+
+ rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq,
+ ent->driver_data, vortex_cards_found);
+ if (rc == 0)
+ vortex_cards_found++;
+
+ return rc;
}
-#endif /* ! Cardbus */
-static struct net_device *vortex_probe1(struct pci_dev *pdev,
- struct net_device *dev, long ioaddr,
- int irq, int chip_idx, int card_idx)
+
+/* NOTE: pdev can be NULL, for the case of an EISA driver */
+static int __devinit vortex_probe1(struct pci_dev *pdev,
+ long ioaddr, int irq,
+ int chip_idx, int card_idx)
{
struct vortex_private *vp;
int option;
unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
+ struct net_device *dev;
+ static int printed_version = 0;
+
+ if (!printed_version) {
+ printk (KERN_INFO "%s", version);
+ printed_version = 1;
+ }
- dev = init_etherdev(dev, 0);
-
- printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
- dev->name, pci_tbl[chip_idx].name, ioaddr);
-
+ dev = init_etherdev(NULL, sizeof(*vp));
+ if (!dev) {
+ printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
+ return -ENOMEM;
+ }
+
+ printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
+ dev->name,
+ pdev ? "PCI" : "EISA",
+ vortex_info_tbl[chip_idx].name,
+ ioaddr);
+
+ /* private struct aligned and zeroed by init_etherdev */
+ vp = dev->priv;
+ vp->priv_addr = vp;
dev->base_addr = ioaddr;
dev->irq = irq;
dev->mtu = mtu;
- /* Make certain the descriptor lists are aligned. */
- {
- void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
- vp = (void *)(((long)mem + 15) & ~15);
- memset(vp, 0, sizeof(*vp));
- vp->priv_addr = mem;
+ /* module list only for EISA devices */
+ if (pdev == NULL) {
+ vp->next_module = root_vortex_eisa_dev;
+ root_vortex_eisa_dev = dev;
}
- dev->priv = vp;
+
+ /* PCI-only startup logic */
+ if (pdev) {
+ /* EISA resources already marked, so only PCI needs to do this here */
+ if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size,
+ dev->name)) {
+ printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
+ dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr);
+ kfree (dev);
+ return -EBUSY;
+ }
+
+ /* wake up and enable device */
+ if (pci_enable_device (pdev)) {
+ printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name);
+ release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
+ kfree (dev);
+ return -EIO;
+ }
- vp->next_module = root_vortex_dev;
- root_vortex_dev = dev;
+ /* enable bus-mastering if necessary */
+ if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER)
+ pci_set_master (pdev);
+ }
vp->lock = SPIN_LOCK_UNLOCKED;
vp->chip_id = chip_idx;
vp->pdev = pdev;
+ /* if we are a PCI driver, we store info in pdev->driver_data
+ * instead of a module list */
+ if (pdev)
+ pdev->driver_data = dev;
+
/* The lower four bits are the media type. */
if (dev->mem_start)
option = dev->mem_start;
@@ -793,7 +758,7 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
EL3WINDOW(0);
for (i = 0; i < 0x40; i++) {
int timer;
-#ifdef CARDBUS
+#if 1 /* ifdef CARDBUS */
outw(0x230 + i, ioaddr + Wn0EepromCmd);
#else
outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
@@ -835,7 +800,7 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
dev->irq);
#endif
- if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+ if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
u32 fn_st_addr; /* Cardbus function status space */
fn_st_addr = pci_resource_start (pdev, 2);
if (fn_st_addr)
@@ -922,9 +887,6 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
}
- /* We do a request_region() to register /proc/ioports info. */
- request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
/* The 3c59x-specific entries in the device structure. */
dev->open = &vortex_open;
dev->hard_start_xmit = &vortex_start_xmit;
@@ -932,10 +894,10 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
dev->get_stats = &vortex_get_stats;
dev->do_ioctl = &vortex_ioctl;
dev->set_multicast_list = &set_rx_mode;
- dev->tx_timeout = vortex_tx_timeout;
+ dev->tx_timeout = &vortex_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- return dev;
+ return 0;
}
static void wait_for_completion(struct net_device *dev, int cmd)
@@ -956,11 +918,13 @@ vortex_up(struct net_device *dev)
long ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
union wn3_config config;
- int i;
-
- /* Should be if(HAS_ACPI) */
- acpi_wake(vp->pdev);
+ int i, device_id;
+ if (vp->pdev)
+ device_id = vp->pdev->device;
+ else
+ device_id = 0x5900; /* EISA */
+
/* Before initializing select the active media port. */
EL3WINDOW(3);
config.i = inl(ioaddr + Wn3_Config);
@@ -972,7 +936,7 @@ vortex_up(struct net_device *dev)
media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
} else if (vp->autoselect) {
- if (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY)
+ if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)
dev->if_port = XCVR_NWAY;
else {
/* Find first available media type, starting with 100baseTx. */
@@ -995,7 +959,7 @@ vortex_up(struct net_device *dev)
vp->full_duplex = vp->force_fd;
config.u.xcvr = dev->if_port;
- if ( ! (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY))
+ if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
outl(config.i, ioaddr + Wn3_Config);
if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
@@ -1045,12 +1009,11 @@ vortex_up(struct net_device *dev)
if (vp->cb_fn_base) {
u_short n = inw(ioaddr + Wn2_ResetOptions);
/* Inverted LED polarity */
- if (pci_tbl[vp->chip_id].device_id != 0x5257)
+ if (device_id != 0x5257)
n |= 0x0010;
/* Inverted polarity of MII power bit */
- if ((pci_tbl[vp->chip_id].device_id == 0x6560) ||
- (pci_tbl[vp->chip_id].device_id == 0x6562) ||
- (pci_tbl[vp->chip_id].device_id == 0x5257))
+ if ((device_id == 0x6560) || (device_id == 0x6562) ||
+ (device_id == 0x5257))
n |= 0x4000;
outw(n, ioaddr + Wn2_ResetOptions);
}
@@ -2088,66 +2051,107 @@ static void acpi_set_WOL(struct net_device *dev)
/* Change the power state to D3; RxEnable doesn't take effect. */
pci_write_config_word(vp->pdev, 0xe0, 0x8103);
}
-/* Change from D3 (sleep) to D0 (active).
- Problem: The Cyclone forgets all PCI config info during the transition! */
-static void acpi_wake(struct pci_dev *pdev)
+
+
+static void __devexit vortex_remove_one (struct pci_dev *pdev)
{
- u32 base0, base1, romaddr;
- u16 pci_command, pwr_command;
- u8 pci_latency, pci_cacheline, irq;
+ struct net_device *dev = pdev->driver_data;
+ struct vortex_private *vp;
- pci_read_config_word(pdev, 0xe0, &pwr_command);
- if ((pwr_command & 3) == 0)
+ if (!dev)
return;
- pci_read_config_word( pdev, PCI_COMMAND, &pci_command);
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base0);
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &base1);
- pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr);
- pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency);
- pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
- pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq);
-
- pci_write_config_word( pdev, 0xe0, 0x0000);
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, base0);
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base1);
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr);
- pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq);
- pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency);
- pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
- pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5);
+
+ vp = (void *)(dev->priv);
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ unregister_netdev(dev);
+ outw(TotalReset, dev->base_addr + EL3_CMD);
+ release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size);
+ kfree(dev);
}
-#ifdef MODULE
-void cleanup_module(void)
+
+static struct pci_driver vortex_driver = {
+ name: "3c575_cb",
+ probe: vortex_init_one,
+ remove: vortex_remove_one,
+ suspend: vortex_suspend,
+ resume: vortex_resume,
+ id_table: vortex_pci_tbl,
+};
+
+
+static int vortex_have_pci = 0;
+static int vortex_have_eisa = 0;
+
+
+static int __init vortex_init (void)
{
- struct net_device *next_dev;
+ int rc;
+
+ MOD_INC_USE_COUNT;
+
+ rc = pci_module_init (&vortex_driver);
+ if (rc < 0)
+ goto out;
+ if (rc > 0)
+ vortex_have_pci = 1;
+
+ rc = vortex_eisa_init ();
+ if (rc < 0)
+ goto out;
+ if (rc > 0)
+ vortex_have_eisa = 1;
+
+out:
+ MOD_DEC_USE_COUNT;
+ return rc;
+}
-#ifdef CARDBUS
- unregister_driver(&vortex_ops);
- vortex_reap();
-#endif
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_vortex_dev) {
- struct vortex_private *vp=(void *)(root_vortex_dev->priv);
- next_dev = vp->next_module;
- unregister_netdev(root_vortex_dev);
- outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
- release_region(root_vortex_dev->base_addr,
- pci_tbl[vp->chip_id].io_size);
- kfree(root_vortex_dev);
- kfree(vp->priv_addr);
- root_vortex_dev = next_dev;
+static void __exit vortex_eisa_cleanup (void)
+{
+ struct net_device *dev, *tmp;
+ struct vortex_private *vp;
+ long ioaddr;
+
+ dev = root_vortex_eisa_dev;
+
+ while (dev) {
+ vp = dev->priv;
+ ioaddr = dev->base_addr;
+
+ unregister_netdev (dev);
+ outw (TotalReset, ioaddr + EL3_CMD);
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+
+ tmp = dev;
+ dev = vp->next_module;
+
+ kfree (tmp);
}
}
-#endif /* MODULE */
+
+static void __exit vortex_cleanup (void)
+{
+ if (vortex_have_pci)
+ pci_unregister_driver (&vortex_driver);
+ if (vortex_have_eisa)
+ vortex_eisa_cleanup ();
+}
+
+
+module_init(vortex_init);
+module_exit(vortex_cleanup);
+
+
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c"
+ * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 534a4bdbd..936abfed8 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -18,6 +18,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
if [ "$CONFIG_CARDBUS" = "y" ]; then
dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
+ tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP
fi
bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile
index 5d0d36f4a..65938d96d 100644
--- a/drivers/net/pcmcia/Makefile
+++ b/drivers/net/pcmcia/Makefile
@@ -19,8 +19,6 @@ obj- :=
# Things that need to export symbols
export-objs := ray_cs.o
-CFLAGS_3c575_cb.o = -DCARDBUS -DMODULE
-
# 16-bit client drivers
obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o
@@ -39,6 +37,7 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o
# Cardbus client drivers
obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o
+obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o
O_OBJS := $(filter-out $(export-objs), $(obj-y))
OX_OBJS := $(filter $(export-objs), $(obj-y))
diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c
new file mode 100644
index 000000000..c1cb7629f
--- /dev/null
+++ b/drivers/net/pcmcia/xircom_tulip_cb.c
@@ -0,0 +1,3153 @@
+/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
+/*
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ This driver is for the Digital "Tulip" Ethernet adapter interface.
+ It should work with most DEC 21*4*-based chips/ethercards, as well as
+ with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
+
+ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ Center of Excellence in Space Data and Information Sciences
+ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Support and updates available at
+ http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+*/
+
+#define SMP_CHECK
+#define CARDBUS 1
+static const char version[] = "xircom_tulip_cb.c:v0.91 4/14/99 becker@cesdis.gsfc.nasa.gov (modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford)\n";
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
+
+/* The possible media types that can be set in options[] are: */
+static const char * const medianame[] = {
+ "10baseT", "10base2", "AUI", "100baseTx",
+ "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+ "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+
+/* Keep the ring sizes a power of two for efficiency.
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 32
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+
+/*
+ Set the bus performance register.
+ Typical: Set 16 longword cache alignment, no burst limit.
+ Cache alignment bits 15:14 Burst length 13:8
+ 0000 No alignment 0x00000000 unlimited 0800 8 longwords
+ 4000 8 longwords 0100 1 longword 1000 16 longwords
+ 8000 16 longwords 0200 2 longwords 2000 32 longwords
+ C000 32 longwords 0400 4 longwords
+ Warning: many older 486 systems are broken and require setting 0x00A04800
+ 8 longword cache alignment, 8 longword burst.
+ ToDo: Non-Intel setting could be better.
+*/
+
+#if defined(__alpha__)
+static int csr0 = 0x01A00000 | 0xE000;
+#elif defined(__powerpc__)
+static int csr0 = 0x01B00000 | 0x8000;
+#elif defined(__sparc__)
+static int csr0 = 0x01B00080 | 0x8000;
+#elif defined(__i386__)
+static int csr0 = 0x01A00000 | 0x8000;
+#else
+#warning Processor architecture undefined!
+static int csr0 = 0x00A00000 | 0x4800;
+#endif
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+ to support a pre-NWay full-duplex signaling mechanism using short frames.
+ No one knows what it should be, but if left at its default value some
+ 10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC 0x6969
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
+ This is only in the support-all-kernels source code. */
+
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(csr0, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+#define RUN_AT(x) (jiffies + (x))
+
+#define tulip_debug debug
+#ifdef TULIP_DEBUG
+static int tulip_debug = TULIP_DEBUG;
+#else
+static int tulip_debug = 1;
+#endif
+
+/*
+ Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the DECchip "Tulip", Digital's
+single-chip ethernet controllers for PCI. Supported members of the family
+are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported.
+
+These chips are used on at least 140 unique PCI board designs. The great
+number of chips and board designs supported is the reason for the
+driver size and complexity. Almost of the increasing complexity is in the
+board configuration and media selection code. There is very little
+increasing in the operational critical path length.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board. The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+
+Some boards have EEPROMs tables with default media entry. The factory default
+is usually "autoselect". This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Tulip as receive data buffers. When an incoming frame is less than
+RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
+copied to the new skbuff. When the incoming frame is larger, the skbuff is
+passed directly up the protocol stack and replaced by a newly allocated
+skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames. For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information). For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data. A subtle aspect of this
+choice is that the Tulip only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control. One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag. The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'tp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.) After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+IV. Notes
+
+Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
+Greg LaPolla at Linksys provided PNIC and other Linksys boards.
+Znyx provided a four-port card for testing.
+
+IVb. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
+http://www.national.com/pf/DP/DP83840A.html
+http://www.asix.com.tw/pmac.htm
+http://www.admtek.com.tw/
+
+IVc. Errata
+
+The old DEC databooks were light on details.
+The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written. Hmmm, now how is that possible?
+
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below. Some boards do not have EEPROM
+media tables and need to be patched up. Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
+
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them. The MII transceiver status is polled using an kernel timer.
+
+*/
+
+/* This table use during operation for capabilities and media timer. */
+
+static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
+static void comet_timer(unsigned long data);
+
+enum tbl_flag {
+ HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
+ HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+ HAS_NWAY143=0x40, /* Uses 21143-like internal NWay. */
+};
+static struct tulip_chip_table {
+ char *chip_name;
+ int io_size;
+ int valid_intrs; /* CSR7 interrupt enable settings */
+ int flags;
+ void (*media_timer)(unsigned long data);
+} tulip_tbl[] = {
+ { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+ { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
+ { "Digital DS21140 Tulip", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+ { "Digital DS21143 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, t21142_timer },
+ { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+ HAS_MII, pnic_timer },
+ { "Macronix 98713 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Macronix 98715 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "Macronix 98725 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+ { "Lite-On PNIC-II", 256, 0x0001ebef,
+ HAS_MII | HAS_NWAY143, pnic_timer },
+ { "ADMtek Comet", 256, 0x0001abef,
+ MC_HASH_ONLY, comet_timer },
+ { "Compex 9881 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Xircom Cardbus Adapter (DEC 21143 compatible mode)", 128, 0x0801fbff,
+ HAS_MII | HAS_ACPI, tulip_timer },
+ {0},
+};
+/* This matches the table above. Note 21142 == 21143. */
+enum chips {
+ DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+ LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
+ X3201_3,
+};
+
+/* A full-duplex map for media types. */
+enum MediaIs {
+ MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+ MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
+static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
+/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
+static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
+static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+/* Offsets to the Command and Status Registers, "CSRs". All accesses
+ must be longword instructions and quadword aligned. */
+enum tulip_offsets {
+ CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+ CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+ CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+ TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+ NormalIntr=0x10000, AbnormalIntr=0x8000,
+ RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
+ TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
+};
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct tulip_rx_desc {
+ s32 status;
+ s32 length;
+ u32 buffer1, buffer2;
+};
+
+struct tulip_tx_desc {
+ s32 status;
+ s32 length;
+ u32 buffer1, buffer2; /* We use only buffer 1. */
+};
+
+enum desc_status_bits {
+ DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+
+/* Ring-wrap flag in length field, use for last ring entry.
+ 0x01000000 means chain on buffer2 address,
+ 0x02000000 means use the ring start address in CSR2/3.
+ Note: Some work-alike chips do not function correctly in chained mode.
+ The ASIX chip works only in chained mode.
+ Thus we indicates ring mode, but always write the 'next' field for
+ chained mode as well.
+*/
+#define DESC_RING_WRAP 0x02000000
+
+#ifdef CARDBUS
+#define EEPROM_ADDRLEN (chip_rev == 65 ? 8 : 6)
+#else
+#define EEPROM_ADDRLEN 6
+#endif
+#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */
+
+struct medialeaf {
+ u8 type;
+ u8 media;
+ unsigned char *leafdata;
+};
+
+struct mediatable {
+ u16 defaultmedia;
+ u8 leafcount, csr12dir; /* General purpose pin directions. */
+ unsigned has_mii:1, has_nonmii:1, has_reset:6;
+ u32 csr15dir, csr15val; /* 21143 NWay setting. */
+ struct medialeaf mleaf[0];
+};
+
+struct mediainfo {
+ struct mediainfo *next;
+ int info_type;
+ int index;
+ unsigned char *info;
+};
+
+struct tulip_private {
+ char devname[8]; /* Used only for kernel debugging. */
+ const char *product_name;
+ struct tulip_rx_desc rx_ring[RX_RING_SIZE];
+ struct tulip_tx_desc tx_ring[TX_RING_SIZE];
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
+#ifdef CARDBUS
+ /* The X3201-3 requires double word aligned tx bufs */
+ struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
+#endif
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
+ char *rx_buffs; /* Address of temporary Rx buffers. */
+ u8 setup_buf[96*sizeof(u16) + 7];
+ u16 *setup_frame; /* Pseudo-Tx frame to init address table. */
+ int chip_id;
+ int revision;
+ struct net_device_stats stats;
+ struct timer_list timer; /* Media selection timer. */
+ int interrupt; /* In-interrupt flag. */
+ unsigned int cur_rx, cur_tx; /* The next free ring entry */
+ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int full_duplex_lock:1;
+ unsigned int fake_addr:1; /* Multiport board faked address. */
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int media2:4; /* Secondary monitored media port. */
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+ unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
+ unsigned int open:1;
+ unsigned int csr0; /* CSR0 setting. */
+ unsigned int csr6; /* Current CSR6 control settings. */
+ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
+ u16 to_advertise; /* NWay capabilities advertised. */
+ u16 lpar; /* 21143 Link partner ability. */
+ u16 advertising[4];
+ signed char phys[4], mii_cnt; /* MII device addresses. */
+ struct mediatable *mtable;
+ int cur_index; /* Current media index. */
+ int saved_if_port;
+ struct pci_dev *pdev;
+ spinlock_t lock;
+ int pad0, pad1; /* Used for 8-byte alignment */
+};
+
+static void parse_eeprom(struct net_device *dev);
+static int read_eeprom(long ioaddr, int location, int addr_len);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static void select_media(struct net_device *dev, int startup);
+static void tulip_up(struct net_device *dev);
+static void tulip_down(struct net_device *dev);
+static int tulip_open(struct net_device *dev);
+static void tulip_timer(unsigned long data);
+static void t21142_start_nway(struct net_device *dev);
+static void tulip_tx_timeout(struct net_device *dev);
+static void tulip_init_ring(struct net_device *dev);
+static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int tulip_rx(struct net_device *dev);
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int tulip_close(struct net_device *dev);
+static struct net_device_stats *tulip_get_stats(struct net_device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#endif
+static void set_rx_mode(struct net_device *dev);
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+ manipulated. Keith Owens <kaos@ocs.com.au>. */
+
+static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx)
+{
+ const int strict_bits = 0x0060e202;
+ int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+ long flags;
+ save_flags(flags);
+ cli();
+ if (chip_idx != X3201_3) {
+ outl(newcsr6, ioaddr + CSR6);
+ restore_flags(flags);
+ return;
+ }
+ newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
+ /* read 0 on the Xircom cards */
+ newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
+ currcsr6 = inl(ioaddr + CSR6);
+ if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+ ((currcsr6 & ~0x2002) == 0)) {
+ outl(newcsr6, ioaddr + CSR6); /* safe */
+ restore_flags(flags);
+ return;
+ }
+ /* make sure the transmitter and receiver are stopped first */
+ currcsr6 &= ~0x2002;
+ while (1) {
+ csr5 = inl(ioaddr + CSR5);
+ if (csr5 == 0xffffffff)
+ break; /* cannot read csr5, card removed? */
+ csr5_22_20 = csr5 & 0x700000;
+ csr5_19_17 = csr5 & 0x0e0000;
+ if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+ (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+ break; /* both are stopped or suspended */
+ if (!--attempts) {
+ printk(KERN_INFO "tulip.c: outl_CSR6 too many attempts,"
+ "csr5=0x%08x\n", csr5);
+ outl(newcsr6, ioaddr + CSR6); /* unsafe but do it anyway */
+ restore_flags(flags);
+ return;
+ }
+ outl(currcsr6, ioaddr + CSR6);
+ udelay(1);
+ }
+ /* now it is safe to change csr6 */
+ outl(newcsr6, ioaddr + CSR6);
+ restore_flags(flags);
+}
+
+static struct net_device *tulip_probe1(struct pci_dev *pdev,
+ struct net_device *dev, long ioaddr, int irq,
+ int chip_idx, int board_idx)
+{
+ static int did_version = 0; /* Already printed version info. */
+ struct tulip_private *tp;
+ /* See note below on the multiport cards. */
+ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+ static int last_irq = 0;
+ static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
+ u8 chip_rev;
+ int i;
+ unsigned short sum;
+
+ if (tulip_debug > 0 && did_version++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ dev = init_etherdev(dev, 0);
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
+ /* Bring the 21143 out of sleep mode.
+ Caution: Snooze mode does not work with some boards! */
+ if (tulip_tbl[chip_idx].flags & HAS_ACPI)
+ pci_write_config_dword(pdev, 0x40, 0x00000000);
+
+ printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+ dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+
+ /* Stop the chip's Tx and Rx processes. */
+ outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, chip_idx);
+ /* Clear the missed-packet counter. */
+ (volatile int)inl(ioaddr + CSR8);
+
+ if (chip_idx == DC21041) {
+ if (inl(ioaddr + CSR9) & 0x8000) {
+ printk(" 21040 compatible mode,");
+ chip_idx = DC21040;
+ } else {
+ printk(" 21041 mode,");
+ }
+ }
+
+ /* The station address ROM is read byte serially. The register must
+ be polled, waiting for the value to be read bit serially from the
+ EEPROM.
+ */
+ sum = 0;
+ if (chip_idx == DC21040) {
+ outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
+ for (i = 0; i < 6; i++) {
+ int value, boguscnt = 100000;
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ dev->dev_addr[i] = value;
+ sum += value & 0xff;
+ }
+ } else if (chip_idx == LC82C168) {
+ for (i = 0; i < 3; i++) {
+ int value, boguscnt = 100000;
+ outl(0x600 | i, ioaddr + 0x98);
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+ sum += value & 0xffff;
+ }
+ } else if (chip_idx == COMET) {
+ /* No need to read the EEPROM. */
+ put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
+ put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+ for (i = 0; i < 6; i ++)
+ sum += dev->dev_addr[i];
+ } else if (chip_idx == X3201_3) {
+ /* Xircom has its address stored in the CIS
+ * we access it through the boot rom interface for now
+ * this might not work, as the CIS is not parsed but I
+ * (danilo) use the offset I found on my card's CIS !!!
+ *
+ * Doug Ledford: I changed this routine around so that it
+ * walks the CIS memory space, parsing the config items, and
+ * finds the proper lan_node_id tuple and uses the data
+ * stored there.
+ */
+ unsigned char j, tuple, link, data_id, data_count;
+ outl(1<<12, ioaddr + CSR9); /* enable boot rom access */
+ for (i = 0x100; i < 0x1f7; i += link+2) {
+ outl(i, ioaddr + CSR10);
+ tuple = inl(ioaddr + CSR9) & 0xff;
+ outl(i + 1, ioaddr + CSR10);
+ link = inl(ioaddr + CSR9) & 0xff;
+ outl(i + 2, ioaddr + CSR10);
+ data_id = inl(ioaddr + CSR9) & 0xff;
+ outl(i + 3, ioaddr + CSR10);
+ data_count = inl(ioaddr + CSR9) & 0xff;
+ if ( (tuple == 0x22) &&
+ (data_id == 0x04) && (data_count == 0x06) ) {
+ /*
+ * This is it. We have the data we want.
+ */
+ for (j = 0; j < 6; j++) {
+ outl(i + j + 4, ioaddr + CSR10);
+ dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff;
+ }
+ break;
+ } else if (link == 0) {
+ break;
+ }
+ }
+ sum = 1; // to make check below fail!
+ } else { /* Must be a new chip, with a serial EEPROM interface. */
+ /* We read the whole EEPROM, and sort it out later. DEC has a
+ specification _Digital Semiconductor 21X4 Serial ROM Format_
+ but early vendor boards just put the address in the first six
+ EEPROM locations. */
+ unsigned char ee_data[EEPROM_SIZE];
+ int sa_offset = 0;
+
+ for (i = 0; i < sizeof(ee_data)/2; i++)
+ ((u16 *)ee_data)[i] =
+ le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
+
+ /* Detect the simple EEPROM format by the duplicated station addr. */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ sa_offset = 20;
+ if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
+ sa_offset = 2; /* Grrr, damn Matrox boards. */
+ multiport_cnt = 4;
+ }
+ for (i = 0; i < 6; i ++) {
+ dev->dev_addr[i] = ee_data[i + sa_offset];
+ sum += ee_data[i + sa_offset];
+ }
+ }
+ /* Lite-On boards have the address byte-swapped. */
+ if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0)
+ && dev->dev_addr[1] == 0x00)
+ for (i = 0; i < 6; i+=2) {
+ char tmp = dev->dev_addr[i];
+ dev->dev_addr[i] = dev->dev_addr[i+1];
+ dev->dev_addr[i+1] = tmp;
+ }
+ /* On the Zynx 315 Etherarray and other multiport boards only the
+ first Tulip has an EEPROM.
+ The addresses of the subsequent ports are derived from the first.
+ Many PCI BIOSes also incorrectly report the IRQ line, so we correct
+ that here as well. */
+ if (sum == 0 || sum == 6*0xff) {
+ printk(" EEPROM not present,");
+ for (i = 0; i < 5; i++)
+ dev->dev_addr[i] = last_phys_addr[i];
+ dev->dev_addr[i] = last_phys_addr[i] + 1;
+#if defined(__i386__) /* Patch up x86 BIOS bug. */
+ if (last_irq)
+ irq = last_irq;
+#endif
+ }
+
+ for (i = 0; i < 6; i++)
+ printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
+ printk(", IRQ %d.\n", irq);
+ last_irq = irq;
+
+ /* We do a request_region() only to register /proc/ioports info. */
+ /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
+ request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name);
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ /* Make certain the data structures are quadword aligned. */
+ tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
+ memset(tp, 0, sizeof(*tp));
+ dev->priv = tp;
+
+ tp->lock = SPIN_LOCK_UNLOCKED;
+ tp->pdev = pdev;
+ tp->chip_id = chip_idx;
+ tp->revision = chip_rev;
+ tp->csr0 = csr0;
+ tp->setup_frame = (u16 *)(((unsigned long)tp->setup_buf + 7) & ~7);
+
+ /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
+ And the ASIX must have a burst limit or horrible things happen. */
+ if ( (chip_idx == DC21143 && chip_rev == 65) ||
+ (chip_idx == X3201_3) )
+ tp->csr0 &= ~0x01000000;
+ else if (chip_idx == AX88140)
+ tp->csr0 |= 0x2000;
+
+#ifdef TULIP_FULL_DUPLEX
+ tp->full_duplex = 1;
+ tp->full_duplex_lock = 1;
+#endif
+#ifdef TULIP_DEFAULT_MEDIA
+ tp->default_port = TULIP_DEFAULT_MEDIA;
+#endif
+#ifdef TULIP_NO_MEDIA_SWITCH
+ tp->medialock = 1;
+#endif
+
+ /* The lower four bits are the media type. */
+ if (board_idx >= 0 && board_idx < MAX_UNITS) {
+ tp->default_port = options[board_idx] & 15;
+ if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+ tp->full_duplex = 1;
+ if (mtu[board_idx] > 0)
+ dev->mtu = mtu[board_idx];
+ }
+ if (dev->mem_start)
+ tp->default_port = dev->mem_start;
+ if (tp->default_port) {
+ tp->medialock = 1;
+ if (media_cap[tp->default_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ }
+ if (tp->full_duplex)
+ tp->full_duplex_lock = 1;
+
+ /* This is logically part of probe1(), but too complex to write inline. */
+ if (tulip_tbl[chip_idx].flags & HAS_MEDIA_TABLE)
+ parse_eeprom(dev);
+
+ if (media_cap[tp->default_port] & MediaIsMII) {
+ u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+ tp->to_advertise = media2advert[tp->default_port - 9];
+ } else
+ tp->to_advertise = 0x03e1;
+
+ if ((tulip_tbl[chip_idx].flags & ALWAYS_CHECK_MII) ||
+ (tp->mtable && tp->mtable->has_mii) ||
+ ( ! tp->mtable && (tulip_tbl[chip_idx].flags & HAS_MII))) {
+ int phy, phy_idx;
+ if (tp->mtable && tp->mtable->has_mii) {
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == 11) {
+ tp->cur_index = i;
+ tp->saved_if_port = dev->if_port;
+ select_media(dev, 1);
+ dev->if_port = tp->saved_if_port;
+ break;
+ }
+ }
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later,
+ but takes much time. */
+ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+ phy++) {
+ int mii_status = mdio_read(dev, phy, 1);
+ if ((mii_status & 0x8301) == 0x8001 ||
+ ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) {
+ int mii_reg0 = mdio_read(dev, phy, 0);
+ int mii_advert = mdio_read(dev, phy, 4);
+ int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+ tp->phys[phy_idx] = phy;
+ tp->advertising[phy_idx++] = reg4;
+ printk(KERN_INFO "%s: MII transceiver #%d "
+ "config %4.4x status %4.4x advertising %4.4x.\n",
+ dev->name, phy, mii_reg0, mii_status, mii_advert);
+ /* Fixup for DLink with miswired PHY. */
+ if (mii_advert != reg4) {
+ printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
+ " previously advertising %4.4x.\n",
+ dev->name, reg4, phy, mii_advert);
+ mdio_write(dev, phy, 4, reg4);
+ }
+ /* Enable autonegotiation: some boards default to off. */
+ mdio_write(dev, phy, 0, mii_reg0 |
+ (tp->full_duplex ? 0x1100 : 0x1000) |
+ (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
+ }
+ }
+ tp->mii_cnt = phy_idx;
+ if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
+ printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+ dev->name);
+ tp->phys[0] = 1;
+ }
+ }
+
+ /* The Tulip-specific entries in the device structure. */
+ dev->open = &tulip_open;
+ dev->hard_start_xmit = &tulip_start_xmit;
+ dev->stop = &tulip_close;
+ dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+ dev->do_ioctl = &private_ioctl;
+#endif
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_rx_mode;
+#endif
+ dev->tx_timeout = tulip_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ /* Reset the xcvr interface and turn on heartbeat. */
+ switch (chip_idx) {
+ case DC21041:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+ outl_CSR6(inl(ioaddr + CSR6) | 0x0200, ioaddr, chip_idx);
+ outl(0x0000EF05, ioaddr + CSR13);
+ break;
+ case DC21040:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0x00000004, ioaddr + CSR13);
+ break;
+ case DC21140: default:
+ if (tp->mtable)
+ outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+ break;
+ case DC21142:
+ case PNIC2:
+ if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) {
+ outl_CSR6(0x82020000, ioaddr, chip_idx);
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ outl_CSR6(0x820E0000, ioaddr, chip_idx);
+ } else {
+ outl_CSR6(0x82420200, ioaddr, chip_idx);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+ }
+ break;
+ case X3201_3:
+ outl(0x0008, ioaddr + CSR15);
+ udelay(5); /* The delays are Xircom recommended to give the
+ * chipset time to reset the actual hardware
+ * on the PCMCIA card
+ */
+ outl(0xa8050000, ioaddr + CSR15);
+ udelay(5);
+ outl(0xa00f0000, ioaddr + CSR15);
+ udelay(5);
+ outl_CSR6(0x32000200, ioaddr, chip_idx);
+ break;
+ case LC82C168:
+ if ( ! tp->mii_cnt) {
+ outl_CSR6(0x00420000, ioaddr, chip_idx);
+ outl(0x30, ioaddr + CSR12);
+ outl(0x0001F078, ioaddr + 0xB8);
+ outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+ }
+ break;
+ case MX98713: case COMPEX9881:
+ outl_CSR6(0x00000000, ioaddr, chip_idx);
+ outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+ outl(0x00000001, ioaddr + CSR13);
+ break;
+ case MX98715: case MX98725:
+ outl_CSR6(0x01a80000, ioaddr, chip_idx);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00001000, ioaddr + CSR12);
+ break;
+ case COMET:
+ /* No initialization necessary. */
+ break;
+ }
+
+ return dev;
+}
+
+/* Serial EEPROM section. */
+/* The main routine to parse the very complicated SROM structure.
+ Search www.digital.com for "21X4 SROM" to get details.
+ This code is very complex, and will require changes to support
+ additional cards, so I'll be verbose about what is going on.
+ */
+
+/* Known cards that have old-style EEPROMs. */
+static struct fixups {
+ char *name;
+ unsigned char addr0, addr1, addr2;
+ u16 newtable[32]; /* Max length below. */
+} eeprom_fixups[] = {
+ {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
+ 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+ {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0903, 0x006D, /* 100baseTx */ }},
+ {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,
+ 0x0107, 0x8021, /* 100baseFx */
+ 0x0108, 0x8021, /* 100baseFx-FD */
+ 0x0103, 0x006D, /* 100baseTx */ }},
+ {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
+ 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},
+ {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,
+ 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ }},
+ {0, 0, 0, 0, {}}};
+
+static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+
+#if defined(__i386__) /* AKA get_unaligned() */
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
+static void parse_eeprom(struct net_device *dev)
+{
+ /* The last media info list parsed, for multiport boards. */
+ static struct mediatable *last_mediatable = NULL;
+ static unsigned char *last_ee_data = NULL;
+ static int controller_index = 0;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ unsigned char *ee_data = tp->eeprom;
+ int i;
+#ifdef CARDBUS
+ int chip_rev = tp->revision;
+#endif
+
+ tp->mtable = 0;
+ for (i = 0; i < EEPROM_SIZE/2; i++)
+ ((u16 *)ee_data)[i] =
+ le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
+
+ /* Detect an old-style (SA only) EEPROM layout:
+ memcmp(eedata, eedata+16, 8). */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ break;
+ if (i >= 8) {
+ if (ee_data[0] == 0xff) {
+ if (last_mediatable) {
+ controller_index++;
+ printk(KERN_INFO "%s: Controller %d of multiport board.\n",
+ dev->name, controller_index);
+ tp->mtable = last_mediatable;
+ ee_data = last_ee_data;
+ goto subsequent_board;
+ } else
+ printk(KERN_INFO "%s: Missing EEPROM, this interface may "
+ "not work correctly!\n",
+ dev->name);
+ return;
+ }
+ /* Do a fix-up based on the vendor half of the station address prefix. */
+ for (i = 0; eeprom_fixups[i].name; i++) {
+ if (dev->dev_addr[0] == eeprom_fixups[i].addr0
+ && dev->dev_addr[1] == eeprom_fixups[i].addr1
+ && dev->dev_addr[2] == eeprom_fixups[i].addr2) {
+ if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
+ i++; /* An Accton EN1207, not an outlaw Maxtech. */
+ memcpy(ee_data + 26, eeprom_fixups[i].newtable,
+ sizeof(eeprom_fixups[i].newtable));
+ printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using"
+ " substitute media control info.\n",
+ dev->name, eeprom_fixups[i].name);
+ break;
+ }
+ }
+ if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
+ printk(KERN_INFO "%s: Old style EEPROM with no media selection "
+ "information.\n",
+ dev->name);
+ return;
+ }
+ }
+
+ controller_index = 0;
+ if (ee_data[19] > 1) { /* Multiport board. */
+ last_ee_data = ee_data;
+ }
+subsequent_board:
+
+ if (ee_data[27] == 0) { /* No valid media table. */
+ } else if (tp->chip_id == DC21041) {
+ unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
+ short media;
+ int count;
+
+ media = get_u16(p);
+ p += 2;
+ count = *p++;
+
+ printk(KERN_INFO "%s:21041 Media information at %d, default media "
+ "%4.4x (%s).\n", dev->name, ee_data[27], media,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ unsigned char media_code = *p++;
+ u16 csrvals[3];
+ int idx;
+ for (idx = 0; idx < 3; idx++) {
+ csrvals[idx] = get_u16(p);
+ p += 2;
+ }
+ if (media_code & 0x40) {
+ printk(KERN_INFO "%s: 21041 media %2.2x (%s),"
+ " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
+ dev->name, media_code & 15, medianame[media_code & 15],
+ csrvals[0], csrvals[1], csrvals[2]);
+ } else
+ printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
+ dev->name, media_code & 15, medianame[media_code & 15]);
+ }
+ } else {
+ unsigned char *p = (void *)ee_data + ee_data[27];
+ unsigned char csr12dir = 0;
+ int count;
+ struct mediatable *mtable;
+ u16 media = get_u16(p);
+
+ p += 2;
+ if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
+ csr12dir = *p++;
+ count = *p++;
+ mtable = (struct mediatable *)
+ kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
+ GFP_KERNEL);
+ if (mtable == NULL)
+ return; /* Horrible, impossible failure. */
+ last_mediatable = tp->mtable = mtable;
+ mtable->defaultmedia = media;
+ mtable->leafcount = count;
+ mtable->csr12dir = csr12dir;
+ mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
+ mtable->csr15dir = mtable->csr15val = 0;
+
+ printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ struct medialeaf *leaf = &mtable->mleaf[i];
+
+ if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
+ leaf->type = 0;
+ leaf->media = p[0] & 0x3f;
+ leaf->leafdata = p;
+ if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */
+ mtable->has_mii = 1;
+ p += 4;
+ } else {
+ leaf->type = p[1];
+ if (p[1] == 0x05) {
+ mtable->has_reset = i;
+ leaf->media = p[2] & 0x0f;
+ } else if (p[1] & 1) {
+ mtable->has_mii = 1;
+ leaf->media = 11;
+ } else {
+ mtable->has_nonmii = 1;
+ leaf->media = p[2] & 0x0f;
+ if (p[1] == 2) {
+ if (leaf->media == 0) {
+ mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
+ mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
+ } else if (leaf->media == 0x40) {
+ u32 base15 = get_unaligned((u16*)&p[7]);
+ mtable->csr15dir =
+ (get_unaligned((u16*)&p[9])<<16) + base15;
+ mtable->csr15val =
+ (get_unaligned((u16*)&p[11])<<16) + base15;
+ }
+ }
+ }
+ leaf->leafdata = p + 2;
+ p += (p[0] & 0x3f) + 1;
+ }
+ if (tulip_debug > 1 && leaf->media == 11) {
+ unsigned char *bp = leaf->leafdata;
+ printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
+ "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
+ dev->name, bp[0], bp[1], bp[1 + bp[1]*2],
+ bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+ }
+ printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
+ "by a %s (%d) block.\n",
+ dev->name, i, medianame[leaf->media], leaf->media,
+ block_name[leaf->type], leaf->type);
+ }
+ }
+}
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
+#define EE_CS 0x01 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x01
+#define EE_WRITE_1 0x05
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+ We add a bus turn-around to insure that this remains true. */
+#define eeprom_delay() inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5 << addr_len)
+#define EE_READ_CMD (6 << addr_len)
+#define EE_ERASE_CMD (7 << addr_len)
+
+static int read_eeprom(long ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned short retval = 0;
+ long ee_addr = ioaddr + CSR9;
+ int read_cmd = location | EE_READ_CMD;
+
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ outl(EE_ENB, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ outl(EE_ENB | dataval, ee_addr);
+ eeprom_delay();
+ outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ }
+ outl(EE_ENB, ee_addr);
+
+ for (i = 16; i > 0; i--) {
+ outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outl(EE_ENB, ee_addr);
+ eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ return retval;
+}
+
+/* MII transceiver control section.
+ Read and write the MII registers using software-generated serial
+ MDIO protocol. See the MII specifications or DP83840A data sheet
+ for details. */
+
+/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+ MDIO protocol. It is just different enough from the EEPROM protocol
+ to not share code. The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN 0x40000
+#define MDIO_DATA_READ 0x80000
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int retval = 0;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ int i = 1000;
+ outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ while (--i > 0)
+ if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+ return retval & 0xffff;
+ return 0xffff;
+ }
+
+ if (tp->chip_id == COMET) {
+ if (phy_id == 1) {
+ if (location < 7)
+ return inl(ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ return inl(ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ return inl(ioaddr + 0xD4 + ((location-29)<<2));
+ }
+ return 0xffff;
+ }
+
+ /* Establish sync by sending at least 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+ int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ int i = 1000;
+ outl(cmd, ioaddr + 0xA0);
+ do
+ if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+ break;
+ while (--i > 0);
+ return;
+ }
+
+ if (tp->chip_id == COMET) {
+ if (phy_id != 1)
+ return;
+ if (location < 7)
+ outl(value, ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ outl(value, ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+ return;
+ }
+
+ /* Establish sync by sending 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return;
+}
+
+static void
+tulip_up(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int i;
+
+ /* On some chip revs we must set the MII/SYM port before the reset!? */
+ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
+ outl_CSR6(0x00040000, ioaddr, tp->chip_id);
+
+ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+ outl(0x00000001, ioaddr + CSR0);
+
+ /* Deassert reset. */
+ outl(tp->csr0, ioaddr + CSR0);
+ udelay(2);
+
+ if (tulip_tbl[tp->chip_id].flags & HAS_ACPI)
+ pci_write_config_dword(tp->pdev, 0x40, 0x00000000);
+
+ /* Clear the tx ring */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ tp->tx_skbuff[i] = 0;
+ tp->tx_ring[i].status = 0x00000000;
+ }
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
+
+ if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) {
+ u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+ u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
+ if (tp->chip_id == AX88140) {
+ outl(0, ioaddr + CSR13);
+ outl(addr_low, ioaddr + CSR14);
+ outl(1, ioaddr + CSR13);
+ outl(addr_high, ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) {
+ outl(addr_low, ioaddr + 0xA4);
+ outl(addr_high, ioaddr + 0xA8);
+ outl(0, ioaddr + 0xAC);
+ outl(0, ioaddr + 0xB0);
+ }
+ } else if (tp->chip_id != X3201_3) {
+ /* This is set_rx_mode(), but without starting the transmitter. */
+ u16 *eaddrs = (u16 *)dev->dev_addr;
+ u16 *setup_frm = &tp->setup_frame[15*6];
+
+ /* 21140 bug: you must add the broadcast address. */
+ memset(tp->setup_frame, 0xff, 96*sizeof(u16));
+ /* Fill the final entry of the table with our physical address. */
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ /* Put the setup frame on the Tx list. */
+ tp->tx_ring[0].length = 0x08000000 | 192;
+ tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
+ tp->tx_ring[0].status = DescOwned;
+
+ tp->cur_tx++;
+ } else { /* X3201_3 */
+ u16 *eaddrs = (u16 *)dev->dev_addr;
+ u16 *setup_frm = &tp->setup_frame[0*6];
+
+ /* fill the table with the broadcast address */
+ memset(tp->setup_frame, 0xff, 96*sizeof(u16));
+ /* re-fill the first 14 table entries with our address */
+ for(i=0; i<14; i++) {
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+
+ /* Put the setup frame on the Tx list. */
+ tp->tx_ring[0].length = 0x08000000 | 192;
+ /* Lie about the address of our setup frame to make the */
+ /* chip happy */
+ tp->tx_ring[0].buffer1 = (virt_to_bus(tp->setup_frame) + 4);
+ tp->tx_ring[0].status = DescOwned;
+
+ tp->cur_tx++;
+ }
+ outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
+ outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+
+ tp->saved_if_port = dev->if_port;
+ if (dev->if_port == 0)
+ dev->if_port = tp->default_port;
+ if (tp->chip_id == DC21041 && dev->if_port > 4)
+ /* Invalid: Select initial TP, autosense, autonegotiate. */
+ dev->if_port = 4;
+
+ /* Allow selecting a default media. */
+ i = 0;
+ if (tp->mtable == NULL)
+ goto media_picked;
+ if (dev->if_port) {
+ int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
+ (dev->if_port == 12 ? 0 : dev->if_port);
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using user-specified media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ goto media_picked;
+ }
+ }
+ if ((tp->mtable->defaultmedia & 0x0800) == 0) {
+ int looking_for = tp->mtable->defaultmedia & 15;
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+ dev->name, medianame[looking_for]);
+ goto media_picked;
+ }
+ }
+ /* Start sensing first non-full-duplex media. */
+ for (i = tp->mtable->leafcount - 1;
+ (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
+ ;
+media_picked:
+
+ tp->csr6 = 0;
+ tp->cur_index = i;
+ if (dev->if_port == 0 && tp->chip_id == DC21142) {
+ if (tp->mii_cnt) {
+ select_media(dev, 1);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Using MII transceiver %d, status "
+ "%4.4x.\n",
+ dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
+ outl_CSR6(0x82020000, ioaddr, tp->chip_id);
+ tp->csr6 = 0x820E0000;
+ dev->if_port = 11;
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ } else
+ t21142_start_nway(dev);
+ } else if ((tp->chip_id == LC82C168 || tp->chip_id == PNIC2)
+ && tp->mii_cnt && ! tp->medialock) {
+ dev->if_port = 11;
+ tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0001, ioaddr + CSR15);
+ } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
+ && ! tp->medialock) {
+ dev->if_port = 0;
+ tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
+ /* Provided by BOLO, Macronix - 12/10/1998. */
+ dev->if_port = 0;
+ tp->csr6 = 0x01880200;
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
+ } else if (tp->chip_id == DC21143 &&
+ media_cap[dev->if_port] & MediaIsMII) {
+ /* We must reset the media CSRs when we force-select MII mode. */
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ } else if (tp->chip_id == X3201_3) {
+ outl(0x0008, ioaddr + CSR15);
+ udelay(5);
+ outl(0xa8050000, ioaddr + CSR15);
+ udelay(5);
+ outl(0xa00f0000, ioaddr + CSR15);
+ udelay(5);
+ tp->csr6 = 0x32400000;
+ } else if (tp->chip_id == COMET) {
+ dev->if_port = 0;
+ tp->csr6 = 0x00040000;
+ } else
+ select_media(dev, 1);
+
+ /* Start the chip's Tx to process setup frame. */
+ outl_CSR6(tp->csr6, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id);
+
+ /* Enable interrupts by setting the interrupt mask. */
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ outl(0, ioaddr + CSR2); /* Rx poll demand */
+
+ netif_start_queue (dev);
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
+ dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
+ inl(ioaddr + CSR6));
+ }
+ /* Set the timer to switch to check for link beat and perhaps switch
+ to an alternate media type. */
+ init_timer(&tp->timer);
+ tp->timer.expires = RUN_AT(5*HZ);
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+ add_timer(&tp->timer);
+}
+
+static int
+tulip_open(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))
+ return -EAGAIN;
+
+ tulip_init_ring(dev);
+
+ tulip_up(dev);
+ tp->open = 1;
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+/* Set up the transceiver control registers for the selected media type. */
+static void select_media(struct net_device *dev, int startup)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ struct mediatable *mtable = tp->mtable;
+ u32 new_csr6;
+ int i;
+
+ if (mtable) {
+ struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
+ unsigned char *p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: /* 21140 non-MII xcvr. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+ " with control setting %2.2x.\n",
+ dev->name, p[1]);
+ dev->if_port = p[0];
+ if (startup)
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ outl(p[1], ioaddr + CSR12);
+ new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
+ break;
+ case 2: case 4: {
+ u16 setup[5];
+ u32 csr13val, csr14val, csr15dir, csr15val;
+ for (i = 0; i < 5; i++)
+ setup[i] = get_u16(&p[i*2 + 1]);
+
+ dev->if_port = p[0] & 15;
+ if (media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+
+ if (startup && mtable->has_reset) {
+ struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
+ unsigned char *rst = rleaf->leafdata;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
+ dev->name);
+ for (i = 0; i < rst[0]; i++)
+ outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
+ "%4.4x/%4.4x.\n",
+ dev->name, medianame[dev->if_port], setup[0], setup[1]);
+ if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
+ csr13val = setup[0];
+ csr14val = setup[1];
+ csr15dir = (setup[3]<<16) | setup[2];
+ csr15val = (setup[4]<<16) | setup[2];
+ outl(0, ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ outl(csr13val, ioaddr + CSR13);
+ } else {
+ csr13val = 1;
+ csr14val = 0x0003FF7F;
+ csr15dir = (setup[0]<<16) | 0x0008;
+ csr15val = (setup[1]<<16) | 0x0008;
+ if (dev->if_port <= 4)
+ csr14val = t21142_csr14[dev->if_port];
+ if (startup) {
+ outl(0, ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ }
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ if (startup) outl(csr13val, ioaddr + CSR13);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n",
+ dev->name, csr15dir, csr15val);
+ if (mleaf->type == 4)
+ new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
+ else
+ new_csr6 = 0x82420000;
+ break;
+ }
+ case 1: case 3: {
+ int phy_num = p[0];
+ int init_length = p[1];
+ u16 *misc_info;
+ u16 to_advertise;
+
+ dev->if_port = 11;
+ new_csr6 = 0x020E0000;
+ if (mleaf->type == 3) { /* 21142 */
+ u16 *init_sequence = (u16*)(p+2);
+ u16 *reset_sequence = &((u16*)(p+3))[init_length];
+ int reset_length = p[2 + init_length*2];
+ misc_info = reset_sequence + reset_length;
+ if (startup)
+ for (i = 0; i < reset_length; i++)
+ outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+ for (i = 0; i < init_length; i++)
+ outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+ } else {
+ u8 *init_sequence = p + 2;
+ u8 *reset_sequence = p + 3 + init_length;
+ int reset_length = p[2 + init_length];
+ misc_info = (u16*)(reset_sequence + reset_length);
+ if (startup) {
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ for (i = 0; i < reset_length; i++)
+ outl(reset_sequence[i], ioaddr + CSR12);
+ }
+ for (i = 0; i < init_length; i++)
+ outl(init_sequence[i], ioaddr + CSR12);
+ }
+ to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+ tp->advertising[phy_num] = to_advertise;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n",
+ dev->name, to_advertise, phy_num, tp->phys[phy_num]);
+ /* Bogus: put in by a committee? */
+ mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
+ break;
+ }
+ default:
+ printk(KERN_DEBUG "%s: Invalid media table selection %d.\n",
+ dev->name, mleaf->type);
+ new_csr6 = 0x020E0000;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12) & 0xff);
+ } else if (tp->chip_id == DC21041) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
+ dev->name, medianame[dev->if_port & 15],
+ inl(ioaddr + CSR12) & 0xffff);
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ new_csr6 = 0x80020000;
+ } else if (tp->chip_id == LC82C168 || tp->chip_id == PNIC2) {
+ if (startup && ! tp->medialock)
+ dev->if_port = tp->mii_cnt ? 11 : 0;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x,"
+ " media %s.\n",
+ dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
+ medianame[dev->if_port]);
+ if (tp->mii_cnt) {
+ new_csr6 = 0x810C0000;
+ outl(0x0001, ioaddr + CSR15);
+ outl(0x0201B07A, ioaddr + 0xB8);
+ } else if (startup) {
+ /* Start with 10mbps to do autonegotiation. */
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x0001B078, ioaddr + 0xB8);
+ outl(0x0201B078, ioaddr + 0xB8);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ if (startup)
+ outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */
+ else
+ outl(0x1F868, ioaddr + 0xB8);
+ } else {
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
+ }
+ } else if (tp->chip_id == DC21040) { /* 21040 */
+ /* Turn on the xcvr interface. */
+ int csr12 = inl(ioaddr + CSR12);
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ if (media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ new_csr6 = 0x20000;
+ /* Set the full duplux match frame. */
+ outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ if (t21040_csr13[dev->if_port] & 8) {
+ outl(0x0705, ioaddr + CSR14);
+ outl(0x0006, ioaddr + CSR15);
+ } else {
+ outl(0xffff, ioaddr + CSR14);
+ outl(0x0000, ioaddr + CSR15);
+ }
+ outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13);
+ } else if (tp->chip_id == X3201_3) { /* Xircom */
+ if (tp->default_port == 0)
+ dev->if_port = tp->mii_cnt ? 11 : 3;
+/* Someone is on crack, the Xircom only does MII, no Fx */
+/* if (media_cap[dev->if_port] & MediaIsMII) {
+ new_csr6 = 0x020E0000;
+ } else if (media_cap[dev->if_port] & MediaIsFx) {
+ new_csr6 = 0x028600000;
+ } else
+ new_csr6 = 0x038600000;*/
+ new_csr6 = 0x324c0000;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Xircom CardBus Adapter: "
+ "%s transceiver, CSR12 %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12));
+ } else { /* Unknown chip type with no media table. */
+ if (tp->default_port == 0)
+ dev->if_port = tp->mii_cnt ? 11 : 3;
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ new_csr6 = 0x020E0000;
+ } else if (media_cap[dev->if_port] & MediaIsFx) {
+ new_csr6 = 0x028600000;
+ } else
+ new_csr6 = 0x038600000;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No media description table, assuming "
+ "%s transceiver, CSR12 %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12));
+ }
+
+ tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+ return;
+}
+
+/*
+ Check the MII negotiated duplex, and change the CSR6 setting if
+ required.
+ Return 0 if everything is OK.
+ Return < 0 if the transceiver is missing or has no link beat.
+ */
+static int check_duplex(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int mii_reg1, mii_reg5, negotiated, duplex;
+
+ if (tp->full_duplex_lock)
+ return 0;
+ mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+ mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+ "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
+ if (mii_reg1 == 0xffff)
+ return -2;
+ if ((mii_reg1 & 0x0004) == 0) {
+ int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+ if ((new_reg1 & 0x0004) == 0) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: No link beat on the MII interface,"
+ " status %4.4x.\n", dev->name, new_reg1);
+ return -1;
+ }
+ }
+ negotiated = mii_reg5 & tp->advertising[0];
+ duplex = ((negotiated & 0x0300) == 0x0100
+ || (negotiated & 0x00C0) == 0x0040);
+ /* 100baseTx-FD or 10T-FD, but not 100-HD */
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ if (tp->full_duplex) tp->csr6 |= 0x0200;
+ else tp->csr6 &= ~0x0200;
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ if (tulip_debug > 0)
+ printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+ "#%d link partner capability of %4.4x.\n",
+ dev->name, tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ }
+ return 0;
+}
+
+static void tulip_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u32 csr12 = inl(ioaddr + CSR12);
+ int next_tick = 2*HZ;
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x "
+ "SIA %8.8x %8.8x %8.8x %8.8x.\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6),
+ csr12, inl(ioaddr + CSR13),
+ inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ }
+ switch (tp->chip_id) {
+ case DC21040:
+ if (!tp->medialock && csr12 & 0x0002) { /* Network error */
+ printk(KERN_INFO "%s: No link beat found.\n",
+ dev->name);
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ select_media(dev, 0);
+ dev->trans_start = jiffies;
+ }
+ break;
+ case DC21041:
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n",
+ dev->name, csr12);
+ switch (dev->if_port) {
+ case 0: case 3: case 4:
+ if (csr12 & 0x0004) { /*LnkFail */
+ /* 10baseT is dead. Check for activity on alternate port. */
+ tp->mediasense = 1;
+ if (csr12 & 0x0200)
+ dev->if_port = 2;
+ else
+ dev->if_port = 1;
+ printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
+ dev->name, medianame[dev->if_port]);
+ outl(0, ioaddr + CSR13); /* Reset */
+ outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ next_tick = 10*HZ; /* 2.4 sec. */
+ } else
+ next_tick = 30*HZ;
+ break;
+ case 1: /* 10base2 */
+ case 2: /* AUI */
+ if (csr12 & 0x0100) {
+ next_tick = (30*HZ); /* 30 sec. */
+ tp->mediasense = 0;
+ } else if ((csr12 & 0x0004) == 0) {
+ printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
+ dev->name);
+ dev->if_port = 0;
+ select_media(dev, 0);
+ next_tick = (24*HZ)/10; /* 2.4 sec. */
+ } else if (tp->mediasense || (csr12 & 0x0002)) {
+ dev->if_port = 3 - dev->if_port; /* Swap ports. */
+ select_media(dev, 0);
+ next_tick = 20*HZ;
+ } else {
+ next_tick = 20*HZ;
+ }
+ break;
+ }
+ break;
+ case DC21140: case DC21142: case MX98713: case COMPEX9881: default: {
+ struct medialeaf *mleaf;
+ unsigned char *p;
+ if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
+ /* Not much that can be done.
+ Assume this a generic MII or SYM transceiver. */
+ next_tick = 60*HZ;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+ "CSR12 0x%2.2x.\n",
+ dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+ break;
+ }
+ mleaf = &tp->mtable->mleaf[tp->cur_index];
+ p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: case 4: {
+ /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */
+ int offset = mleaf->type == 4 ? 5 : 2;
+ s8 bitnum = p[offset];
+ if (p[offset+1] & 0x80) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG"%s: Transceiver monitor tick "
+ "CSR12=%#2.2x, no media sense.\n",
+ dev->name, csr12);
+ if (mleaf->type == 4) {
+ if (mleaf->media == 3 && (csr12 & 0x02))
+ goto select_next_media;
+ }
+ break;
+ }
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+ " bit %d is %d, expecting %d.\n",
+ dev->name, csr12, (bitnum >> 1) & 7,
+ (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+ (bitnum >= 0));
+ /* Check that the specified bit has the proper value. */
+ if ((bitnum < 0) !=
+ ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+ medianame[mleaf->media]);
+ if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
+ goto actually_mii;
+ break;
+ }
+ if (tp->medialock)
+ break;
+ select_next_media:
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+ if (media_cap[dev->if_port] & MediaIsFD)
+ goto select_next_media; /* Skip FD entries. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No link beat on media %s,"
+ " trying transceiver type %s.\n",
+ dev->name, medianame[mleaf->media & 15],
+ medianame[tp->mtable->mleaf[tp->cur_index].media]);
+ select_media(dev, 0);
+ /* Restart the transmit process. */
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ next_tick = (24*HZ)/10;
+ break;
+ }
+ case 1: case 3: /* 21140, 21142 MII */
+ actually_mii:
+ check_duplex(dev);
+ next_tick = 60*HZ;
+ break;
+ case 2: /* 21142 serial block has no link beat. */
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+ of available transceivers. */
+static void t21142_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+ int next_tick = 60*HZ;
+ int new_csr6 = 0;
+
+ if ((tulip_debug > 2) && !(media_cap[dev->if_port] & MediaIsMII))
+ printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
+ dev->name, csr12, medianame[dev->if_port]);
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ check_duplex(dev);
+ next_tick = 60*HZ;
+ } else if (tp->nwayset) {
+ /* Don't screw up a negotiated session! */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ } else if (tp->medialock) {
+ ;
+ } else if (dev->if_port == 3) {
+ if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
+ "trying NWay.\n", dev->name, csr12);
+ t21142_start_nway(dev);
+ next_tick = 3*HZ;
+ }
+ } else if (((csr12 & 0x7000) != 0x5000)
+ && tp->chip_id != X3201_3) {
+ /* Negotiation failed. Search media types. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
+ dev->name, csr12);
+ if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ new_csr6 = 0x82420000;
+ dev->if_port = 0;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+ } else {
+ /* Select 100mbps port to check for link beat. */
+ new_csr6 = 0x83860000;
+ dev->if_port = 3;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outw(8, ioaddr + CSR15);
+ outl(1, ioaddr + CSR13);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+ tp->csr6 &= 0x00D5;
+ tp->csr6 |= new_csr6;
+ outl(0x0301, ioaddr + CSR12);
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ next_tick = 3*HZ;
+ }
+ if (tp->cur_tx - tp->dirty_tx > 0 &&
+ jiffies - dev->trans_start > TX_TIMEOUT) {
+ printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n",
+ dev->name, tp->cur_tx, tp->dirty_tx);
+ tulip_tx_timeout(dev);
+ }
+
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void t21142_start_nway(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr14 = ((tp->to_advertise & 0x0180) << 9) |
+ ((tp->to_advertise&0x0020)<<1) | 0xffbf;
+
+ dev->if_port = 0;
+ tp->nway = tp->mediasense = 1;
+ tp->nwayset = tp->lpar = 0;
+ if (debug > 1)
+ printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
+ dev->name, csr14);
+ outl(0x0001, ioaddr + CSR13);
+ outl(csr14, ioaddr + CSR14);
+ tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+ outl_CSR6(tp->csr6, ioaddr, tp->chip_id);
+ if (tp->mtable && tp->mtable->csr15dir) {
+ outl(tp->mtable->csr15dir, ioaddr + CSR15);
+ outl(tp->mtable->csr15val, ioaddr + CSR15);
+ } else
+ outw(0x0008, ioaddr + CSR15);
+ outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */
+}
+
+static void t21142_lnk_change(struct net_device *dev, int csr5)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
+ "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
+
+ /* If NWay finished and we have a negotiated partner capability. */
+ if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
+ int setup_done = 0;
+ tp->lpar = csr12 >> 16;
+ tp->nwayset = 1;
+ if (csr12 & 0x01000000) dev->if_port = 5;
+ else if (csr12 & 0x00800000) dev->if_port = 3;
+ else if (csr12 & 0x00400000) dev->if_port = 4;
+ else if (csr12 & 0x00200000) dev->if_port = 0;
+ else {
+ tp->nwayset = 0;
+ if ( ! (csr12 & 2)) dev->if_port = 3;
+ else if ( ! (csr12 & 4)) dev->if_port = 0;
+ }
+ tp->full_duplex = (media_cap[tp->default_port] & MediaAlwaysFD) ? 1:0;
+
+ if (tulip_debug > 1) {
+ if (tp->nwayset)
+ printk(KERN_INFO "%s: Switching to %s based on link partner "
+ "advertisement %4.4x.\n",
+ dev->name, medianame[dev->if_port], tp->lpar);
+ else
+ printk(KERN_INFO "%s: Switching to %s based on link beat "
+ "status of %4.4x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ }
+
+ if (tp->mtable) {
+ int i;
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == dev->if_port) {
+ tp->cur_index = i;
+ select_media(dev, 0);
+ setup_done = 1;
+ break;
+ }
+ }
+ if ( ! setup_done) {
+ tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
+ if (tp->full_duplex)
+ tp->csr6 |= 0x0200;
+ outw(0x0000, ioaddr + CSR13);
+ outw(0x0000, ioaddr + CSR14);
+ }
+ outl_CSR6(tp->csr6 | 0x0000, ioaddr, tp->chip_id);
+ if (debug > 2)
+ printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n",
+ dev->name, inl(ioaddr + CSR5));
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ } else if ((tp->nwayset && (csr5 & 0x08000000)
+ && (dev->if_port == 3 || dev->if_port == 5)
+ && (csr12 & 2) == 2) ||
+ (tp->nway && (csr5 & (TPLnkFail)))) {
+ /* Link blew? Maybe restart NWay. */
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
+ dev->name, medianame[dev->if_port],
+ (csr12 & 2) ? "failed" : "good");
+ if ((csr12 & 2) && ! tp->medialock) {
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ }
+ } else if (dev->if_port == 0 || dev->if_port == 4) {
+ if ((csr12 & 4) == 0)
+ printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
+ dev->name);
+ } else if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
+ dev->name);
+ dev->if_port = 0;
+ } else if (tp->nwayset) {
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
+ dev->name, medianame[dev->if_port], tp->csr6);
+ } else { /* 100mbps link beat good. */
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
+ dev->name);
+ dev->if_port = 3;
+ tp->csr6 = 0x83860000;
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outl(0x0301, ioaddr + CSR12);
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+}
+
+static void mxic_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 3) {
+ printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+ inl(ioaddr + CSR12));
+ }
+ if (next_tick) {
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+ }
+}
+
+static void pnic_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+ int next_tick = 60*HZ;
+ int new_csr6 = tp->csr6 & ~0x40C40200;
+
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC negotiated capability %8.8x, "
+ "CSR5 %8.8x.\n",
+ dev->name, negotiated, inl(ioaddr + CSR5));
+
+ if (negotiated & 0x0380) /* 10 vs 100mbps */
+ new_csr6 |= 0x810E0000;
+ else
+ new_csr6 |= 0x814E0000;
+ if (((negotiated & 0x0300) == 0x0100) /* Duplex */
+ || (negotiated & 0x00C0) == 0x0040
+ || tp->full_duplex_lock) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x0200;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC MII PHY status %4.4x, Link "
+ "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
+ dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
+ tp->csr6, inl(ioaddr + CSR6));
+ } else {
+ int phy_reg = inl(ioaddr + 0xB8);
+ int csr5 = inl(ioaddr + CSR5);
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC PHY status %8.8x, CSR5 %8.8x.\n",
+ dev->name, phy_reg, csr5);
+
+ if (phy_reg & 0x04000000) { /* Remote link fault */
+ /*outl(0x0201F078, ioaddr + 0xB8);*/
+ next_tick = 3*HZ;
+ }
+ if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+ "CSR5 %8.8x, PHY %3.3x.\n",
+ dev->name, medianame[dev->if_port], csr12,
+ inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+ if (tp->medialock) {
+ } else if (dev->if_port == 0) {
+ dev->if_port = 3;
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ outl(0x1F868, ioaddr + 0xB8);
+ } else {
+ dev->if_port = 0;
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
+ }
+ new_csr6 |= (tp->csr6 & 0xfdff);
+ next_tick = 3*HZ;
+ } else
+ new_csr6 = tp->csr6;
+ if (tp->full_duplex_lock || (phy_reg & 0x30000000) != 0) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x00000200;
+ }
+ }
+ if (tp->csr6 != new_csr6) {
+ tp->csr6 = new_csr6;
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); /* Restart Tx */
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ dev->trans_start = jiffies;
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
+ "CSR6 %8.8x.\n",
+ dev->name, tp->full_duplex ? "full" : "half", new_csr6);
+ }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void comet_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
+ "%4.4x.\n",
+ dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void tulip_tx_timeout(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ /* Do nothing -- the media monitor should handle this. */
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+ dev->name);
+ } else if (tp->chip_id == DC21040) {
+ if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) {
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ printk(KERN_INFO "%s: transmit timed out, switching to "
+ "%s.\n",
+ dev->name, medianame[dev->if_port]);
+ select_media(dev, 0);
+ }
+ dev->trans_start = jiffies;
+ return;
+ } else if (tp->chip_id == DC21041) {
+ int csr12 = inl(ioaddr + CSR12);
+
+ printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
+ "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), csr12,
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+ tp->mediasense = 1;
+ if ( ! tp->medialock) {
+ if (dev->if_port == 1 || dev->if_port == 2)
+ if (csr12 & 0x0004) {
+ dev->if_port = 2 - dev->if_port;
+ } else
+ dev->if_port = 0;
+ else
+ dev->if_port = 1;
+ select_media(dev, 0);
+ }
+ } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+ || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
+ printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ if ( ! tp->medialock && tp->mtable) {
+ do
+ --tp->cur_index;
+ while (tp->cur_index >= 0
+ && (media_cap[tp->mtable->mleaf[tp->cur_index].media]
+ & MediaIsFD));
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ select_media(dev, 0);
+ printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+ "media.\n", dev->name, medianame[dev->if_port]);
+ }
+ } else {
+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
+ "%8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+ dev->if_port = 0;
+ }
+
+#if defined(way_too_many_messages)
+ if (tulip_debug > 3) {
+ int i;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
+ int j;
+ printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x "
+ "%2.2x %2.2x %2.2x.\n",
+ i, (unsigned int)tp->rx_ring[i].status,
+ (unsigned int)tp->rx_ring[i].length,
+ (unsigned int)tp->rx_ring[i].buffer1,
+ (unsigned int)tp->rx_ring[i].buffer2,
+ buf[0], buf[1], buf[2]);
+ for (j = 0; buf[j] != 0xee && j < 1600; j++)
+ if (j < 100) printk(" %2.2x", buf[j]);
+ printk(" j=%d.\n", j);
+ }
+ printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+ printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+ printk("\n");
+ }
+#endif
+
+ /* Stop and restart the chip's Tx processes . */
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
+
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+ tp->stats.tx_errors++;
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void tulip_init_ring(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+
+ tp->tx_full = 0;
+ tp->cur_rx = tp->cur_tx = 0;
+ tp->dirty_rx = tp->dirty_tx = 0;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ tp->rx_ring[i].status = 0x00000000;
+ tp->rx_ring[i].length = PKT_BUF_SZ;
+ tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
+ tp->rx_skbuff[i] = NULL;
+ }
+ /* Mark the last entry as wrapping the ring. */
+ tp->rx_ring[i-1].length = PKT_BUF_SZ | DESC_RING_WRAP;
+ tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ /* Note the receive buffer must be longword aligned.
+ dev_alloc_skb() provides 16 byte alignment. But do *not*
+ use skb_reserve() to align the IP header! */
+ struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+ tp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[i].status = DescOwned; /* Owned by Tulip chip */
+ tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
+ }
+ tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+ /* The Tx buffer descriptor is filled in as needed, but we
+ do need to clear the ownership bit. */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ tp->tx_skbuff[i] = 0;
+ tp->tx_ring[i].status = 0x00000000;
+ tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
+#ifdef CARDBUS
+ if (tp->chip_id == X3201_3)
+ tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
+#endif CARDBUS
+ }
+ tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
+}
+
+static int
+tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry;
+ u32 flag;
+
+ /* Caution: the write order is important here, set the base address
+ with the "ownership" bits last. */
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = tp->cur_tx % TX_RING_SIZE;
+
+ tp->tx_skbuff[entry] = skb;
+#ifdef CARDBUS
+ if (tp->chip_id == X3201_3) {
+ memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
+ tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
+ } else
+#endif
+ tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+
+ if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+ flag = 0x60000000; /* No interrupt */
+ } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+ flag = 0xe0000000; /* Tx-done intr. */
+ } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+ flag = 0x60000000; /* No Tx-done intr. */
+ } else {
+ /* Leave room for set_rx_mode() to fill entries. */
+ flag = 0xe0000000; /* Tx-done intr. */
+ tp->tx_full = 1;
+ }
+ if (entry == TX_RING_SIZE-1)
+ flag |= 0xe0000000 | DESC_RING_WRAP;
+
+ tp->tx_ring[entry].length = skb->len | flag;
+ tp->tx_ring[entry].status = DescOwned; /* Pass ownership to the chip. */
+ tp->cur_tx++;
+ if (tp->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
+
+ /* Trigger an immediate transmit demand. */
+ outl(0, dev->base_addr + CSR1);
+
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *)dev_instance;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr5, work_budget = max_interrupt_work;
+
+ spin_lock (&tp->lock);
+
+ do {
+ csr5 = inl(ioaddr + CSR5);
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
+ dev->name, csr5, inl(dev->base_addr + CSR5));
+
+ if (csr5 == 0xffffffff)
+ break; /* all bits set, assume PCMCIA card removed */
+
+ if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
+ break;
+
+ if (csr5 & (RxIntr | RxNoBuf))
+ work_budget -= tulip_rx(dev);
+
+ if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+ unsigned int dirty_tx;
+
+ for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+ dirty_tx++) {
+ int entry = dirty_tx % TX_RING_SIZE;
+ int status = tp->tx_ring[entry].status;
+
+ if (status < 0)
+ break; /* It still hasn't been Txed */
+ /* Check for Rx filter setup frames. */
+ if (tp->tx_skbuff[entry] == NULL)
+ continue;
+
+ if (status & 0x8000) {
+ /* There was an major error, log it. */
+#ifndef final_version
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, status);
+#endif
+ tp->stats.tx_errors++;
+ if (status & 0x4104) tp->stats.tx_aborted_errors++;
+ if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+ if (status & 0x0200) tp->stats.tx_window_errors++;
+ if (status & 0x0002) tp->stats.tx_fifo_errors++;
+ if ((status & 0x0080) && tp->full_duplex == 0)
+ tp->stats.tx_heartbeat_errors++;
+#ifdef ETHER_STATS
+ if (status & 0x0100) tp->stats.collisions16++;
+#endif
+ } else {
+#ifdef ETHER_STATS
+ if (status & 0x0001) tp->stats.tx_deferred++;
+#endif
+ tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+ tp->stats.collisions += (status >> 3) & 15;
+ tp->stats.tx_packets++;
+ }
+
+ /* Free the original skb. */
+ dev_kfree_skb_irq(tp->tx_skbuff[entry]);
+ tp->tx_skbuff[entry] = 0;
+ }
+
+#ifndef final_version
+ if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
+ printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+ dirty_tx += TX_RING_SIZE;
+ }
+#endif
+
+ if (tp->tx_full &&
+ tp->cur_tx - dirty_tx < TX_RING_SIZE - 2)
+ /* The ring is no longer full */
+ tp->tx_full = 0;
+
+ if (tp->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
+
+ tp->dirty_tx = dirty_tx;
+ if (csr5 & TxDied) {
+ if (tulip_debug > 2)
+ printk(KERN_WARNING "%s: The transmitter stopped."
+ " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
+ dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ }
+
+ /* Log errors. */
+ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
+ if (csr5 == 0xffffffff)
+ break;
+ if (csr5 & TxJabber) tp->stats.tx_errors++;
+ if (csr5 & TxFIFOUnderflow) {
+ if ((tp->csr6 & 0xC000) != 0xC000)
+ tp->csr6 += 0x4000; /* Bump up the Tx threshold */
+ else
+ tp->csr6 |= 0x00200000; /* Store-n-forward. */
+ /* Restart the transmit process. */
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ if (csr5 & RxDied) { /* Missed a Rx frame. */
+ tp->stats.rx_errors++;
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ if (csr5 & TimerInt) {
+ if (tulip_debug > 2)
+ printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+ dev->name, csr5);
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+ }
+ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
+ if ( tp->chip_id == DC21142)
+ t21142_lnk_change(dev, csr5);
+ }
+ /* Clear all error sources, included undocumented ones! */
+ outl(0x0800f7ba, ioaddr + CSR5);
+ }
+ if (--work_budget < 0) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Too much work during an interrupt, "
+ "csr5=0x%8.8x.\n", dev->name, csr5);
+ /* Acknowledge all interrupt sources. */
+ outl(0x8001ffff, ioaddr + CSR5);
+#ifdef notdef
+ /* Clear all but standard interrupt sources. */
+ outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#endif
+ break;
+ }
+ } while (1);
+
+ if (tulip_debug > 3)
+ printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
+ dev->name, inl(ioaddr + CSR5));
+
+ spin_unlock (&tp->lock);
+}
+
+static int
+tulip_rx(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry = tp->cur_rx % RX_RING_SIZE;
+ int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+ int work_done = 0;
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+ tp->rx_ring[entry].status);
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while (tp->rx_ring[entry].status >= 0) {
+ s32 status = tp->rx_ring[entry].status;
+
+ if (tulip_debug > 5)
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+ tp->rx_ring[entry].status);
+ if (--rx_work_limit < 0)
+ break;
+ if ((status & 0x38008300) != 0x0300) {
+ if ((status & 0x38000300) != 0x0300) {
+ /* Ingore earlier buffers. */
+ if ((status & 0xffff) != 0x7fff) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Oversized Ethernet frame "
+ "spanned multiple buffers, status %8.8x!\n",
+ dev->name, status);
+ tp->stats.rx_length_errors++;
+ }
+ } else if (status & RxDescFatalErr) {
+ /* There was a fatal error. */
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+ dev->name, status);
+ tp->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x0890) tp->stats.rx_length_errors++;
+ if (status & 0x0004) tp->stats.rx_frame_errors++;
+ if (status & 0x0002) tp->stats.rx_crc_errors++;
+ if (status & 0x0001) tp->stats.rx_fifo_errors++;
+ }
+ } else {
+ /* Omit the four octet CRC from the length. */
+ short pkt_len = ((status >> 16) & 0x7ff) - 4;
+ struct sk_buff *skb;
+
+#ifndef final_version
+ if (pkt_len > 1518) {
+ printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
+ dev->name, pkt_len, pkt_len);
+ pkt_len = 1518;
+ tp->stats.rx_length_errors++;
+ }
+#endif
+ /* Check if the packet is long enough to accept without copying
+ to a minimally-sized skbuff. */
+ if (pkt_len < rx_copybreak
+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align the IP header */
+#if ! defined(__alpha__)
+ eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+ pkt_len, 0);
+ skb_put(skb, pkt_len);
+#else
+ memcpy(skb_put(skb, pkt_len),
+ bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
+#endif
+ work_done++;
+ } else { /* Pass up the skb already on the Rx ring. */
+ char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
+ tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+ if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+ "do not match in tulip_rx: %p vs. %p / %p.\n",
+ dev->name, bus_to_virt(tp->rx_ring[entry].buffer1),
+ skb->head, temp);
+#endif
+ }
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ tp->stats.rx_packets++;
+ tp->stats.rx_bytes += pkt_len;
+ }
+ entry = (++tp->cur_rx) % RX_RING_SIZE;
+ }
+
+ /* Refill the Rx ring buffers. */
+ for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+ entry = tp->dirty_rx % RX_RING_SIZE;
+ if (tp->rx_skbuff[entry] == NULL) {
+ struct sk_buff *skb;
+ skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+ work_done++;
+ }
+ tp->rx_ring[entry].status = DescOwned;
+ }
+
+ return work_done;
+}
+
+static void
+tulip_down(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ outl(0x00000000, ioaddr + CSR7);
+ /* Stop the chip's Tx and Rx processes. */
+ outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, tp->chip_id);
+ /* 21040 -- Leave the card in 10baseT state. */
+ if (tp->chip_id == DC21040)
+ outl(0x00000004, ioaddr + CSR13);
+
+ if (inl(ioaddr + CSR6) != 0xffffffff)
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+ dev->if_port = tp->saved_if_port;
+}
+
+static int
+tulip_close(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, inl(ioaddr + CSR5));
+
+ netif_stop_queue(dev);
+
+ if (netif_device_present(dev))
+ tulip_down(dev);
+
+ del_timer(&tp->timer);
+
+ free_irq(dev->irq, dev);
+
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = tp->rx_skbuff[i];
+ tp->rx_skbuff[i] = 0;
+ tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */
+ tp->rx_ring[i].length = 0;
+ tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+ if (skb) {
+ dev_kfree_skb(skb);
+ }
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (tp->tx_skbuff[i])
+ dev_kfree_skb(tp->tx_skbuff[i]);
+ tp->tx_skbuff[i] = 0;
+ }
+
+ MOD_DEC_USE_COUNT;
+ tp->open = 0;
+ return 0;
+}
+
+static struct net_device_stats *tulip_get_stats(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+
+ if (netif_device_present(dev))
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+ return &tp->stats;
+}
+
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u16 *data = (u16 *)&rq->ifr_data;
+ int phy = tp->phys[0] & 0x1f;
+ long flags;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ if (tp->mii_cnt)
+ data[0] = phy;
+ else if (tp->chip_id == DC21142) /* 21142 pseudo-MII */
+ data[0] = 32;
+ else if (tp->chip_id == PNIC2)
+ data[0] = 32;
+ else if (tp->chip_id == COMET)
+ data[0] = 1;
+ else
+ return -ENODEV;
+ return 0;
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ if (data[0] == 32 &&
+ (tp->chip_id == DC21142 || tp->chip_id == PNIC2)) {
+ int csr12 = inl(ioaddr + CSR12);
+ int csr14 = inl(ioaddr + CSR14);
+ switch (data[1]) {
+ case 0: {
+ data[3] = (csr14<<5) & 0x1000;
+ break; }
+ case 1:
+ data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+ + (csr12&0x06 ? 0x04 : 0);
+ break;
+ case 4: {
+ data[3] = ((csr14>>9)&0x0380) +
+ ((inl(ioaddr + CSR6)>>3)&0x0040) +((csr14>>1)&0x20) + 1;
+ break;
+ }
+ case 5: data[3] = csr12 >> 16; break;
+ default: data[3] = 0; break;
+ }
+ } else {
+ save_flags(flags);
+ cli();
+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+ restore_flags(flags);
+ }
+ return 0;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+#if defined(CAP_NET_ADMIN)
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+#else
+ if (!suser())
+ return -EPERM;
+#endif
+ if (data[0] == 32 && tp->chip_id == DC21142) {
+ if (data[1] == 5)
+ tp->to_advertise = data[2];
+ } else {
+ save_flags(flags);
+ cli();
+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ restore_flags(flags);
+ }
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return -EOPNOTSUPP;
+}
+#endif /* HAVE_PRIVATE_IOCTL */
+
+/* Set or clear the multicast filter for this adaptor.
+ Note that we only use exclusion around actually queueing the
+ new frame, not around filling tp->setup_frame. This is non-deterministic
+ when re-entered but still correct. */
+
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+ N.B. Do not use for bulk data, use a table-based routine instead.
+ This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline u32 ether_crc_le(int length, unsigned char *data)
+{
+ u32 crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+ int crc = -1;
+
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^
+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+ }
+ return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ tp->csr6 &= ~0x00D5;
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ tp->csr6 |= 0x00C0;
+ csr6 |= 0x00C0;
+ /* Unconditionally log net taps. */
+ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter well -- accept all multicasts. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) {
+ /* Some work-alikes have only a 64-entry hash filter table. */
+ /* Should verify correctness on big-endian/__powerpc__ */
+ struct dev_mc_list *mclist;
+ int i;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else {
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
+ if (tp->chip_id == AX88140) {
+ outl(2, ioaddr + CSR13);
+ outl(mc_filter[0], ioaddr + CSR14);
+ outl(3, ioaddr + CSR13);
+ outl(mc_filter[1], ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
+ outl(mc_filter[0], ioaddr + 0xAC);
+ outl(mc_filter[1], ioaddr + 0xB0);
+ }
+ }
+ } else {
+ u16 *eaddrs, *setup_frm = tp->setup_frame;
+ struct dev_mc_list *mclist;
+ u32 tx_flags = 0x08000000 | 192;
+ int i;
+
+ /* Note that only the low-address shortword of setup_frame is valid!
+ The values are doubled for big-endian architectures. */
+ if ((dev->mc_count > 14) || ((dev->mc_count > 6) && (tp->chip_id == X3201_3))) { /* Must use a multicast hash table. */
+ u16 hash_table[32];
+ tx_flags = 0x08400000 | 192; /* Use hash filter. */
+ memset(hash_table, 0, sizeof(hash_table));
+ set_bit(255, hash_table); /* Broadcast entry */
+ /* This should work on big-endian machines as well. */
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+ hash_table);
+ for (i = 0; i < 32; i++) {
+ *setup_frm++ = hash_table[i];
+ *setup_frm++ = hash_table[i];
+ }
+ setup_frm = &tp->setup_frame[13*6];
+ } else if(tp->chip_id != X3201_3) {
+ /* We have <= 14 addresses so we can use the wonderful
+ 16 address perfect filtering of the Tulip. */
+ for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+ /* Fill the unused entries with the broadcast address. */
+ memset(setup_frm, 0xff, (15-i)*12);
+ setup_frm = &tp->setup_frame[15*6];
+ } else {
+ /* fill the first two table entries with our address */
+ eaddrs = (u16 *)dev->dev_addr;
+ for(i=0; i<2; i++) {
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+ /* Double fill each entry to accomodate chips that */
+ /* don't like to parse these correctly */
+ for (i=0, mclist=dev->mc_list; i<dev->mc_count;
+ i++, mclist=mclist->next) {
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+ i=((i+1)*2);
+ /* Fill the unused entries with the broadcast address. */
+ memset(setup_frm, 0xff, (15-i)*12);
+ setup_frm = &tp->setup_frame[15*6];
+ }
+
+ /* Fill the final entry with our physical address. */
+ eaddrs = (u16 *)dev->dev_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ /* Now add this frame to the Tx list. */
+ if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
+ /* Same setup recently queued, we need not add it. */
+ } else {
+ unsigned long flags;
+ unsigned int entry, dummy = -1;
+
+ save_flags(flags); cli();
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+
+ if (entry != 0) {
+ /* Avoid a chip errata by prefixing a dummy entry. */
+ tp->tx_skbuff[entry] = 0;
+ tp->tx_ring[entry].length =
+ (entry == TX_RING_SIZE-1) ? DESC_RING_WRAP : 0;
+ tp->tx_ring[entry].buffer1 = 0;
+ /* race with chip, set DescOwned later */
+ dummy = entry;
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+ }
+
+ tp->tx_skbuff[entry] = 0;
+ /* Put the setup frame on the Tx list. */
+ if (entry == TX_RING_SIZE-1)
+ tx_flags |= DESC_RING_WRAP; /* Wrap ring. */
+ tp->tx_ring[entry].length = tx_flags;
+ if(tp->chip_id == X3201_3)
+ tp->tx_ring[entry].buffer1 = (virt_to_bus(tp->setup_frame) + 4);
+ else
+ tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
+ tp->tx_ring[entry].status = DescOwned;
+ if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
+ tp->tx_full = 1;
+ netif_stop_queue (dev);
+ }
+ if (dummy >= 0)
+ tp->tx_ring[dummy].status = DescOwned;
+ restore_flags(flags);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
+ }
+ }
+ outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id);
+}
+
+static struct pci_device_id tulip_pci_table[] __devinitdata = {
+#if 0 /* these entries conflict with regular tulip driver */
+ { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
+ { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
+ { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 },
+ { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
+ { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
+ { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
+ { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
+ { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
+#endif
+ { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+ {0},
+};
+
+MODULE_DEVICE_TABLE(pci, tulip_pci_table);
+
+static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct net_device *dev;
+ static int board_idx = 0;
+
+ printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
+
+ pci_enable_device (pdev);
+ pci_set_master (pdev);
+ dev = tulip_probe1(pdev, NULL,
+ pci_resource_start (pdev, 0), pdev->irq,
+ id->driver_data, board_idx++);
+ if (dev) {
+ pdev->driver_data = dev;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static void tulip_suspend(struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ printk(KERN_INFO "tulip_suspend(%s)\n", dev->name);
+ if (tp->open) tulip_down(dev);
+}
+
+static void tulip_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ printk(KERN_INFO "tulip_resume(%s)\n", dev->name);
+ if (tp->open) tulip_up(dev);
+}
+
+static void __devexit tulip_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ printk(KERN_INFO "tulip_detach(%s)\n", dev->name);
+ unregister_netdev(dev);
+ kfree(dev);
+ kfree(tp);
+}
+
+static struct pci_driver tulip_ops = {
+ name: "tulip_cb",
+ id_table: tulip_pci_table,
+ probe: tulip_pci_probe,
+ remove: tulip_remove,
+ suspend: tulip_suspend,
+ resume: tulip_resume
+};
+
+static int __init tulip_init(void)
+{
+ pci_register_driver(&tulip_ops);
+ return 0;
+}
+
+static __exit void tulip_exit(void)
+{
+ pci_unregister_driver(&tulip_ops);
+}
+
+module_init(tulip_init)
+module_exit(tulip_exit)
+
+
+/*
+ * Local variables:
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 64fafa17f..6508c56c2 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -1325,7 +1325,7 @@ static void __exit plip_cleanup_module (void)
static int parport_ptr = 0;
-static void __init plip_setup(char *str)
+static int __init plip_setup(char *str)
{
int ints[4];
@@ -1350,6 +1350,7 @@ static void __init plip_setup(char *str)
ints[1]);
}
}
+ return 1;
}
__setup("plip=", plip_setup);
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 8e8236e92..8ad1a2a16 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1650,6 +1650,6 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/*
* Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
+ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
* End:
*/
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 213905c3a..c7cb98318 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.c,v 1.16 2000/03/26 22:57:54 ralf Exp $
+/* $Id: sgiseeq.c,v 1.17 2000/03/27 23:02:57 ralf Exp $
*
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
@@ -32,6 +32,7 @@
#include <linux/skbuff.h>
#include <asm/sgi/sgihpc.h>
+#include <asm/sgi/sgint23.h>
#include <asm/sgialib.h>
#include "sgiseeq.h"
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index c3a552b43..41e15ff36 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -485,20 +485,24 @@ static void shaper_cache_update(struct hh_cache *hh, struct net_device *dev,
static int shaper_neigh_setup(struct neighbour *n)
{
+#ifdef CONFIG_INET
if (n->nud_state == NUD_NONE) {
n->ops = &arp_broken_ops;
n->output = n->ops->output;
}
+#endif
return 0;
}
static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
{
+#ifdef CONFIG_INET
if (p->tbl->family == AF_INET) {
p->neigh_setup = shaper_neigh_setup;
p->ucast_probes = 0;
p->mcast_probes = 0;
}
+#endif
return 0;
}
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index de0856020..5036b01af 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -12,10 +12,16 @@
Support and updates available at
http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html
+
+ LK1.1.1 (jgarzik):
+ - Use PCI driver interface
+ - Fix MOD_xxx races
+ - softnet fixups
+
*/
static const char *versionA =
-"starfire.c:v0.12 5/28/99 Written by Donald Becker\n",
+"starfire.c:v0.12+LK1.1.1 3/19/2000 Written by Donald Becker and others\n",
*versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n";
/* A few user-configurable values. These may be modified when a driver
@@ -26,7 +32,6 @@ static int interrupt_mitigation = 0x0;
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
static int mtu = 0;
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
The Starfire has a 512 element hash table based on the Ethernet CRC. */
@@ -62,6 +67,9 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+#define PFX "starfire: "
+
+
#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
#warning You must compile this file with the correct options!
#warning See the last lines of the source file.
@@ -94,7 +102,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(min_pci_latency, "i");
MODULE_PARM(mtu, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
@@ -196,38 +203,33 @@ enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, flags;
- int io_size;
- struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-
-static struct net_device *starfire_probe1(struct pci_dev *pdev, int pci_bus,
- int pci_devfn, long ioaddr,
- int irq, int chp_idx, int fnd_cnt);
#if 0
#define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */
#endif
#define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */
-static struct pci_id_info pci_tbl[] = {
- { "Adaptec Starfire 6915",
- 0x9004, 0x6915, 0xffff, PCI_USES_MASTER, 128, starfire_probe1},
- {0,}, /* 0 terminated list. */
+
+enum chipset {
+ CH_6915 = 0,
};
-/* A chip capabilities table, matching the entries in pci_tbl[] above. */
+static struct pci_device_id starfire_pci_tbl[] __devinitdata = {
+ { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
+
+
+/* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */
enum chip_capability_flags {CanHaveMII=1, };
-struct chip_info {
+static struct chip_info {
char *chip_name;
int io_size;
int flags;
- void (*media_timer)(unsigned long data);
-} static skel_netdrv_tbl[] = {
- {"Adaptec Starfire 6915", 128, CanHaveMII, 0, },
+} netdrv_tbl[] = {
+ { "Adaptec Starfire 6915", 128, CanHaveMII },
};
@@ -322,8 +324,6 @@ struct netdev_private {
struct starfire_tx_desc *tx_ring;
dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma;
- struct net_device *next_module; /* Link for devices of this type. */
- const char *product_name;
/* The addresses of rx/tx-in-place skbuffs. */
struct ring_info rx_info[RX_RING_SIZE];
struct ring_info tx_info[TX_RING_SIZE];
@@ -340,7 +340,6 @@ struct netdev_private {
/* Frequently used values: keep some adjacent for cache effect. */
int chip_id;
struct pci_dev *pdev;
- unsigned char pci_bus, pci_devfn;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
@@ -378,107 +377,62 @@ static struct net_device_stats *get_stats(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev);
-
-/* A list of our installed devices, for removing the driver module. */
-static struct net_device *root_net_dev = NULL;
-
-/* Ideally we would detect all network cards in slot order. That would
- be best done a central PCI probe dispatch, which wouldn't work
- well when dynamically adding drivers. So instead we detect just the
- cards we know about in slot order. */
-
-static int pci_etherdev_probe(struct pci_id_info pci_tbl[])
+static int __devinit starfire_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int cards_found = 0;
- int pci_index = 0;
- unsigned char pci_bus, pci_device_fn;
+ struct netdev_private *np;
+ int i, irq, option, chip_id = ent->driver_data;
struct net_device *dev;
-
- for (;pci_index < 0xff; pci_index++) {
- struct pci_dev *pdev;
- u16 vendor, device, pci_command, new_command;
- int chip_idx, irq;
- long pciaddr;
- long ioaddr;
-
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
- &pci_bus, &pci_device_fn)
- != PCIBIOS_SUCCESSFUL)
- break;
- pdev = pci_find_slot (pci_bus, pci_device_fn);
- if (!pdev) continue;
- vendor = pdev->vendor;
- device = pdev->device;
-
- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == pci_tbl[chip_idx].vendor_id
- && (device & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
- continue;
-
- pciaddr = pdev->resource[0].start;
-#if defined(ADDR_64BITS) && defined(__alpha__)
- pciaddr |= ((long)pdev->base_address[1]) << 32;
-#endif
- irq = pdev->irq;
-
- if (debug > 2)
- printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
- pci_tbl[chip_idx].name, pciaddr, irq);
-
- if ((pci_tbl[chip_idx].flags & PCI_USES_IO)) {
- if (check_region(pciaddr, pci_tbl[chip_idx].io_size))
- continue;
- ioaddr = pciaddr;
- } else if ((ioaddr = (long)ioremap(pciaddr&~0xf, MEM_ADDR_SZ)) == 0) {
- printk(KERN_INFO "Failed to map PCI address %#lx.\n",
- pciaddr);
- continue;
- }
-
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled the"
- " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
- pci_bus, pci_device_fn, pci_command, new_command);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
-
- dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr,
- irq, chip_idx, cards_found);
-
- if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
- u8 pci_latency;
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < min_pci_latency) {
- printk(KERN_INFO " PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to %d clocks.\n",
- pci_latency, min_pci_latency);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency);
- }
- }
- cards_found++;
+ static int card_idx = 0;
+ static int printed_version = 0;
+ long ioaddr;
+ int io_size = netdrv_tbl[chip_id].io_size;
+
+ ioaddr = pci_resource_start (pdev, 0);
+ if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
+ printk (KERN_ERR PFX "no PCI MEM resources, aborting\n");
+ return -ENODEV;
+ }
+
+ dev = init_etherdev(NULL, sizeof(*np));
+ if (!dev) {
+ printk (KERN_ERR PFX "cannot alloc etherdev, aborting\n");
+ return -ENOMEM;
+ }
+
+ irq = pdev->irq;
+
+ if (request_mem_region (ioaddr, io_size, dev->name) == NULL) {
+ printk (KERN_ERR PFX "resource 0x%x @ 0x%lx busy, aborting\n",
+ io_size, ioaddr);
+ goto err_out_free_netdev;
+ }
+
+ if (pci_enable_device (pdev)) {
+ printk (KERN_ERR PFX "cannot enable PCI device, aborting\n");
+ goto err_out_free_res;
+ }
+
+ ioaddr = (long) ioremap (ioaddr, io_size);
+ if (!ioaddr) {
+ printk (KERN_ERR PFX "cannot remap 0x%x @ 0x%lx, aborting\n",
+ io_size, ioaddr);
+ goto err_out_free_res;
}
- return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device *
-starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_id, int card_idx)
-{
- struct netdev_private *np;
- int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
- struct net_device *dev = init_etherdev(NULL, 0);
-
- if (!dev)
- return NULL;
+ pci_set_master (pdev);
+
+ option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+ card_idx++;
+
+ if (!printed_version) {
+ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printed_version = 1;
+ }
- printk(KERN_INFO "%s: %s at 0x%lx, ",
- dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
+ printk (KERN_INFO "%s: %s at 0x%lx, ",
+ dev->name, netdrv_tbl[chip_id].chip_name, ioaddr);
/* Serial EEPROM reads are hidden by the hardware. */
for (i = 0; i < 6; i++)
@@ -500,18 +454,13 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
dev->base_addr = ioaddr;
dev->irq = irq;
- /* Make certain the descriptor lists are aligned. */
- np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 15) & ~15);
- memset(np, 0, sizeof(*np));
- dev->priv = np;
-
- np->next_module = root_net_dev;
- root_net_dev = dev;
+ /* private struct aligned and zeroed by init_etherdev */
+ np = dev->priv;
np->pdev = pdev;
- np->pci_bus = pci_bus;
- np->pci_devfn = pci_devfn;
np->chip_id = chip_id;
+
+ pdev->driver_data = dev;
if (dev->mem_start)
option = dev->mem_start;
@@ -533,7 +482,7 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
/* The chip-specific entries in the device structure. */
dev->open = &netdev_open;
dev->hard_start_xmit = &start_tx;
- dev->tx_timeout = tx_timeout;
+ dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->stop = &netdev_close;
dev->get_stats = &get_stats;
@@ -543,7 +492,7 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
if (mtu)
dev->mtu = mtu;
- if (skel_netdrv_tbl[np->chip_id].flags & CanHaveMII) {
+ if (netdrv_tbl[np->chip_id].flags & CanHaveMII) {
int phy, phy_idx = 0;
for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
int mii_status = mdio_read(dev, phy, 1);
@@ -558,7 +507,14 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
np->mii_cnt = phy_idx;
}
- return dev;
+ return 0;
+
+err_out_free_res:
+ release_mem_region (ioaddr, io_size);
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+ return -ENODEV;
}
@@ -590,10 +546,13 @@ static int netdev_open(struct net_device *dev)
long ioaddr = dev->base_addr;
int i;
+ MOD_INC_USE_COUNT;
/* Do we need to reset the chip??? */
- if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
- return -EAGAIN;
+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
/* Disable the Rx and Tx, and reset the chip. */
writel(0, ioaddr + GenCtrl);
@@ -624,11 +583,10 @@ static int netdev_open(struct net_device *dev)
if (np->rx_ring)
pci_free_consistent(np->pdev, PAGE_SIZE,
np->rx_ring, np->rx_ring_dma);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
- MOD_INC_USE_COUNT;
-
init_ring(dev);
/* Set the size of the Rx buffers. */
writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl);
@@ -691,6 +649,8 @@ static int netdev_open(struct net_device *dev)
/* Enable the Rx and Tx units. */
writel(0x000F, ioaddr + GenCtrl);
+ netif_start_queue(dev);
+
if (debug > 2)
printk(KERN_DEBUG "%s: Done netdev_open().\n",
dev->name);
@@ -762,6 +722,7 @@ static void netdev_timer(unsigned long data)
add_timer(&np->timer);
}
+
static void tx_timeout(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -783,15 +744,16 @@ static void tx_timeout(struct net_device *dev)
}
#endif
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
+ /* Perhaps we should reinitialize the hardware here. */
+ dev->if_port = 0;
+
+ /* Stop and restart the chip's Tx processes . */
+ /* XXX todo */
- /* Trigger an immediate transmit demand. */
+ /* Trigger an immediate transmit demand. */
+ /* XXX todo */
- netif_wake_queue(dev);
- np->stats.tx_errors++;
- return;
+ np->stats.tx_errors++;
}
@@ -849,8 +811,6 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
struct netdev_private *np = (struct netdev_private *)dev->priv;
unsigned entry;
- netif_stop_queue(dev);
-
/* Caution: the write order is important here, set the field
with the "ownership" bits last. */
@@ -883,10 +843,10 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
/* Update the producer index. */
writel(++entry, dev->base_addr + TxProducerIdx);
- if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1)
+ if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) {
np->tx_full = 1;
- if (! np->tx_full)
- netif_start_queue(dev);
+ netif_stop_queue(dev);
+ }
dev->trans_start = jiffies;
if (debug > 4) {
@@ -1347,56 +1307,69 @@ static int netdev_close(struct net_device *dev)
return 0;
}
-static int __init starfire_init_module (void)
+
+static void __devexit starfire_remove_one (struct pci_dev *pdev)
{
- if (debug) /* Emit version even if no cards detected. */
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-#ifdef CARDBUS
- register_driver(&etherdev_ops);
- return 0;
-#else
- if (pci_etherdev_probe(pci_tbl)) {
- printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n");
- return -ENODEV;
+ struct net_device *dev = pdev->driver_data;
+ struct netdev_private *np;
+
+ if (!dev) {
+ printk (KERN_WARNING "bug: removing starfire pci dev without driver\n");
+ return;
}
- return 0;
-#endif
+
+ np = dev->priv;
+
+ unregister_netdev(dev);
+ iounmap((char *)dev->base_addr);
+
+ if (np->tx_done_q)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->tx_done_q, np->tx_done_q_dma);
+ if (np->rx_done_q)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->rx_done_q, np->rx_done_q_dma);
+ if (np->tx_ring)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->tx_ring, np->tx_ring_dma);
+ if (np->rx_ring)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->rx_ring, np->rx_ring_dma);
+
+ kfree(dev);
}
-static void __exit starfire_cleanup_module (void)
+
+static struct pci_driver starfire_driver = {
+ name: "starfire",
+ probe: starfire_init_one,
+ remove: starfire_remove_one,
+ id_table: starfire_pci_tbl,
+};
+
+
+static int __init starfire_init (void)
{
- struct net_device *next_dev;
+ int rc;
+
+ MOD_INC_USE_COUNT;
+
+ rc = pci_module_init (&starfire_driver);
+
+ MOD_DEC_USE_COUNT;
+
+ return rc;
+}
-#ifdef CARDBUS
- unregister_driver(&etherdev_ops);
-#endif
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_net_dev) {
- struct netdev_private *np =
- (struct netdev_private *)root_net_dev->priv;
- next_dev = np->next_module;
- unregister_netdev(root_net_dev);
- iounmap((char *)root_net_dev->base_addr);
- if (np->tx_done_q)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->tx_done_q, np->tx_done_q_dma);
- if (np->rx_done_q)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->rx_done_q, np->rx_done_q_dma);
- if (np->tx_ring)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->tx_ring, np->tx_ring_dma);
- if (np->rx_ring)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->rx_ring, np->rx_ring_dma);
- kfree(root_net_dev);
- root_net_dev = next_dev;
- }
+static void __exit starfire_cleanup (void)
+{
+ pci_unregister_driver (&starfire_driver);
}
-module_init(starfire_init_module);
-module_exit(starfire_cleanup_module);
+
+module_init(starfire_init);
+module_exit(starfire_cleanup);
/*
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index a699391da..5c466ecf0 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -66,6 +66,12 @@
* network cleanup in 2.3.43pre7 (Tigran & myself)
* - Minor stuff.
*
+ * v1.5 March 22, 2000 - Fixed another timer bug that would hang the driver
+ * if no cable/link were present.
+ * - Cosmetic changes.
+ * - TODO: Port completely to new PCI/DMA API
+ * Auto-Neg fallback.
+ *
*******************************************************************************/
@@ -106,7 +112,7 @@ static int bbuf = 0;
static u8 *TLanPadBuffer;
static char TLanSignature[] = "TLAN";
static int TLanVersionMajor = 1;
-static int TLanVersionMinor = 4;
+static int TLanVersionMinor = 5;
static TLanAdapterEntry TLanAdapterList[] __initdata = {
@@ -430,7 +436,8 @@ static int __init tlan_probe(void)
}
- printk(KERN_INFO "TLAN: %d device(s) installed\n", TLanDevicesInstalled);
+ printk(KERN_INFO "TLAN: %d device%s installed\n",
+ TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s");
return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV);
}
@@ -839,8 +846,10 @@ static int TLan_Close(struct net_device *dev)
TLan_ReadAndClearStats( dev, TLAN_RECORD );
outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
- if ( priv->timer.function != NULL )
+ if ( priv->timer.function != NULL ) {
del_timer( &priv->timer );
+ priv->timer.function = NULL;
+ }
free_irq( dev->irq, dev );
TLan_FreeLists( dev );
TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name );
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index e0a339bfa..1714d34d1 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -58,6 +58,7 @@
* First release to the public
* 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing
* malloc free checks, reviewed code. <alan@redhat.com>
+ * 03/13/00 - Added spinlocks for smp
*
* To Do:
*
@@ -105,6 +106,7 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include <net/checksum.h>
#include <asm/io.h>
@@ -121,7 +123,7 @@
* Official releases will only have an a.b.c version number format.
*/
-static char *version = "LanStreamer.c v0.1.0 12/10/99 - Mike Sullivan";
+static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan";
static char *open_maj_error[] = {
"No error", "Lobe Media Test", "Physical Insertion",
@@ -210,7 +212,7 @@ static int __init streamer_scan(struct net_device *dev)
/* Check to see if io has been allocated, if so, we've already done this card,
so continue on the card discovery loop */
- if (check_region(pci_device->resource[0].start, STREAMER_IO_SPACE))
+ if (check_region(pci_device->resource[0].start & (~3), STREAMER_IO_SPACE))
{
card_no++;
continue;
@@ -223,6 +225,8 @@ static int __init streamer_scan(struct net_device *dev)
break;
}
memset(streamer_priv, 0, sizeof(struct streamer_private));
+ init_waitqueue_head(&streamer_priv->srb_wait);
+ init_waitqueue_head(&streamer_priv->trb_wait);
#ifndef MODULE
dev = init_trdev(dev, 0);
if(dev==NULL)
@@ -238,11 +242,11 @@ static int __init streamer_scan(struct net_device *dev)
pci_device, dev, dev->priv);
#endif
dev->irq = pci_device->irq;
- dev->base_addr = pci_device->resource[0].start;
+ dev->base_addr = pci_device->resource[0].start & (~3);
dev->init = &streamer_init;
+ streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name;
streamer_priv->streamer_mmio = ioremap(pci_device->resource[1].start, 256);
- init_waitqueue_head(&streamer_priv->srb_wait);
- init_waitqueue_head(&streamer_priv->trb_wait);
+
if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000))
streamer_priv->pkt_buf_sz = PKT_BUF_SZ;
else
@@ -250,7 +254,6 @@ static int __init streamer_scan(struct net_device *dev)
streamer_priv->streamer_ring_speed = ringspeed[card_no];
streamer_priv->streamer_message_level = message_level[card_no];
- streamer_priv->streamer_multicast_set = 0;
if (streamer_init(dev) == -1) {
unregister_netdevice(dev);
@@ -274,7 +277,7 @@ static int __init streamer_scan(struct net_device *dev)
}
-static int __init streamer_init(struct net_device *dev)
+static int streamer_reset(struct net_device *dev)
{
struct streamer_private *streamer_priv;
__u8 *streamer_mmio;
@@ -286,12 +289,6 @@ static int __init streamer_init(struct net_device *dev)
streamer_priv = (struct streamer_private *) dev->priv;
streamer_mmio = streamer_priv->streamer_mmio;
- printk("%s \n", version);
- printk(KERN_INFO "%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, using irq %d\n",
- dev->name, (unsigned int) dev->base_addr,
- streamer_priv->streamer_mmio, dev->irq);
-
- request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer");
writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
t = jiffies;
/* Hold soft reset bit for a while */
@@ -330,11 +327,16 @@ static int __init streamer_init(struct net_device *dev)
printk(KERN_INFO "%s: skb allocation for diagnostics failed...proceeding\n",
dev->name);
} else {
- streamer_priv->streamer_rx_ring[0].forward = 0;
- streamer_priv->streamer_rx_ring[0].status = 0;
- streamer_priv->streamer_rx_ring[0].buffer = virt_to_bus(skb->data);
- streamer_priv->streamer_rx_ring[0].framelen_buflen = 512; /* streamer_priv->pkt_buf_sz; */
- writel(virt_to_bus(&streamer_priv->streamer_rx_ring[0]), streamer_mmio + RXBDA);
+ struct streamer_rx_desc *rx_ring;
+ u8 *data;
+
+ rx_ring=(struct streamer_rx_desc *)skb->data;
+ data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc);
+ rx_ring->forward=0;
+ rx_ring->status=0;
+ rx_ring->buffer=virt_to_bus(data);
+ rx_ring->framelen_buflen=512;
+ writel(virt_to_bus(rx_ring),streamer_mmio+RXBDA);
}
#if STREAMER_DEBUG
@@ -382,7 +384,7 @@ static int __init streamer_init(struct net_device *dev)
writew(readw(streamer_mmio + LAPWWO) + 6, streamer_mmio + LAPA);
if (readw(streamer_mmio + LAPD)) {
printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",
- readw(streamer_mmio + LAPD));
+ ntohs(readw(streamer_mmio + LAPD)));
release_region(dev->base_addr, STREAMER_IO_SPACE);
return -1;
}
@@ -398,17 +400,14 @@ static int __init streamer_init(struct net_device *dev)
#endif
/* setup uaa area for access with LAPD */
- writew(uaa_addr, streamer_mmio + LAPA);
-
- /* setup uaa area for access with LAPD */
{
int i;
__u16 addr;
writew(uaa_addr, streamer_mmio + LAPA);
for (i = 0; i < 6; i += 2) {
- addr = readw(streamer_mmio + LAPDINC);
- dev->dev_addr[i] = addr & 0xff;
- dev->dev_addr[i + 1] = (addr >> 8) & 0xff;
+ addr=ntohs(readw(streamer_mmio+LAPDINC));
+ dev->dev_addr[i]= (addr >> 8) & 0xff;
+ dev->dev_addr[i+1]= addr & 0xff;
}
#if STREAMER_DEBUG
printk("Adapter address: ");
@@ -421,6 +420,32 @@ static int __init streamer_init(struct net_device *dev)
return 0;
}
+static int __init streamer_init(struct net_device *dev)
+{
+ struct streamer_private *streamer_priv;
+ __u8 *streamer_mmio;
+ int rc;
+
+ streamer_priv=(struct streamer_private *)dev->priv;
+ streamer_mmio=streamer_priv->streamer_mmio;
+
+ spin_lock_init(&streamer_priv->streamer_lock);
+
+ printk("%s \n", version);
+ printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
+ streamer_priv->streamer_card_name,
+ (unsigned int) dev->base_addr,
+ streamer_priv->streamer_mmio,
+ dev->irq);
+
+ request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer");
+
+ rc=streamer_reset(dev);
+ return rc;
+}
+
+
+
static int streamer_open(struct net_device *dev)
{
struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
@@ -430,7 +455,11 @@ static int streamer_open(struct net_device *dev)
int i, open_finished = 1;
__u16 srb_word;
__u16 srb_open;
+ int rc;
+ if (readw(streamer_mmio+BMCTL_SUM) & BMCTL_RX_ENABLED) {
+ rc=streamer_reset(dev);
+ }
if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "streamer", dev)) {
return -EAGAIN;
@@ -461,23 +490,27 @@ static int streamer_open(struct net_device *dev)
writew(0, streamer_mmio + LAPDINC);
}
- writew(readw(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
- writew(SRB_OPEN_ADAPTER, streamer_mmio + LAPDINC); /* open */
+ writew(readw(streamer_mmio+LAPWWO),streamer_mmio+LAPA);
+ writew(htons(SRB_OPEN_ADAPTER<<8),streamer_mmio+LAPDINC) ; /* open */
+ writew(htons(STREAMER_CLEAR_RET_CODE<<8),streamer_mmio+LAPDINC);
writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
writew(readw(streamer_mmio + LAPWWO) + 8, streamer_mmio + LAPA);
#if STREAMER_NETWORK_MONITOR
/* If Network Monitor, instruct card to copy MAC frames through the ARB */
- writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */
+ writew(htons(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */
#else
- writew(ntohs(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */
+ writew(htons(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */
#endif
if (streamer_priv->streamer_laa[0]) {
writew(readw(streamer_mmio + LAPWWO) + 12, streamer_mmio + LAPA);
- writew(((__u16 *) (streamer_priv->streamer_laa))[0], streamer_mmio + LAPDINC); /* offset 12 word */
- writew(((__u16 *) (streamer_priv->streamer_laa))[2], streamer_mmio + LAPDINC); /* offset 14 word */
- writew(((__u16 *) (streamer_priv->streamer_laa))[4], streamer_mmio + LAPDINC); /* offset 16 word */
+ writew(htons((streamer_priv->streamer_laa[0] << 8) |
+ streamer_priv->streamer_laa[1]),streamer_mmio+LAPDINC);
+ writew(htons((streamer_priv->streamer_laa[2] << 8) |
+ streamer_priv->streamer_laa[3]),streamer_mmio+LAPDINC);
+ writew(htons((streamer_priv->streamer_laa[4] << 8) |
+ streamer_priv->streamer_laa[5]),streamer_mmio+LAPDINC);
memcpy(dev->dev_addr, streamer_priv->streamer_laa, dev->addr_len);
}
@@ -526,7 +559,7 @@ static int streamer_open(struct net_device *dev)
* timed out.
*/
writew(srb_open + 2, streamer_mmio + LAPA);
- srb_word = readw(streamer_mmio + LAPD) & 0xFF;
+ srb_word = ntohs(readw(streamer_mmio + LAPD)) & 0xFF;
if (srb_word == STREAMER_CLEAR_RET_CODE) {
printk(KERN_WARNING "%s: Adapter Open time out or error.\n",
dev->name);
@@ -574,7 +607,7 @@ static int streamer_open(struct net_device *dev)
} while (!(open_finished)); /* Will only loop if ring speed mismatch re-open attempted && autosense is on */
writew(srb_open + 18, streamer_mmio + LAPA);
- srb_word = readw(streamer_mmio + LAPD) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8;
if (srb_word & (1 << 3))
if (streamer_priv->streamer_message_level)
printk(KERN_INFO "%s: Opened in FDX Mode\n", dev->name);
@@ -604,6 +637,14 @@ static int streamer_open(struct net_device *dev)
writew(~BMCTL_RX_DIS, streamer_mmio + BMCTL_RUM);
/* setup rx descriptors */
+ streamer_priv->streamer_rx_ring=
+ kmalloc( sizeof(struct streamer_rx_desc)*
+ STREAMER_RX_RING_SIZE,GFP_KERNEL);
+ if (!streamer_priv->streamer_rx_ring) {
+ printk(KERN_WARNING "%s ALLOC of streamer rx ring FAILED!!\n",dev->name);
+ return -EIO;
+ }
+
for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
struct sk_buff *skb;
@@ -638,6 +679,13 @@ static int streamer_open(struct net_device *dev)
/* setup tx ring */
+ streamer_priv->streamer_tx_ring=kmalloc(sizeof(struct streamer_tx_desc)*
+ STREAMER_TX_RING_SIZE,GFP_KERNEL);
+ if (!streamer_priv->streamer_tx_ring) {
+ printk(KERN_WARNING "%s ALLOC of streamer_tx_ring FAILED\n",dev->name);
+ return -EIO;
+ }
+
writew(~BMCTL_TX2_DIS, streamer_mmio + BMCTL_RUM); /* Enables TX channel 2 */
for (i = 0; i < STREAMER_TX_RING_SIZE; i++) {
streamer_priv->streamer_tx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_tx_ring[i + 1]);
@@ -776,7 +824,7 @@ static void streamer_rx(struct net_device *dev)
memcpy(skb_put(skb, length),bus_to_virt(rx_desc->buffer), length); /* copy this fragment */
streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0;
streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz;
- streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = virt_to_bus(skb->data);
+
/* give descriptor back to the adapter */
writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]), streamer_mmio + RXLBDA);
@@ -828,10 +876,14 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
misr = readw(streamer_mmio + MISR_RUM);
writew(~misr, streamer_mmio + MISR_RUM);
- if (!sisr) { /* Interrupt isn't for us */
+ if (!sisr)
+ { /* Interrupt isn't for us */
+ writew(~misr,streamer_mmio+MISR_RUM);
return;
}
+ spin_lock(&streamer_priv->streamer_lock);
+
if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY))
|| (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) {
if (sisr & SISR_SRB_REPLY) {
@@ -868,9 +920,9 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n",
dev->name, readw(streamer_mmio + LAPDINC),
- readw(streamer_mmio + LAPDINC),
- readw(streamer_mmio + LAPDINC),
- readw(streamer_mmio + LAPDINC));
+ ntohs(readw(streamer_mmio + LAPDINC)),
+ ntohs(readw(streamer_mmio + LAPDINC)),
+ ntohs(readw(streamer_mmio + LAPDINC)));
free_irq(dev->irq, dev);
}
@@ -907,17 +959,19 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} /* One if the interrupts we want */
writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+ spin_unlock(&streamer_priv->streamer_lock) ;
}
-
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct streamer_private *streamer_priv =
(struct streamer_private *) dev->priv;
__u8 *streamer_mmio = streamer_priv->streamer_mmio;
+ unsigned long flags ;
+ spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
netif_stop_queue(dev);
-
+
if (streamer_priv->free_tx_ring_entries) {
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
@@ -941,9 +995,11 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
- netif_start_queue(dev);
+ netif_wake_queue(dev);
+ spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
return 0;
} else {
+ spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
return 1;
}
}
@@ -957,9 +1013,10 @@ static int streamer_close(struct net_device *dev)
unsigned long flags;
int i;
+ netif_stop_queue(dev);
writew(streamer_priv->srb, streamer_mmio + LAPA);
- writew(SRB_CLOSE_ADAPTER, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
+ writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
save_flags(flags);
cli();
@@ -987,7 +1044,9 @@ static int streamer_close(struct net_device *dev)
streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
- dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]);
+ if (streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]) {
+ dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]);
+ }
streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
}
@@ -1003,11 +1062,10 @@ static int streamer_close(struct net_device *dev)
writew(streamer_priv->srb, streamer_mmio + LAPA);
printk("srb): ");
for (i = 0; i < 2; i++) {
- printk("%x ", htons(readw(streamer_mmio + LAPDINC)));
+ printk("%x ", ntohs(readw(streamer_mmio + LAPDINC)));
}
printk("\n");
#endif
- netif_stop_queue(dev);
free_irq(dev->irq, dev);
MOD_DEC_USE_COUNT;
@@ -1019,9 +1077,10 @@ static void streamer_set_rx_mode(struct net_device *dev)
struct streamer_private *streamer_priv =
(struct streamer_private *) dev->priv;
__u8 *streamer_mmio = streamer_priv->streamer_mmio;
- __u8 options = 0, set_mc_list = 0;
- __u16 ata1, ata2;
+ __u8 options = 0;
struct dev_mc_list *dmi;
+ unsigned char dev_mc_address[5];
+ int i;
writel(streamer_priv->srb, streamer_mmio + LAPA);
options = streamer_priv->streamer_copy_all_options;
@@ -1031,23 +1090,17 @@ static void streamer_set_rx_mode(struct net_device *dev)
else
options &= ~(3 << 5);
- if (dev->mc_count) {
- set_mc_list = 1;
- }
-
/* Only issue the srb if there is a change in options */
if ((options ^ streamer_priv->streamer_copy_all_options))
{
/* Now to issue the srb command to alter the copy.all.options */
-
- writew(SRB_MODIFY_RECEIVE_OPTIONS,
- streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
- writew(streamer_priv->streamer_receive_options | (options << 8), streamer_mmio + LAPDINC);
- writew(0x414a, streamer_mmio + LAPDINC);
- writew(0x454d, streamer_mmio + LAPDINC);
- writew(0x2053, streamer_mmio + LAPDINC);
+ writew(htons(SRB_MODIFY_RECEIVE_OPTIONS << 8), streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
+ writew(htons((streamer_priv->streamer_receive_options << 8) | options),streamer_mmio+LAPDINC);
+ writew(htons(0x4a41),streamer_mmio+LAPDINC);
+ writew(htons(0x4d45),streamer_mmio+LAPDINC);
+ writew(htons(0x5320),streamer_mmio+LAPDINC);
writew(0x2020, streamer_mmio + LAPDINC);
streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */
@@ -1058,54 +1111,25 @@ static void streamer_set_rx_mode(struct net_device *dev)
return;
}
- if (set_mc_list ^ streamer_priv->streamer_multicast_set)
- { /* Multicast options have changed */
- dmi = dev->mc_list;
-
- writel(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA);
- ata1 = readw(streamer_mmio + LAPDINC);
- ata2 = readw(streamer_mmio + LAPD);
-
- writel(streamer_priv->srb, streamer_mmio + LAPA);
-
- if (set_mc_list)
- {
- /* Turn multicast on */
-
- /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
- * We do this with a set functional address mask.
- */
-
- if (!(ata1 & 0x0400)) { /* need to set functional mask */
- writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
- writew(0, streamer_mmio + LAPDINC);
- writew(ata1 | 0x0400, streamer_mmio + LAPDINC);
- writew(ata2, streamer_mmio + LAPD);
-
- streamer_priv->srb_queued = 2;
- writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
-
- streamer_priv->streamer_multicast_set = 1;
- }
-
- } else { /* Turn multicast off */
-
- if ((ata1 & 0x0400)) { /* Hmmm, need to reset the functional mask */
- writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
- writew(0, streamer_mmio + LAPDINC);
- writew(ata1 & ~0x0400, streamer_mmio + LAPDINC);
- writew(ata2, streamer_mmio + LAPD);
-
- streamer_priv->srb_queued = 2;
- writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
-
- streamer_priv->streamer_multicast_set = 0;
- }
- }
-
+ /* Set the functional addresses we need for multicast */
+ writel(streamer_priv->srb,streamer_mmio+LAPA);
+ dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
+
+ for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next)
+ {
+ dev_mc_address[0] |= dmi->dmi_addr[2] ;
+ dev_mc_address[1] |= dmi->dmi_addr[3] ;
+ dev_mc_address[2] |= dmi->dmi_addr[4] ;
+ dev_mc_address[3] |= dmi->dmi_addr[5] ;
}
+
+ writew(htons(SRB_SET_FUNC_ADDRESS << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
+ writew(0,streamer_mmio+LAPDINC);
+ writew(htons( (dev_mc_address[0] << 8) | dev_mc_address[1]),streamer_mmio+LAPDINC);
+ writew(htons( (dev_mc_address[2] << 8) | dev_mc_address[3]),streamer_mmio+LAPDINC);
+ streamer_priv->srb_queued = 2 ;
+ writel(LISR_SRB_CMD,streamer_mmio+LISR_SUM);
}
static void streamer_srb_bh(struct net_device *dev)
@@ -1115,7 +1139,7 @@ static void streamer_srb_bh(struct net_device *dev)
__u16 srb_word;
writew(streamer_priv->srb, streamer_mmio + LAPA);
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
@@ -1125,7 +1149,8 @@ static void streamer_srb_bh(struct net_device *dev)
*/
case SRB_MODIFY_RECEIVE_OPTIONS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
+
switch (srb_word) {
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name);
@@ -1147,11 +1172,10 @@ static void streamer_srb_bh(struct net_device *dev)
/* SRB_SET_GROUP_ADDRESS - Multicast group setting
*/
case SRB_SET_GROUP_ADDRESS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
- streamer_priv->streamer_multicast_set = 1;
- break;
+ break;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name);
break;
@@ -1176,11 +1200,10 @@ static void streamer_srb_bh(struct net_device *dev)
/* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list
*/
case SRB_RESET_GROUP_ADDRESS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
- streamer_priv->streamer_multicast_set = 0;
- break;
+ break;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name);
break;
@@ -1200,7 +1223,7 @@ static void streamer_srb_bh(struct net_device *dev)
*/
case SRB_SET_FUNC_ADDRESS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
if (streamer_priv->streamer_message_level)
@@ -1221,7 +1244,7 @@ static void streamer_srb_bh(struct net_device *dev)
*/
case SRB_READ_LOG:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
{
@@ -1250,7 +1273,7 @@ static void streamer_srb_bh(struct net_device *dev)
/* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */
case SRB_READ_SR_COUNTERS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
if (streamer_priv->streamer_message_level)
@@ -1285,9 +1308,10 @@ static int streamer_set_mac_address(struct net_device *dev, void *addr)
struct sockaddr *saddr = addr;
struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
- if (netif_running(dev)) {
+ if (netif_running(dev))
+ {
printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name);
- return -EBUSY;
+ return -EIO;
}
memcpy(streamer_priv->streamer_laa, saddr->sa_data, dev->addr_len);
@@ -1324,12 +1348,12 @@ static void streamer_arb_cmd(struct net_device *dev)
#endif
writew(streamer_priv->arb, streamer_mmio + LAPA);
- arb_word = readw(streamer_mmio + LAPD) & 0xFF;
-
+ arb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8;
+
if (arb_word == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
writew(streamer_priv->arb + 6, streamer_mmio + LAPA);
streamer_priv->mac_rx_buffer = buff_off = ntohs(readw(streamer_mmio + LAPDINC));
- header_len = readw(streamer_mmio + LAPDINC) & 0xff; /* 802.5 Token-Ring Header Length */
+ header_len=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; /* 802.5 Token-Ring Header Length */
frame_len = ntohs(readw(streamer_mmio + LAPDINC));
#if STREAMER_DEBUG
@@ -1340,7 +1364,7 @@ static void streamer_arb_cmd(struct net_device *dev)
__u16 len;
writew(ntohs(buff_off), streamer_mmio + LAPA); /*setup window to frame data */
- next = ntohs(readw(streamer_mmio + LAPDINC));
+ next = htons(readw(streamer_mmio + LAPDINC));
status =
ntohs(readw(streamer_mmio + LAPDINC)) & 0xff;
len = ntohs(readw(streamer_mmio + LAPDINC));
@@ -1364,7 +1388,7 @@ static void streamer_arb_cmd(struct net_device *dev)
int i;
__u16 rx_word;
- writew(ntohs(buff_off), streamer_mmio + LAPA); /* setup window to frame data */
+ writew(htons(buff_off), streamer_mmio + LAPA); /* setup window to frame data */
next_ptr = ntohs(readw(streamer_mmio + LAPDINC));
readw(streamer_mmio + LAPDINC); /* read thru status word */
buffer_len = ntohs(readw(streamer_mmio + LAPDINC));
@@ -1374,9 +1398,9 @@ static void streamer_arb_cmd(struct net_device *dev)
i = 0;
while (i < buffer_len) {
- rx_word = readw(streamer_mmio + LAPDINC);
- frame_data[i] = rx_word & 0xff;
- frame_data[i + 1] = (rx_word >> 8) & 0xff;
+ rx_word=ntohs(readw(streamer_mmio+LAPDINC));
+ frame_data[i]=rx_word >> 8;
+ frame_data[i+1]=rx_word & 0xff;
i += 2;
}
@@ -1420,10 +1444,10 @@ static void streamer_arb_cmd(struct net_device *dev)
writew(streamer_priv->asb, streamer_mmio + LAPA);
- writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */
+ writew(htons(ASB_RECEIVE_DATA << 8), streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
writew(0, streamer_mmio + LAPDINC);
- writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
+ writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM);
@@ -1433,12 +1457,13 @@ static void streamer_arb_cmd(struct net_device *dev)
} else if (arb_word == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */
writew(streamer_priv->arb + 6, streamer_mmio + LAPA);
lan_status = ntohs(readw(streamer_mmio + LAPDINC));
- fdx_prot_error = readw(streamer_mmio + LAPD) & 0xFF;
-
+ fdx_prot_error = ntohs(readw(streamer_mmio+LAPD)) >> 8;
+
/* Issue ARB Free */
writew(LISR_ARB_FREE, streamer_priv->streamer_mmio + LISR_SUM);
- lan_status_diff = streamer_priv->streamer_lan_status ^ lan_status;
+ lan_status_diff = (streamer_priv->streamer_lan_status ^ lan_status) &
+ lan_status;
if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR))
{
@@ -1489,8 +1514,8 @@ static void streamer_arb_cmd(struct net_device *dev)
/* Issue READ.LOG command */
writew(streamer_priv->srb, streamer_mmio + LAPA);
- writew(SRB_READ_LOG, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
+ writew(htons(SRB_READ_LOG << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
writew(0, streamer_mmio + LAPDINC);
streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */
@@ -1503,10 +1528,10 @@ static void streamer_arb_cmd(struct net_device *dev)
/* Issue a READ.SR.COUNTERS */
writew(streamer_priv->srb, streamer_mmio + LAPA);
- writew(SRB_READ_SR_COUNTERS,
- streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE,
- streamer_mmio + LAPDINC);
+ writew(htons(SRB_READ_SR_COUNTERS << 8),
+ streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8),
+ streamer_mmio+LAPDINC);
streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */
writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
@@ -1528,10 +1553,10 @@ static void streamer_asb_bh(struct net_device *dev)
/* Dropped through the first time */
writew(streamer_priv->asb, streamer_mmio + LAPA);
- writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */
+ writew(htons(ASB_RECEIVE_DATA << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
writew(0, streamer_mmio + LAPDINC);
- writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
+ writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM);
streamer_priv->asb_queued = 2;
@@ -1542,7 +1567,7 @@ static void streamer_asb_bh(struct net_device *dev)
if (streamer_priv->asb_queued == 2) {
__u8 rc;
writew(streamer_priv->asb + 2, streamer_mmio + LAPA);
- rc = readw(streamer_mmio + LAPD) & 0xff;
+ rc=ntohs(readw(streamer_mmio+LAPD)) >> 8;
switch (rc) {
case 0x01:
printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
@@ -1594,7 +1619,7 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset,
off_t pos = 0;
int size;
- struct net_device *dev;
+ struct device *dev;
size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n");
@@ -1607,8 +1632,8 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset,
for (dev = dev_base; dev != NULL; dev = dev->next)
{
- if (dev->base_addr == (pci_device->base_address[0] & (~3)))
- { /* Yep, a Streamer device */
+ if (dev->base_addr == pci_device->resource[0].start)
+ { /* Yep, a Streamer device */
size = sprintf_info(buffer + len, dev);
len += size;
pos = begin + len;
@@ -1644,17 +1669,17 @@ static int sprintf_info(char *buffer, struct net_device *dev)
for (i = 0; i < 14; i += 2) {
__u16 io_word;
__u8 *datap = (__u8 *) & sat;
- io_word = readw(streamer_mmio + LAPDINC);
- datap[size] = io_word & 0xff;
- datap[size + 1] = (io_word >> 8) & 0xff;
+ io_word=ntohs(readw(streamer_mmio+LAPDINC));
+ datap[size]=io_word >> 8;
+ datap[size+1]=io_word & 0xff;
}
writew(streamer_priv->streamer_parms_addr, streamer_mmio + LAPA);
for (i = 0; i < 68; i += 2) {
__u16 io_word;
__u8 *datap = (__u8 *) & spt;
- io_word = readw(streamer_mmio + LAPDINC);
- datap[size] = io_word & 0xff;
- datap[size + 1] = (io_word >> 8) & 0xff;
+ io_word=ntohs(readw(streamer_mmio+LAPDINC));
+ datap[size]=io_word >> 8;
+ datap[size+1]=io_word & 0xff;
}
@@ -1723,10 +1748,7 @@ int init_module(void)
#if STREAMER_NETWORK_MONITOR
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-
- ent = create_proc_entry("net/streamer_tr", 0, 0);
- ent->read_proc = &streamer_proc_info;
+ create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL);
#endif
#endif
for (i = 0; (i < STREAMER_MAX_ADAPTERS); i++)
@@ -1758,11 +1780,17 @@ int init_module(void)
void cleanup_module(void)
{
int i;
+ struct streamer_private *streamer_priv;
for (i = 0; i < STREAMER_MAX_ADAPTERS; i++)
if (dev_streamer[i]) {
unregister_trdev(dev_streamer[i]);
release_region(dev_streamer[i]->base_addr, STREAMER_IO_SPACE);
+ streamer_priv=(struct streamer_private *)dev_streamer[i]->priv;
+ kfree_s(streamer_priv->streamer_rx_ring,
+ sizeof(struct streamer_rx_desc)*STREAMER_RX_RING_SIZE);
+ kfree_s(streamer_priv->streamer_tx_ring,
+ sizeof(struct streamer_tx_desc)*STREAMER_TX_RING_SIZE);
kfree_s(dev_streamer[i]->priv, sizeof(struct streamer_private));
kfree_s(dev_streamer[i], sizeof(struct net_device));
dev_streamer[i] = NULL;
diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h
index 7ba86dfe5..4c99f875e 100644
--- a/drivers/net/tokenring/lanstreamer.h
+++ b/drivers/net/tokenring/lanstreamer.h
@@ -132,6 +132,7 @@
#define BMCTL_TX1_DIS (1<<14)
#define BMCTL_TX2_DIS (1<<10)
#define BMCTL_RX_DIS (1<<6)
+#define BMCTL_RX_ENABLED (1<<5)
#define RXLBDA 0x90
#define RXBDA 0x94
@@ -257,6 +258,9 @@ struct streamer_private {
__u16 asb;
__u8 *streamer_mmio;
+ char *streamer_card_name;
+
+ spinlock_t streamer_lock;
volatile int srb_queued; /* True if an SRB is still posted */
wait_queue_head_t srb_wait;
@@ -264,10 +268,10 @@ struct streamer_private {
volatile int asb_queued; /* True if an ASB is posted */
volatile int trb_queued; /* True if a TRB is posted */
- wait_queue_head_t trb_wait;
+ wait_queue_head_t trb_wait;
- struct streamer_rx_desc streamer_rx_ring[STREAMER_RX_RING_SIZE];
- struct streamer_tx_desc streamer_tx_ring[STREAMER_TX_RING_SIZE];
+ struct streamer_rx_desc *streamer_rx_ring;
+ struct streamer_tx_desc *streamer_tx_ring;
struct sk_buff *tx_ring_skb[STREAMER_TX_RING_SIZE],
*rx_ring_skb[STREAMER_RX_RING_SIZE];
int tx_ring_free, tx_ring_last_status, rx_ring_last_received,
@@ -279,7 +283,6 @@ struct streamer_private {
__u16 pkt_buf_sz;
__u8 streamer_receive_options, streamer_copy_all_options,
streamer_message_level;
- __u8 streamer_multicast_set;
__u16 streamer_addr_table_addr, streamer_parms_addr;
__u16 mac_rx_buffer;
__u8 streamer_laa[6];
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 57b3aa252..f244874e4 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index b009a8a4b..27ea89232 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -15,7 +15,6 @@
#include "tulip.h"
#include <linux/init.h>
-#include <asm/io.h>
#include <asm/unaligned.h>
@@ -30,31 +29,31 @@
/* Known cards that have old-style EEPROMs. */
static struct eeprom_fixup eeprom_fixups[] __devinitdata = {
{"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
- 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+ 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
{"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
- 0x0000, 0x009E, /* 10baseT */
- 0x0004, 0x009E, /* 10baseT-FD */
- 0x0903, 0x006D, /* 100baseTx */
- 0x0905, 0x006D, /* 100baseTx-FD */ }},
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0903, 0x006D, /* 100baseTx */
+ 0x0905, 0x006D, /* 100baseTx-FD */ }},
{"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
- 0x0107, 0x8021, /* 100baseFx */
- 0x0108, 0x8021, /* 100baseFx-FD */
- 0x0100, 0x009E, /* 10baseT */
- 0x0104, 0x009E, /* 10baseT-FD */
- 0x0103, 0x006D, /* 100baseTx */
- 0x0105, 0x006D, /* 100baseTx-FD */ }},
+ 0x0107, 0x8021, /* 100baseFx */
+ 0x0108, 0x8021, /* 100baseFx-FD */
+ 0x0100, 0x009E, /* 10baseT */
+ 0x0104, 0x009E, /* 10baseT-FD */
+ 0x0103, 0x006D, /* 100baseTx */
+ 0x0105, 0x006D, /* 100baseTx-FD */ }},
{"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
- 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
- 0x0000, 0x009E, /* 10baseT */
- 0x0004, 0x009E, /* 10baseT-FD */
- 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
- 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
+ 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
+ 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
{"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
- 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
- 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
- 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
- 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
- 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
+ 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
+ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
}},
{"NetWinder", 0x00, 0x10, 0x57,
/* Default media = MII
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 12b7af968..0a48a27f0 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
@@ -211,9 +210,12 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
if (status < 0)
break; /* It still has not been Txed */
+
/* Check for Rx filter setup frames. */
if (tp->tx_buffers[entry].skb == NULL) {
- pci_unmap_single(tp->pdev,
+ /* test because dummy frames not mapped */
+ if (tp->tx_buffers[entry].mapping)
+ pci_unmap_single(tp->pdev,
tp->tx_buffers[entry].mapping,
sizeof(tp->setup_frame),
PCI_DMA_TODEVICE);
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index 1d4c3b2e4..e704c6c7d 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
index 445d4a440..2f408684f 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/tulip/pnic.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include "tulip.h"
-#include <asm/io.h>
void pnic_do_nway(struct net_device *dev)
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index 796fdd136..0a40abb48 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
void tulip_timer(unsigned long data)
@@ -87,7 +86,11 @@ void tulip_timer(unsigned long data)
break;
}
break;
- case DC21140: case DC21142: case MX98713: case COMPEX9881: default: {
+ case DC21140:
+ case DC21142:
+ case MX98713:
+ case COMPEX9881:
+ default: {
struct medialeaf *mleaf;
unsigned char *p;
if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 8196723ae..22260591f 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -17,7 +17,7 @@
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
-
+#include <asm/io.h>
struct tulip_chip_table {
char *chip_name;
@@ -36,8 +36,10 @@ enum tbl_flag {
HAS_ACPI = 0x10,
MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */
HAS_PNICNWAY = 0x80,
- HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */
- HAS_8023X = 0x100,
+ HAS_NWAY = 0x40, /* Uses internal NWay xcvr. */
+ HAS_INTR_MITIGATION = 0x100,
+ IS_ASIX = 0x200,
+ HAS_8023X = 0x400,
};
@@ -58,7 +60,6 @@ enum chips {
COMET,
COMPEX9881,
I21145,
- X3201_3,
};
@@ -137,6 +138,17 @@ enum desc_status_bits {
};
+enum t21041_csr13_bits {
+ csr13_eng = (0xEF0<<4), /* for eng. purposes only, hardcode at EF0h */
+ csr13_aui = (1<<3), /* clear to force 10bT, set to force AUI/BNC */
+ csr13_cac = (1<<2), /* CSR13/14/15 autoconfiguration */
+ csr13_srl = (1<<0), /* When reset, resets all SIA functions, machines */
+
+ csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_cac | csr13_srl),
+ csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl),
+};
+
+
/* Keep the ring sizes a power of two for efficiency.
Making the Tx ring too large decreases the effectiveness of channel
bonding and packet priority.
@@ -334,7 +346,14 @@ extern u8 t21040_csr13[];
extern u16 t21041_csr13[];
extern u16 t21041_csr14[];
extern u16 t21041_csr15[];
-void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6);
+
+
+extern inline void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
+{
+ long ioaddr = tp->base_addr;
+
+ outl (newcsr6, ioaddr + CSR6);
+}
#endif /* __NET_TULIP_H__ */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 6881093ea..196dcf7f6 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -19,7 +19,7 @@
*/
-static const char version[] = "Linux Tulip driver version 0.9.4 (Feb 28, 2000)\n";
+static const char version[] = "Linux Tulip driver version 0.9.4.2 (Mar 21, 2000)\n";
#include <linux/module.h>
#include "tulip.h"
@@ -27,7 +27,6 @@ static const char version[] = "Linux Tulip driver version 0.9.4 (Feb 28, 2000)\n
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
-#include <asm/io.h>
#include <asm/unaligned.h>
@@ -92,9 +91,6 @@ static int csr0 = 0x00A00000 | 0x4800;
#define TX_TIMEOUT (4*HZ)
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
- This is only in the support-all-kernels source code. */
-
MODULE_AUTHOR("The Linux Kernel Team");
MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
MODULE_PARM(tulip_debug, "i");
@@ -123,12 +119,13 @@ int tulip_debug = 1;
struct tulip_chip_table tulip_tbl[] = {
{ "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
- { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
+ { "Digital DC21041 Tulip", 128, 0x0001ebef,
+ HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer },
{ "Digital DS21140 Tulip", 128, 0x0001ebef,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
{ "Digital DS21143 Tulip", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
- t21142_timer },
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY
+ | HAS_INTR_MITIGATION, t21142_timer },
{ "Lite-On 82c168 PNIC", 256, 0x0001ebef,
HAS_MII | HAS_PNICNWAY, pnic_timer },
{ "Macronix 98713 PMAC", 128, 0x0001ebef,
@@ -138,18 +135,15 @@ struct tulip_chip_table tulip_tbl[] = {
{ "Macronix 98725 PMAC", 256, 0x0001ebef,
HAS_MEDIA_TABLE, mxic_timer },
{ "ASIX AX88140", 128, 0x0001fbff,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer },
{ "Lite-On PNIC-II", 256, 0x0801fbff,
- HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
+ HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer },
{ "ADMtek Comet", 256, 0x0001abef,
MC_HASH_ONLY, comet_timer },
{ "Compex 9881 PMAC", 128, 0x0001ebef,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
{ "Intel DS21145 Tulip", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143,
- t21142_timer },
- { "Xircom tulip work-alike", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY,
t21142_timer },
{0},
};
@@ -163,16 +157,20 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = {
{ 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
{ 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
{ 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
- { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
+/* { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },*/
{ 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
{ 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
{ 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
- { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+ { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
{0},
};
-MODULE_DEVICE_TABLE(pci,tulip_pci_tbl);
+MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
/* A full-duplex map for media types. */
@@ -181,7 +179,13 @@ const char tulip_media_cap[] =
u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
-u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+u16 t21041_csr13[] = {
+ csr13_mask_10bt, /* 10-T */
+ csr13_mask_auibnc, /* 10-2 */
+ csr13_mask_auibnc, /* AUI */
+ csr13_mask_10bt, /* 10-T */
+ csr13_mask_10bt, /* 10T-FD */
+};
u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
@@ -198,54 +202,6 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
-/* The Xircom cards are picky about when certain bits in CSR6 can be
- manipulated. Keith Owens <kaos@ocs.com.au>. */
-
-void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
-{
- long ioaddr = tp->base_addr;
- const int strict_bits = 0x0060e202;
- int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
-
- /* common path */
- if (tp->chip_id != X3201_3) {
- outl (newcsr6, ioaddr + CSR6);
- return;
- }
-
- newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
- /* read 0 on the Xircom cards */
- newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
- currcsr6 = inl (ioaddr + CSR6);
- if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
- ((currcsr6 & ~0x2002) == 0))
- goto out_write;
-
- /* make sure the transmitter and receiver are stopped first */
- currcsr6 &= ~0x2002;
- while (1) {
- csr5 = inl (ioaddr + CSR5);
- if (csr5 == 0xffffffff)
- break; /* cannot read csr5, card removed? */
- csr5_22_20 = csr5 & 0x700000;
- csr5_19_17 = csr5 & 0x0e0000;
- if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
- (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
- break; /* both are stopped or suspended */
- if (!--attempts) {
- printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts,"
- "csr5=0x%08x\n", csr5);
- goto out_write;
- }
- outl (currcsr6, ioaddr + CSR6);
- udelay (1);
- }
-
-out_write:
- /* now it is safe to change csr6 */
- outl (newcsr6, ioaddr + CSR6);
-}
-
static void tulip_up(struct net_device *dev)
{
@@ -264,11 +220,13 @@ static void tulip_up(struct net_device *dev)
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
outl(0x00000001, ioaddr + CSR0);
+ udelay(100);
/* Deassert reset.
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
outl(tp->csr0, ioaddr + CSR0);
+ udelay(100);
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);
@@ -561,7 +519,6 @@ static void tulip_tx_timeout(struct net_device *dev)
out:
dev->trans_start = jiffies;
- netif_start_queue (dev);
spin_unlock_irqrestore (&tp->lock, flags);
}
@@ -786,14 +743,14 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
if (tp->mii_cnt)
data[0] = phy;
- else if (tp->flags & HAS_NWAY143)
+ else if (tp->flags & HAS_NWAY)
data[0] = 32;
else if (tp->chip_id == COMET)
data[0] = 1;
else
return -ENODEV;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
+ if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
int csr12 = inl(ioaddr + CSR12);
int csr14 = inl(ioaddr + CSR14);
switch (data[1]) {
@@ -821,7 +778,7 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
+ if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
if (data[1] == 5)
tp->to_advertise = data[2];
} else {
@@ -1108,9 +1065,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
/* Clear the missed-packet counter. */
(volatile int)inl(ioaddr + CSR8);
- if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) {
- printk(" 21040 compatible mode,");
- chip_idx = DC21040;
+ if (chip_idx == DC21041) {
+ if (inl(ioaddr + CSR9) & 0x8000) {
+ printk(" 21040 compatible mode,");
+ chip_idx = DC21040;
+ } else {
+ printk(" 21041 mode,");
+ }
}
/* The station address ROM is read byte serially. The register must
@@ -1307,7 +1268,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->do_ioctl = private_ioctl;
dev->set_multicast_list = set_rx_mode;
- if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041)
+ if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041)
tp->link_change = t21142_lnk_change;
else if (tp->flags & HAS_PNICNWAY)
tp->link_change = pnic_lnk_change;
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 4c52f055c..a9988e77b 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -27,16 +27,19 @@
LK1.1.1:
- Justin Guyett: softnet and locking fixes
- Jeff Garzik: use PCI interface
-
-*/
-static const char *versionA =
-"via-rhine.c:v1.01-LK1.1.1 3/2/2000 Written by Donald Becker\n";
-static const char *versionB =
-" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
+ LK1.1.2:
+ - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
+
+ LK1.1.3:
+ - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c code)
+ update "Theory of Operation" with softnet/locking changes
+ - Dave Miller: PCI DMA and endian fixups
+ - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
+*/
/* A few user-configurable values. These may be modified when a driver
- module is loaded.*/
+ module is loaded. */
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
static int max_interrupt_work = 20;
@@ -58,6 +61,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
The Rhine has a 64 element 8390-like hash table. */
static const int multicast_filter_limit = 32;
+
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for compile efficiency.
@@ -68,12 +72,21 @@ static const int multicast_filter_limit = 32;
#define TX_RING_SIZE 8
#define RX_RING_SIZE 16
+
/* Operational parameters that usually are not changed. */
+
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (2*HZ)
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error See the last lines of the source file for the proper compile-command.
+#endif
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -91,15 +104,20 @@ static const int multicast_filter_limit = 32;
#include <asm/bitops.h>
#include <asm/io.h>
-/* This driver was written to use PCI memory space, however some x86
- motherboards only configure I/O space accesses correctly. */
-#if defined(__i386__) && !defined(VIA_USE_MEMORY)
-#define VIA_USE_IO
-#endif
-#if defined(__alpha__)
-#define VIA_USE_IO
-#endif
-#ifdef VIA_USE_IO
+static const char *versionA __devinitdata =
+"via-rhine.c:v1.03a-LK1.1.3 3/23/2000 Written by Donald Becker\n";
+static const char *versionB __devinitdata =
+" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
+
+
+
+/* This driver was written to use PCI memory space, however most versions
+ of the Rhine only work correctly with I/O space accesses. */
+#if defined(VIA_USE_MEMORY)
+#warning Many adapters using the VIA Rhine chip are not configured to work
+#warning with PCI memory space accesses.
+#else
+#define USE_IO
#undef readb
#undef readw
#undef readl
@@ -114,9 +132,6 @@ static const int multicast_filter_limit = 32;
#define writel outl
#endif
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
- This is only in the support-all-kernels source code. */
-
#define RUN_AT(x) (jiffies + (x))
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
@@ -186,18 +201,17 @@ IIId. Synchronization
The driver runs as two independent, single-threaded flows of control. One
is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag. The other thread is the interrupt handler, which is single
-threaded by the hardware and interrupt handling software.
+dev->priv->lock spinlock. The other thread is the interrupt handler, which
+is single threaded by the hardware and interrupt handling software.
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'lp->tx_full' flag.
+The send packet thread has partial control over the Tx ring. It locks the
+dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring
+is not available it stops the transmit queue by calling netif_stop_queue.
The interrupt handler has exclusive control over the Rx ring and records stats
from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-clears both the tx_full and tbusy flags.
+empty by incrementing the dirty_tx mark. If at least half of the entries in
+the Rx ring are available the transmit queue is woken up if it was stopped.
IV. Notes
@@ -231,57 +245,49 @@ enum pci_flags_bit {
};
enum via_rhine_chips {
- vt86c100a = 0,
- vt3043,
+ VT86C100A = 0,
+ VT3043,
};
struct via_rhine_chip_info {
const char *name;
- u16 flags;
+ u16 pci_flags;
int io_size;
+ int drv_flags;
};
+enum chip_capability_flags {CanHaveMII=1, };
+
+#if defined(VIA_USE_MEMORY)
+#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1)
+#else
+#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0)
+#endif
+
/* directly indexed by enum via_rhine_chips, above */
static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata =
{
- {"VIA VT86C100A Rhine-II",
- PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
- 128,},
- {"VIA VT3043 Rhine",
- PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
- 128,},
+ { "VIA VT86C100A Rhine-II", RHINE_IOTYPE, 128, CanHaveMII },
+ { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII }
};
static struct pci_device_id via_rhine_pci_tbl[] __devinitdata =
{
- {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a},
- {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043},
+ {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A},
+ {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043},
{0,}, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl);
-
-/* A chip capabilities table, matching the entries in pci_tbl[] above. */
-enum chip_capability_flags {CanHaveMII=1, };
-struct chip_info {
- int io_size;
- int flags;
-} static cap_tbl[] = {
- {128, CanHaveMII, },
- {128, CanHaveMII, },
-};
-
-
-/* Offsets to the device registers.
-*/
+/* Offsets to the device registers. */
enum register_offsets {
StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
IntrStatus=0x0C, IntrEnable=0x0E,
MulticastFilter0=0x10, MulticastFilter1=0x14,
RxRingPtr=0x18, TxRingPtr=0x1C,
- MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E,
+ MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72,
Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E,
};
@@ -295,21 +301,19 @@ enum intr_status_bits {
IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
IntrTxAborted=0x2000, IntrLinkChange=0x4000,
IntrRxWakeUp=0x8000,
- IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260,
+ IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
};
/* The Rx and Tx buffer descriptors. */
struct rx_desc {
- u16 rx_status;
- u16 rx_length;
+ s32 rx_status;
u32 desc_length;
u32 addr;
u32 next_desc;
};
struct tx_desc {
- u16 tx_status;
- u16 tx_own;
+ s32 tx_status;
u32 desc_length;
u32 addr;
u32 next_desc;
@@ -317,9 +321,11 @@ struct tx_desc {
/* Bits in *_desc.status */
enum rx_status_bits {
- RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F};
+ RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
+};
+
enum desc_status_bits {
- DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000,
+ DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
};
/* Bits in ChipCmd. */
@@ -331,32 +337,42 @@ enum chip_cmd_bits {
};
struct netdev_private {
- /* Descriptor rings first for alignment. */
- struct rx_desc rx_ring[RX_RING_SIZE];
- struct tx_desc tx_ring[TX_RING_SIZE];
+ /* Descriptor rings */
+ struct rx_desc *rx_ring;
+ struct tx_desc *tx_ring;
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+
/* The addresses of receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ dma_addr_t rx_skbuff_dma[RX_RING_SIZE];
+
/* The saved address of a sent-in-place packet/buffer, for later free(). */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ dma_addr_t tx_skbuff_dma[TX_RING_SIZE];
unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
+
+ struct pci_dev *pdev;
struct net_device_stats stats;
struct timer_list timer; /* Media monitoring timer. */
spinlock_t lock;
+
/* Frequently used values: keep some adjacent for cache effect. */
int chip_id;
struct rx_desc *rx_head_desc;
- unsigned short int cur_rx, dirty_rx; /* Producer/consumer ring indices */
- unsigned short int cur_tx, dirty_tx;
+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
+ unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
u16 chip_cmd; /* Current setting for ChipCmd */
unsigned int tx_full:1; /* The Tx queue is full. */
+
/* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int duplex_lock:1;
unsigned int medialock:1; /* Do not sense media. */
unsigned int default_port:4; /* Last dev->if_port value. */
u8 tx_thresh, rx_thresh;
+
/* MII transceiver section. */
int mii_cnt; /* MII device addresses. */
u16 advertising; /* NWay media advertisement */
@@ -393,6 +409,9 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
static int did_version = 0;
long ioaddr;
int io_size;
+ int pci_flags;
+ void *ring;
+ dma_addr_t ring_dma;
/* print version once and once only */
if (! did_version++) {
@@ -403,44 +422,67 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
card_idx++;
option = card_idx < MAX_UNITS ? options[card_idx] : 0;
io_size = via_rhine_chip_info[chip_id].io_size;
+ pci_flags = via_rhine_chip_info[chip_id].pci_flags;
+
+ /* this should always be supported */
+ if (!pci_dma_supported(pdev, 0xffffffff)) {
+ printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n");
+ goto err_out;
+ }
+
+ /* sanity check */
+ if ((pci_resource_len (pdev, 0) < io_size) ||
+ (pci_resource_len (pdev, 1) < io_size)) {
+ printk (KERN_ERR "Insufficient PCI resources, aborting\n");
+ goto err_out;
+ }
+ /* allocate pci dma space for rx and tx descriptor rings */
+ ring = pci_alloc_consistent(pdev,
+ RX_RING_SIZE * sizeof(struct rx_desc) +
+ TX_RING_SIZE * sizeof(struct tx_desc),
+ &ring_dma);
+ if (!ring) {
+ printk(KERN_ERR "Could not allocate DMA memory.\n");
+ goto err_out;
+ }
-#ifdef VIA_USE_IO
- ioaddr = pci_resource_start (pdev, 0);
-#else
- ioaddr = pci_resource_start (pdev, 1);
-#endif
+ ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1);
if (pci_enable_device (pdev)) {
printk (KERN_ERR "unable to init PCI device (card #%d)\n",
card_idx);
- goto err_out;
+ goto err_out_free_dma;
}
- if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER)
+ if (pci_flags & PCI_USES_MASTER)
pci_set_master (pdev);
dev = init_etherdev(NULL, sizeof(*np));
if (dev == NULL) {
printk (KERN_ERR "init_ethernet failed for card #%d\n",
card_idx);
- goto err_out;
+ goto err_out_free_dma;
}
- if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) {
+ /* request all PIO and MMIO regions just to make sure
+ * noone else attempts to use any portion of our I/O space */
+ if (!request_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0), dev->name)) {
printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n",
dev->name, io_size,
pci_resource_start (pdev, 0));
goto err_out_free_netdev;
}
- if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) {
+ if (!request_mem_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1), dev->name)) {
printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n",
dev->name, io_size,
pci_resource_start (pdev, 1));
goto err_out_free_pio;
}
-#ifndef VIA_USE_IO
+#ifndef USE_IO
ioaddr = (long) ioremap (ioaddr, io_size);
if (!ioaddr) {
printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n",
@@ -469,6 +511,11 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
np = dev->priv;
spin_lock_init (&np->lock);
np->chip_id = chip_id;
+ np->pdev = pdev;
+ np->rx_ring = ring;
+ np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
+ np->rx_ring_dma = ring_dma;
+ np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc);
if (dev->mem_start)
option = dev->mem_start;
@@ -499,7 +546,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
pdev->driver_data = dev;
- if (cap_tbl[np->chip_id].flags & CanHaveMII) {
+ if (via_rhine_chip_info[chip_id].drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
np->phys[0] = 1; /* Standard for this chip. */
for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
@@ -518,18 +565,25 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
return 0;
-#ifndef VIA_USE_IO
+#ifndef USE_IO
/* note this is ifdef'd because the ioremap is ifdef'd...
* so additional exit conditions above this must move
* release_mem_region outside of the ifdef */
err_out_free_mmio:
- release_mem_region(pci_resource_start (pdev, 1), io_size, dev->name));
+ release_mem_region(pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1));
#endif
err_out_free_pio:
- release_region(pci_resource_start (pdev, 0), io_size);
+ release_region(pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
err_out_free_netdev:
unregister_netdev (dev);
kfree (dev);
+err_out_free_dma:
+ pci_free_consistent(pdev,
+ RX_RING_SIZE * sizeof(struct rx_desc) +
+ TX_RING_SIZE * sizeof(struct tx_desc),
+ ring, ring_dma);
err_out:
return -ENODEV;
}
@@ -557,9 +611,12 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum)
static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value)
{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
long ioaddr = dev->base_addr;
int boguscnt = 1024;
+ if (phy_id == np->phys[0] && regnum == 4)
+ np->advertising = value;
/* Wait for a previous command to complete. */
while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0)
;
@@ -578,32 +635,34 @@ static int via_rhine_open(struct net_device *dev)
long ioaddr = dev->base_addr;
int i;
+ MOD_INC_USE_COUNT;
+
/* Reset the chip. */
writew(CmdReset, ioaddr + ChipCmd);
- if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev))
- return -EAGAIN;
+ if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
if (debug > 1)
printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
dev->name, dev->irq);
- MOD_INC_USE_COUNT;
-
via_rhine_init_ring(dev);
- writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
- writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
+ writel(np->rx_ring_dma, ioaddr + RxRingPtr);
+ writel(np->tx_ring_dma, ioaddr + TxRingPtr);
for (i = 0; i < 6; i++)
writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
/* Initialize other registers. */
- writew(0x0006, ioaddr + PCIConfig); /* Tune configuration??? */
+ writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */
/* Configure the FIFO thresholds. */
writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */
np->tx_thresh = 0x20;
- np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */
+ np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */
if (dev->if_port == 0)
dev->if_port = np->default_port;
@@ -666,6 +725,7 @@ static void via_rhine_check_duplex(struct net_device *dev)
}
}
+
static void via_rhine_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
@@ -677,12 +737,14 @@ static void via_rhine_timer(unsigned long data)
printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
dev->name, readw(ioaddr + IntrStatus));
}
+
via_rhine_check_duplex(dev);
np->timer.expires = RUN_AT(next_tick);
add_timer(&np->timer);
}
+
static void via_rhine_tx_timeout (struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *) dev->priv;
@@ -693,16 +755,17 @@ static void via_rhine_tx_timeout (struct net_device *dev)
dev->name, readw (ioaddr + IntrStatus),
mdio_read (dev, np->phys[0], 1));
- /* Perhaps we should reinitialize the hardware here. */
+ /* XXX Perhaps we should reinitialize the hardware here. */
dev->if_port = 0;
+
/* Stop and restart the chip's Tx processes . */
+ /* XXX to do */
/* Trigger an immediate transmit demand. */
+ /* XXX to do */
dev->trans_start = jiffies;
np->stats.tx_errors++;
-
- netif_start_queue (dev);
}
@@ -720,13 +783,13 @@ static void via_rhine_init_ring(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].rx_length = 0;
- np->rx_ring[i].desc_length = np->rx_buf_sz;
- np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);
+ np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
+ np->rx_ring[i].next_desc =
+ cpu_to_le32(np->rx_ring_dma + sizeof(struct rx_desc)*(i+1));
np->rx_skbuff[i] = 0;
}
/* Mark the last entry as wrapping the ring. */
- np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);
+ np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma);
/* Fill in the Rx buffers. */
for (i = 0; i < RX_RING_SIZE; i++) {
@@ -734,20 +797,25 @@ static void via_rhine_init_ring(struct net_device *dev)
np->rx_skbuff[i] = skb;
if (skb == NULL)
break;
- skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[i].addr = virt_to_bus(skb->tail);
- np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].rx_length = DescOwn;
+ skb->dev = dev; /* Mark as being used by this device. */
+
+ np->rx_skbuff_dma[i] =
+ pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+
+ np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]);
+ np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
}
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_skbuff[i] = 0;
- np->tx_ring[i].tx_own = 0;
- np->tx_ring[i].desc_length = 0x00e08000;
- np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]);
+ np->tx_ring[i].tx_status = 0;
+ np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+ np->tx_ring[i].next_desc =
+ cpu_to_le32(np->tx_ring_dma + sizeof(struct tx_desc)*(i+1));
np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
}
- np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]);
+ np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
return;
}
@@ -771,16 +839,24 @@ static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
if ((long)skb->data & 3) { /* Must use alignment buffer. */
if (np->tx_buf[entry] == NULL &&
- (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL)
+ (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) {
+ spin_unlock_irqrestore (&np->lock, flags);
return 1;
+ }
memcpy(np->tx_buf[entry], skb->data, skb->len);
- np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]);
- } else
- np->tx_ring[entry].addr = virt_to_bus(skb->data);
+ np->tx_skbuff_dma[entry] =
+ pci_map_single(np->pdev, np->tx_buf[entry], skb->len,
+ PCI_DMA_TODEVICE);
+ } else {
+ np->tx_skbuff_dma[entry] =
+ pci_map_single(np->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ }
+ np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]);
- np->tx_ring[entry].desc_length = 0x00E08000 |
- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
- np->tx_ring[entry].tx_own = DescOwn;
+ np->tx_ring[entry].desc_length =
+ cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+ np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
np->cur_tx++;
@@ -848,7 +924,7 @@ static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs
}
/* This routine is logically part of the interrupt handler, but isolated
- for clarity and better register allocation. */
+ for clarity. */
static void via_rhine_tx(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -858,15 +934,15 @@ static void via_rhine_tx(struct net_device *dev)
/* if tx_full is set, they're all dirty, not clean */
while (np->dirty_tx != np->cur_tx) {
- if (np->tx_ring[entry].tx_own) /* transmit request pending */
+ txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
+ if (txstatus & DescOwn)
break;
- txstatus = np->tx_ring[entry].tx_status;
if (debug > 6)
- printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
+ printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
entry, txstatus);
if (txstatus & 0x8000) {
if (debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
dev->name, txstatus);
np->stats.tx_errors++;
if (txstatus & 0x0400) np->stats.tx_carrier_errors++;
@@ -877,12 +953,15 @@ static void via_rhine_tx(struct net_device *dev)
/* Transmitter restarted in 'abnormal' handler. */
} else {
np->stats.collisions += (txstatus >> 3) & 15;
- np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
+ np->stats.tx_bytes += le32_to_cpu(np->tx_ring[entry].desc_length) & 0x7ff;
np->stats.tx_packets++;
- }
- /* Free the original skb. */
- dev_kfree_skb_irq(np->tx_skbuff[entry]);
- np->tx_skbuff[entry] = NULL;
+ }
+ /* Free the original skb. */
+ pci_unmap_single(np->pdev,
+ le32_to_cpu(np->tx_ring[entry].addr),
+ np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(np->tx_skbuff[entry]);
+ np->tx_skbuff[entry] = NULL;
entry = (++np->dirty_tx) % TX_RING_SIZE;
}
if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2)
@@ -896,33 +975,32 @@ static void via_rhine_tx(struct net_device *dev)
static void via_rhine_rx(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
- int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE;
- int boguscnt = RX_RING_SIZE;
+ int entry = np->cur_rx % RX_RING_SIZE;
+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
if (debug > 4) {
- printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n",
- entry, np->rx_head_desc->rx_length);
+ printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %8.8x.\n",
+ entry, le32_to_cpu(np->rx_head_desc->rx_status));
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
- while ( ! (np->rx_head_desc->rx_length & DescOwn)) {
+ while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
struct rx_desc *desc = np->rx_head_desc;
- int data_size = desc->rx_length;
- u16 desc_status = desc->rx_status;
+ u32 desc_status = le32_to_cpu(desc->rx_status);
+ int data_size = desc_status >> 16;
if (debug > 4)
- printk(KERN_DEBUG " via_rhine_rx() status is %4.4x.\n",
+ printk(KERN_DEBUG " via_rhine_rx() status is %8.8x.\n",
desc_status);
if (--boguscnt < 0)
break;
if ( (desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
if ((desc_status & RxWholePkt) != RxWholePkt) {
printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
- "multiple buffers, entry %#x length %d status %4.4x!\n",
+ "multiple buffers, entry %#x length %d status %8.8x!\n",
dev->name, entry, data_size, desc_status);
printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",
- dev->name, np->rx_head_desc,
- &np->rx_ring[entry]);
+ dev->name, np->rx_head_desc, &np->rx_ring[entry]);
np->stats.rx_length_errors++;
} else if (desc_status & RxErr) {
/* There was a error. */
@@ -942,25 +1020,35 @@ static void via_rhine_rx(struct net_device *dev)
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
- if (pkt_len < rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+ if (pkt_len < rx_copybreak &&
+ (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the IP header */
+ pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry],
+ np->rx_buf_sz, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__) || USE_IP_COPYSUM /* Avoid misaligned on Alpha */
- eth_copy_and_sum(skb, bus_to_virt(desc->addr),
- pkt_len, 0);
+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
skb_put(skb, pkt_len);
#else
- memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len);
+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
+ pkt_len);
#endif
} else {
- skb_put(skb = np->rx_skbuff[entry], pkt_len);
+ skb = np->rx_skbuff[entry];
+ if (skb == NULL) {
+ printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",
+ dev->name);
+ break;
+ }
np->rx_skbuff[entry] = NULL;
+ skb_put(skb, pkt_len);
+ pci_unmap_single(np->pdev, np->rx_skbuff_dma[entry],
+ np->rx_buf_sz, PCI_DMA_FROMDEVICE);
}
skb->protocol = eth_type_trans(skb, dev);
- np->stats.rx_bytes+=skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
+ np->stats.rx_bytes += skb->len;
np->stats.rx_packets++;
}
entry = (++np->cur_rx) % RX_RING_SIZE;
@@ -968,19 +1056,21 @@ static void via_rhine_rx(struct net_device *dev)
}
/* Refill the Rx ring buffers. */
- while (np->dirty_rx != np->cur_rx) {
+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
struct sk_buff *skb;
- entry = np->dirty_rx++ % RX_RING_SIZE;
+ entry = np->dirty_rx % RX_RING_SIZE;
if (np->rx_skbuff[entry] == NULL) {
skb = dev_alloc_skb(np->rx_buf_sz);
np->rx_skbuff[entry] = skb;
if (skb == NULL)
break; /* Better luck next round. */
skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[entry].addr = virt_to_bus(skb->tail);
+ np->rx_skbuff_dma[entry] =
+ pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]);
}
- np->rx_ring[entry].rx_status = 0;
- np->rx_ring[entry].rx_length = DescOwn;
+ np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
}
/* Pre-emptively restart Rx engine. */
@@ -1020,7 +1110,8 @@ static void via_rhine_error(struct net_device *dev, int intr_status)
printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
"threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
}
- if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) {
+ if ((intr_status & ~( IntrLinkChange | IntrStatsMax |
+ IntrTxAbort | IntrTxAborted)) && debug > 1) {
printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
dev->name, intr_status);
/* Recovery for other fault sources not known. */
@@ -1076,6 +1167,8 @@ static void via_rhine_set_rx_mode(struct net_device *dev)
} else if ((dev->mc_count > multicast_filter_limit)
|| (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
+ writel(0xffffffff, ioaddr + MulticastFilter0);
+ writel(0xffffffff, ioaddr + MulticastFilter1);
rx_mode = 0x0C;
} else {
struct dev_mc_list *mclist;
@@ -1083,12 +1176,11 @@ static void via_rhine_set_rx_mode(struct net_device *dev)
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26,
- mc_filter);
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
}
writel(mc_filter[0], ioaddr + MulticastFilter0);
writel(mc_filter[1], ioaddr + MulticastFilter1);
- rx_mode = 0x08;
+ rx_mode = 0x0C;
}
writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
}
@@ -1138,13 +1230,17 @@ static int via_rhine_close(struct net_device *dev)
/* Free all the skbuffs in the Rx queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
- np->rx_ring[i].rx_length = 0;
- np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+ np->rx_ring[i].rx_status = 0;
+ np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
if (np->rx_skbuff[i]) {
+ pci_unmap_single(np->pdev,
+ np->rx_skbuff_dma[i],
+ np->rx_buf_sz, PCI_DMA_FROMDEVICE);
dev_kfree_skb(np->rx_skbuff[i]);
}
np->rx_skbuff[i] = 0;
}
+
for (i = 0; i < TX_RING_SIZE; i++) {
if (np->tx_skbuff[i])
dev_kfree_skb(np->tx_skbuff[i]);
@@ -1165,14 +1261,19 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
unregister_netdev(dev);
release_region(pci_resource_start (pdev, 0),
- via_rhine_chip_info[np->chip_id].io_size);
+ pci_resource_len (pdev, 0));
release_mem_region(pci_resource_start (pdev, 1),
- via_rhine_chip_info[np->chip_id].io_size);
+ pci_resource_len (pdev, 1));
-#ifndef VIA_USE_IO
+#ifndef USE_IO
iounmap((char *)(dev->base_addr));
#endif
+ pci_free_consistent(pdev,
+ RX_RING_SIZE * sizeof(struct rx_desc) +
+ TX_RING_SIZE * sizeof(struct tx_desc),
+ np->rx_ring, np->rx_ring_dma);
+
kfree(dev);
}
@@ -1187,7 +1288,15 @@ static struct pci_driver via_rhine_driver = {
static int __init via_rhine_init (void)
{
- return pci_module_init (&via_rhine_driver);
+ int rc;
+
+ MOD_INC_USE_COUNT;
+
+ rc = pci_module_init (&via_rhine_driver);
+
+ MOD_DEC_USE_COUNT;
+
+ return rc;
}
diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
index e0a6f5e8f..4ffe0730f 100644
--- a/drivers/net/wan/Config.in
+++ b/drivers/net/wan/Config.in
@@ -55,9 +55,11 @@ if [ "$CONFIG_WAN" = "y" ]; then
if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1
bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC
- bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+ bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25
+ fi
bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP
- bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index d2bb93c74..e8bd316e6 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -1,3 +1,12 @@
+2000-03-22 Tim Waugh <twaugh@redhat.com>
+
+ * init.c (parport_setup): Fix return value.
+
+2000-03-21 Tim Waugh <twaugh@redhat.com>
+
+ * parport_pc.c (parport_pc_pci_probe): Fix return value; call
+ pci_enable_device.
+
2000-03-16 Tim Waugh <twaugh@redhat.com>
* parport_pc.c (parport_ECP_supported): This seems to trigger on
diff --git a/drivers/parport/init.c b/drivers/parport/init.c
index a43d59dbe..8ad352774 100644
--- a/drivers/parport/init.c
+++ b/drivers/parport/init.c
@@ -49,13 +49,13 @@ static int __init parport_setup (char *str)
if (!str || !*str || (*str == '0' && !*(str+1))) {
/* Disable parport if "parport=0" in cmdline */
io[0] = PARPORT_DISABLE;
- return 0;
+ return 1;
}
if (!strncmp (str, "auto", 4)) {
irq[0] = PARPORT_IRQ_AUTO;
dma[0] = PARPORT_DMA_AUTO;
- return 0;
+ return 1;
}
val = simple_strtoul (str, &endptr, 0);
@@ -108,7 +108,7 @@ static int __init parport_setup (char *str)
}
parport_setup_ptr++;
- return 0;
+ return 1;
}
__setup ("parport=", parport_setup);
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index dbbd12864..16b5ea3fe 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2348,7 +2348,7 @@ MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
const struct pci_device_id *id)
{
- int count, n, i = id->driver_data;
+ int err, count, n, i = id->driver_data;
if (i < last_sio)
/* This is an onboard Super-IO and has already been probed */
return 0;
@@ -2356,6 +2356,9 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
/* This is a PCI card */
i -= last_sio;
count = 0;
+ if ((err = pci_enable_device (dev)) != 0)
+ return err;
+
for (n = 0; n < cards[i].numports; n++) {
int lo = cards[i].addr[n].lo;
int hi = cards[i].addr[n].hi;
@@ -2370,7 +2373,7 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
count++;
}
- return count;
+ return count == 0 ? -ENODEV : 0;
}
static struct pci_driver parport_pc_pci_driver = {
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0b6614fe1..8f523cdf4 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -33,6 +33,16 @@
LIST_HEAD(pci_root_buses);
LIST_HEAD(pci_devices);
+/**
+ * pci_find_slot - locate PCI device from a given PCI slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: number of PCI slot in which desired PCI device resides
+ *
+ * Given a PCI bus and slot number, the desired PCI device is
+ * located in system global list of PCI devices. If the device
+ * is found, a pointer to its data structure is returned. If no
+ * device is found, %NULL is returned.
+ */
struct pci_dev *
pci_find_slot(unsigned int bus, unsigned int devfn)
{
@@ -66,6 +76,19 @@ pci_find_subsys(unsigned int vendor, unsigned int device,
}
+/**
+ * pci_find_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all vendor ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is
+ * found with a matching @vendor and @device, a pointer to its device structure is
+ * returned. Otherwise, %NULL is returned.
+ *
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not null, searches continue from that point.
+ */
struct pci_dev *
pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
{
@@ -73,6 +96,18 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *
}
+/**
+ * pci_find_class - begin or continue searching for a PCI device by class
+ * @class: search for a PCI device with this class designation
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is
+ * found with a matching @class, a pointer to its device structure is
+ * returned. Otherwise, %NULL is returned.
+ *
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not null, searches continue from that point.
+ */
struct pci_dev *
pci_find_class(unsigned int class, const struct pci_dev *from)
{
@@ -122,7 +157,11 @@ pci_find_capability(struct pci_dev *dev, int cap)
}
-/*
+/**
+ * pci_find_parent_resource - return resource region of parent bus of given region
+ * @dev: PCI device structure contains resources to be searched
+ * @res: child resource record for which parent is sought
+ *
* For given resource region of given device, return the resource
* region of parent bus the given region is contained in or where
* it should be allocated from.
@@ -150,7 +189,11 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
return best;
}
-/*
+/**
+ * pci_set_power_state - Set power management state of a device.
+ * @dev: PCI device for which PM is set
+ * @new_state: new power management statement (0 == D0, 3 == D3, etc.)
+ *
* Set power management state of a device. For transitions from state D3
* it isn't as straightforward as one could assume since many devices forget
* their configuration space during wakeup. Returns old power state.
@@ -192,7 +235,10 @@ pci_set_power_state(struct pci_dev *dev, int new_state)
return old_state;
}
-/*
+/**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ *
* Initialize device before it's used by a driver. Ask low-level code
* to enable I/O and memory. Wake up the device if it was suspended.
* Beware, this function can fail.
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index 16c881f7d..e47662901 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -137,16 +137,32 @@
#ifdef CONFIG_CARDBUS
/*
- * Generic TI open - TI has an extension for the
+ * Generic TI init - TI has an extension for the
* INTCTL register that sets the PCI CSC interrupt.
* Make sure we set it correctly at open and init
- * time.
+ * time
+ * - open: disable the PCI CSC interrupt. This makes
+ * it possible to use the CSC interrupt to probe the
+ * ISA interrupts.
+ * - init: set the interrupt to match our PCI state.
+ * This makes us correctly get PCI CSC interrupt
+ * events.
*/
static int ti_open(pci_socket_t *socket)
{
u8 new, reg = exca_readb(socket, I365_INTCTL);
new = reg & ~I365_INTR_ENA;
+ if (new != reg)
+ exca_writeb(socket, I365_INTCTL, new);
+ return 0;
+}
+
+static int ti_intctl(pci_socket_t *socket)
+{
+ u8 new, reg = exca_readb(socket, I365_INTCTL);
+
+ new = reg & ~I365_INTR_ENA;
if (socket->cb_irq)
new |= I365_INTR_ENA;
if (new != reg)
@@ -157,7 +173,7 @@ static int ti_open(pci_socket_t *socket)
static int ti_init(pci_socket_t *socket)
{
yenta_init(socket);
- ti_open(socket);
+ ti_intctl(socket);
return 0;
}
@@ -200,7 +216,7 @@ static int ti113x_init(pci_socket_t *socket)
config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket));
- ti_open(socket);
+ ti_intctl(socket);
return 0;
}
@@ -237,7 +253,7 @@ static int ti1250_init(pci_socket_t *socket)
yenta_init(socket);
config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket));
- ti_open(socket);
+ ti_intctl(socket);
return 0;
}
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index a8b311780..294895733 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -851,22 +851,3 @@ struct pci_socket_ops yenta_operations = {
yenta_proc_setup
};
EXPORT_SYMBOL(yenta_operations);
-
-/*
- * Ricoh cardbus bridge: standard cardbus, except it needs
- * some extra init code to set timings etc.
- */
-struct pci_socket_ops ricoh_operations = {
- yenta_open,
- yenta_close,
- ricoh_init,
- yenta_suspend,
- yenta_get_status,
- yenta_get_socket,
- yenta_set_socket,
- yenta_get_io_map,
- yenta_set_io_map,
- yenta_get_mem_map,
- yenta_set_mem_map,
- yenta_proc_setup
-};
diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
index 51468e1ef..06bf94664 100644
--- a/drivers/pnp/isapnp.c
+++ b/drivers/pnp/isapnp.c
@@ -1208,6 +1208,50 @@ struct pci_dev *isapnp_find_dev(struct pci_bus *card,
return NULL;
}
+static const struct isapnp_card_id *
+isapnp_match_card(const struct isapnp_card_id *ids, struct pci_bus *card)
+{
+ int idx;
+
+ while (ids->vendor || ids->device) {
+ if ((ids->vendor == ISAPNP_ANY_ID || ids->vendor == card->vendor) &&
+ (ids->device == ISAPNP_ANY_ID || ids->device == card->device)) {
+ for (idx = 0; idx < ISAPNP_CARD_DEVS; idx++) {
+ if (ids->devs[idx].vendor == 0 &&
+ ids->devs[idx].function == 0)
+ return ids;
+ if (isapnp_find_dev(card,
+ ids->devs[idx].vendor,
+ ids->devs[idx].function,
+ NULL) == NULL)
+ goto __next;
+ }
+ return ids;
+ }
+ __next:
+ ids++;
+ }
+ return NULL;
+}
+
+int isapnp_probe_cards(const struct isapnp_card_id *ids,
+ int (*probe)(struct pci_bus *_card,
+ const struct isapnp_card_id *_id))
+{
+ struct pci_bus *card;
+ const struct isapnp_card_id *id;
+ int count = 0;
+
+ if (ids == NULL || probe == NULL)
+ return -EINVAL;
+ isapnp_for_each_card(card) {
+ id = isapnp_match_card(ids, card);
+ if (id != NULL && probe(card, id) >= 0)
+ count++;
+ }
+ return count;
+}
+
static unsigned int isapnp_dma_resource_flags(struct isapnp_dma *dma)
{
return dma->flags | IORESOURCE_DMA | IORESOURCE_AUTO;
@@ -2065,6 +2109,8 @@ static void __init isapnp_pci_init(void)
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL(isapnp_cards);
+EXPORT_SYMBOL(isapnp_devices);
EXPORT_SYMBOL(isapnp_present);
EXPORT_SYMBOL(isapnp_cfg_begin);
EXPORT_SYMBOL(isapnp_cfg_end);
@@ -2080,6 +2126,7 @@ EXPORT_SYMBOL(isapnp_activate);
EXPORT_SYMBOL(isapnp_deactivate);
EXPORT_SYMBOL(isapnp_find_card);
EXPORT_SYMBOL(isapnp_find_dev);
+EXPORT_SYMBOL(isapnp_probe_cards);
EXPORT_SYMBOL(isapnp_resource_change);
int __init isapnp_init(void)
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 08acf4f81..039994471 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.15 2000/02/09 22:33:23 davem Exp $
+/* $Id: envctrl.c,v 1.16 2000/03/22 21:29:23 ecd Exp $
* envctrl.c: Temperature and Fan monitoring on Machines providing it.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
@@ -1002,7 +1002,6 @@ rasctrl_setup(int node)
return 0;
out:
- envctrl_stop();
return -ENODEV;
}
@@ -1381,7 +1380,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "cpu-temp-factors",
envctrl.cpu_temp_table, 256);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `cpu-temp-factors'\n");
goto out;
}
@@ -1398,7 +1397,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "cpu-fan-speeds",
envctrl.cpu_fan_speeds, 112);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `cpu-fan-speeds'\n");
goto out;
}
@@ -1415,7 +1414,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "ps-temp-factors",
envctrl.ps_temp_table, 256);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `ps-temp-factors'\n");
goto out;
}
@@ -1432,7 +1431,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "ps-fan-speeds",
envctrl.ps_fan_speeds, 112);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `ps-fan-speeds'\n");
goto out;
}
@@ -1449,8 +1448,6 @@ envctrl_setup(int node)
out:
if (tmp)
kfree(tmp);
-
- envctrl_stop();
return err;
}
#endif /* U450_SUPPORT */
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c
index 091702d15..f1641a33a 100644
--- a/drivers/sbus/char/sunmouse.c
+++ b/drivers/sbus/char/sunmouse.c
@@ -69,7 +69,6 @@ struct sun_mouse {
unsigned char prev_state; /* Previous button state */
int delta_x; /* Current delta-x */
int delta_y; /* Current delta-y */
- int present;
int ready; /* set if there if data is available */
int active; /* set if device is open */
int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */
@@ -382,8 +381,6 @@ sun_mouse_open(struct inode * inode, struct file * file)
{
if(sunmouse.active++)
return 0;
- if(!sunmouse.present)
- return -EINVAL;
sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
sunmouse.button_state = 0x80;
sunmouse.vuid_mode = VUID_NATIVE;
@@ -555,11 +552,8 @@ static struct miscdevice sun_mouse_mouse = {
SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
};
-int __init sun_mouse_init(void)
+void sun_mouse_zsinit(void)
{
- if (!sunmouse.present)
- return -ENODEV;
-
printk("Sun Mouse-Systems mouse driver version 1.00\n");
sunmouse.ready = sunmouse.active = 0;
@@ -568,11 +562,4 @@ int __init sun_mouse_init(void)
sunmouse.button_state = 0x80;
init_waitqueue_head(&sunmouse.proc_list);
sunmouse.byte = 69;
- return 0;
-}
-
-void
-sun_mouse_zsinit(void)
-{
- sunmouse.present = 1;
}
diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c
index 9719f625a..e58eb1ef7 100644
--- a/drivers/sbus/char/sunserial.c
+++ b/drivers/sbus/char/sunserial.c
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.74 1999/12/15 22:30:23 davem Exp $
+/* $Id: sunserial.c,v 1.75 2000/03/22 02:45:36 davem Exp $
* serial.c: Serial port driver infrastructure for the Sparc.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -67,6 +67,8 @@ int rs_init(void)
return err;
}
+__initcall(rs_init);
+
void __init rs_kgdb_hook(int channel)
{
rs_ops.rs_kgdb_hook(channel);
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 74644cccf..81a164066 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -738,18 +738,12 @@ sim710_u.h: sim710_d.h
sim710.o : sim710_d.h
-initio.o: ini9100u.c i91uscsi.c
- $(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o
- $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o
+initio.o: ini9100u.o i91uscsi.o
$(LD) -r -o initio.o ini9100u.o i91uscsi.o
- rm -f ini9100u.o i91uscsi.o
a100u2w.o: inia100.o i60uscsi.o
$(LD) -r -o a100u2w.o inia100.o i60uscsi.o
-megaraid.o: megaraid.c
- $(CC) $(CFLAGS) -c megaraid.c
-
scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o \
scsi_queue.o scsi_lib.o scsi_merge.o scsi_dma.o scsi_scan.o
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 9e2f14548..eb3c22cf0 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -4186,7 +4186,7 @@ STATIC void asc_prt_hex(char *f, uchar *, int);
#endif /* ADVANSYS_DEBUG */
#ifdef ADVANSYS_ASSERT
-STATIC int interrupts_enabled(void);
+STATIC int advansys_interrupts_enabled(void);
#endif /* ADVANSYS_ASSERT */
@@ -7053,7 +7053,7 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
Scsi_Device *device;
int ret;
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %lx, done %lx\n",
(ulong) scp, (ulong) scp->scsi_done);
@@ -7182,7 +7182,7 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
}
ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
return ret;
}
@@ -7602,7 +7602,7 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
struct Scsi_Host *shp;
int i;
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %lx, qdonep %lx\n",
(ulong) asc_dvc_varp, (ulong) qdonep);
ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
@@ -7773,7 +7773,7 @@ adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
struct Scsi_Host *shp;
int i;
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %lx, scsiqp %lx\n",
(ulong) adv_dvc_varp, (ulong) scsiqp);
ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
@@ -8422,7 +8422,7 @@ asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
ASC_DBG3(3, "asc_enqueue: ascq %lx, reqp %lx, flag %d\n",
(ulong) ascq, (ulong) reqp, flag);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
tid = REQPTID(reqp);
@@ -8475,7 +8475,7 @@ asc_dequeue(asc_queue_t *ascq, int tid)
REQP reqp;
ASC_DBG2(3, "asc_dequeue: ascq %lx, tid %d\n", (ulong) ascq, tid);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
if ((reqp = ascq->q_first[tid]) != NULL) {
ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
@@ -8524,7 +8524,7 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
int i;
ASC_DBG2(3, "asc_dequeue_list: ascq %lx, tid %d\n", (ulong) ascq, tid);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
/*
@@ -8607,7 +8607,7 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
ASC_DBG2(3, "asc_rmqueue: ascq %lx, reqp %lx\n",
(ulong) ascq, (ulong) reqp);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
tid = REQPTID(reqp);
@@ -8675,7 +8675,7 @@ asc_isqueued(asc_queue_t *ascq, REQP reqp)
ASC_DBG2(3, "asc_isqueued: ascq %lx, reqp %lx\n",
(ulong) ascq, (ulong) reqp);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
tid = REQPTID(reqp);
@@ -8705,7 +8705,7 @@ asc_execute_queue(asc_queue_t *ascq)
int i;
ASC_DBG1(1, "asc_execute_queue: ascq %lx\n", (ulong) ascq);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
/*
* Execute queued commands for devices attached to
* the current board in round-robin fashion.
@@ -10919,12 +10919,12 @@ asc_prt_hex(char *f, uchar *s, int l)
#ifdef ADVANSYS_ASSERT
/*
- * interrupts_enabled()
+ * advansys_interrupts_enabled()
*
* Return 1 if interrupts are enabled, otherwise return 0.
*/
STATIC int
-interrupts_enabled(void)
+advansys_interrupts_enabled(void)
{
int flags;
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index d87bf6d70..c1939a817 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1212,7 +1212,7 @@ static int option_setup(char *str) {
ints[0] = i - 1;
internal_setup(cur, ints);
- return 0;
+ return 1;
}
static void add_pci_ports(void) {
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
index 8bc0230fd..8e9c314ba 100644
--- a/drivers/scsi/qlogicisp.c
+++ b/drivers/scsi/qlogicisp.c
@@ -6,6 +6,9 @@
* Copyright 2000, Jayson C. Vantuyl <vantuyl@csc.smsu.edu>
* and Bryon W. Roche <bryon@csc.smsu.edu>
*
+ * 64-bit addressing added by Kanoj Sarcar <kanoj@sgi.com>
+ * and Leo Dagum <dagum@sgi.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, or (at your option) any
@@ -18,6 +21,7 @@
*/
#include <linux/blk.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
@@ -179,7 +183,7 @@ struct {
#define REQUEST_QUEUE_WAKEUP 0x8005
#define EXECUTION_TIMEOUT_RESET 0x8006
-#ifdef CONFIG_QL_ISP_A64
+#ifdef CONFIG_QL_ISP_A64
#define IOCB_SEGS 2
#define CONTINUATION_SEGS 5
#define MAX_CONTINUATION_ENTRIES 254
@@ -500,7 +504,7 @@ static const u_char mbox_param[] = {
PACKB(0, 0), /* 0x004b */
PACKB(0, 0), /* 0x004c */
PACKB(0, 0), /* 0x004d */
- PACKB(0, 0), /* 0x004e */
+ PACKB(0, 0), /* 0x004e */
PACKB(0, 0), /* 0x004f */
PACKB(0, 0), /* 0x0050 */
PACKB(0, 0), /* 0x0051 */
@@ -907,7 +911,7 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
dma_addr = sg_dma_address(sg);
ds[i].d_base = cpu_to_le32((u32) dma_addr);
#ifdef CONFIG_QL_ISP_A64
- ds[i].d_base_hi = cpu_to_le32((u32) (dma_addr>>32));
+ ds[i].d_base_hi = cpu_to_le32((u32)(dma_addr>>32));
#endif /* CONFIG_QL_ISP_A64 */
ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
++sg;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 21cb989ca..9fa8bc444 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1377,12 +1377,12 @@ int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
*/
void scsi_release_commandblocks(Scsi_Device * SDpnt)
{
- Scsi_Cmnd *SCpnt;
+ Scsi_Cmnd *SCpnt, *SCnext;
unsigned long flags;
- spin_lock_irqsave(&device_request_lock, flags);
- for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
- SDpnt->device_queue = SCpnt->next;
+ spin_lock_irqsave(&device_request_lock, flags);
+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {
+ SDpnt->device_queue = SCnext = SCpnt->next;
kfree((char *) SCpnt);
}
SDpnt->has_cmdblocks = 0;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8df062781..8ea85f0cd 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -5,14 +5,14 @@
History:
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Contribution and ideas from several people including (in alphabetical
- order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
- Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and
- Eric Youngdale.
+ order) Klaus Ehrenfried, Eric Lee Green, Wolfgang Denk, Steve Hirsch,
+ Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer,
+ J"org Weule, and Eric Youngdale.
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Mon Mar 13 21:15:29 2000 by makisara@kai.makisara.local
+ Last modified: Sun Mar 19 22:06:54 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -2621,8 +2621,7 @@ static int update_partition(Scsi_Tape *STp)
return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
}
-/* Functions for reading and writing the medium partition mode page. These
- seem to work with Wangtek 6200HS and HP C1533A. */
+/* Functions for reading and writing the medium partition mode page. */
#define PART_PAGE 0x11
#define PART_PAGE_FIXED_LENGTH 8
@@ -2675,6 +2674,11 @@ static int nbr_partitions(Scsi_Tape *STp)
The following algorithm is used to accomodate both drives: if the number of
partition size fields is greater than the maximum number of additional partitions
in the mode page, the second field is used. Otherwise the first field is used.
+
+ For Seagate DDS drives the page length must be 8 when no partitions is defined
+ and 10 when 1 partition is defined (information from Eric Lee Green). This is
+ is acceptable also to some other old drives and enforced if the first partition
+ size field is used for the first additional partition size.
*/
static int partition_tape(Scsi_Tape *STp, int size)
{
@@ -2707,12 +2711,16 @@ static int partition_tape(Scsi_Tape *STp, int size)
if (size <= 0) {
bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
+ if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
+ bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n",
dev));
} else {
bp[psdo] = (size >> 8) & 0xff;
bp[psdo + 1] = size & 0xff;
bp[pgo + 3] = 1;
+ if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
+ bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
DEBC(printk(ST_DEB_MSG
"st%d: Formatting tape with two partitions (1 = %d MB).\n",
dev, size));
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 379b55874..aa6706e8c 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -943,7 +943,7 @@ static int option_setup(char *str) {
ints[0] = i - 1;
internal_setup(cur, ints);
- return 0;
+ return 1;
}
int u14_34f_detect(Scsi_Host_Template *tpnt)
diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c
index 0a0e30775..ae866148b 100644
--- a/drivers/sound/ac97_codec.c
+++ b/drivers/sound/ac97_codec.c
@@ -25,7 +25,7 @@
* v0.3 Feb 22 2000 Ollie Lho
* bug fix for record mask setting
* v0.2 Feb 10 2000 Ollie Lho
- * add ac97_read_proc for /proc/driver/vnedor/ac97
+ * add ac97_read_proc for /proc/driver/{vendor}/ac97
* v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
* Isolated from trident.c to support multiple ac97 codec
*/
diff --git a/drivers/sound/awe_hw.h b/drivers/sound/awe_hw.h
index c7dde2679..7e403ad68 100644
--- a/drivers/sound/awe_hw.h
+++ b/drivers/sound/awe_hw.h
@@ -3,9 +3,9 @@
*
* Access routines and definitions for the low level driver for the
* Creative AWE32/SB32/AWE64 wave table synth.
- * version 0.4.3; Mar. 1, 1998
+ * version 0.4.4; Jan. 4, 2000
*
- * Copyright (C) 1996-1998 Takashi Iwai
+ * Copyright (C) 1996-2000 Takashi Iwai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/sound/awe_wave.c b/drivers/sound/awe_wave.c
index bedebb3b6..ac00add8f 100644
--- a/drivers/sound/awe_wave.c
+++ b/drivers/sound/awe_wave.c
@@ -2,9 +2,9 @@
* sound/awe_wave.c
*
* The low level driver for the AWE32/SB32/AWE64 wave table synth.
- * version 0.4.3; Feb. 1, 1999
+ * version 0.4.4; Jan. 4, 2000
*
- * Copyright (C) 1996-1999 Takashi Iwai
+ * Copyright (C) 1996-2000 Takashi Iwai
*
* 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
@@ -26,6 +26,9 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+#include <linux/isapnp.h>
+#endif
#include "sound_config.h"
#include "soundmodule.h"
@@ -42,9 +45,6 @@
* debug message
*/
-/* do not allocate buffer at beginning */
-#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
-
#ifdef AWE_DEBUG_ON
#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
@@ -59,56 +59,56 @@
* bank and voice record
*/
+typedef struct _sf_list sf_list;
+typedef struct _awe_voice_list awe_voice_list;
+typedef struct _awe_sample_list awe_sample_list;
+
/* soundfont record */
-typedef struct _sf_list {
- unsigned short sf_id;
- unsigned short type;
+struct _sf_list {
+ unsigned short sf_id; /* id number */
+ unsigned short type; /* lock & shared flags */
int num_info; /* current info table index */
int num_sample; /* current sample table index */
int mem_ptr; /* current word byte pointer */
- int infos;
- int samples;
+ awe_voice_list *infos, *last_infos; /* instruments */
+ awe_sample_list *samples, *last_samples; /* samples */
#ifdef AWE_ALLOW_SAMPLE_SHARING
- int shared; /* shared index */
- unsigned char name[AWE_PATCH_NAME_LEN];
+ sf_list *shared; /* shared list */
+ unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */
#endif
-} sf_list;
+ sf_list *next, *prev;
+};
-/* bank record */
-typedef struct _awe_voice_list {
- int next; /* linked list with same sf_id */
+/* instrument list */
+struct _awe_voice_list {
+ awe_voice_info v; /* instrument information */
+ sf_list *holder; /* parent sf_list of this record */
unsigned char bank, instr; /* preset number information */
char type, disabled; /* type=normal/mapped, disabled=boolean */
- awe_voice_info v; /* voice information */
- int next_instr; /* preset table list */
- int next_bank; /* preset table list */
-} awe_voice_list;
+ awe_voice_list *next; /* linked list with same sf_id */
+ awe_voice_list *next_instr; /* instrument list */
+ awe_voice_list *next_bank; /* hash table list */
+};
/* voice list type */
#define V_ST_NORMAL 0
#define V_ST_MAPPED 1
-typedef struct _awe_sample_list {
- int next; /* linked list with same sf_id */
+/* sample list */
+struct _awe_sample_list {
awe_sample_info v; /* sample information */
-} awe_sample_list;
+ sf_list *holder; /* parent sf_list of this record */
+ awe_sample_list *next; /* linked list with same sf_id */
+};
/* sample and information table */
-static int current_sf_id = 0;
-static int locked_sf_id = 0;
-static int max_sfs;
-static sf_list *sflists = NULL;
-
-#define awe_free_mem_ptr() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].mem_ptr)
-#define awe_free_info() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_info)
-#define awe_free_sample() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_sample)
-
-static int max_samples;
-static awe_sample_list *samples = NULL;
-
-static int max_infos;
-static awe_voice_list *infos = NULL;
+static int current_sf_id = 0; /* current number of fonts */
+static int locked_sf_id = 0; /* locked position */
+static sf_list *sfhead = NULL, *sftail = NULL; /* linked-lists */
+#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0)
+#define awe_free_info() (sftail ? sftail->num_info : 0)
+#define awe_free_sample() (sftail ? sftail->num_sample : 0)
#define AWE_MAX_PRESETS 256
#define AWE_DEFAULT_PRESET 0
@@ -119,7 +119,7 @@ static awe_voice_list *infos = NULL;
#define MAX_LAYERS AWE_MAX_VOICES
/* preset table index */
-static int preset_table[AWE_MAX_PRESETS];
+static awe_voice_list *preset_table[AWE_MAX_PRESETS];
/*
* voice table
@@ -143,8 +143,6 @@ typedef struct _awe_chan_info {
int main_vol; /* channel volume (0-127) */
int expression_vol; /* midi expression (0-127) */
int chan_press; /* channel pressure */
- int vrec; /* instrument list */
- int def_vrec; /* default instrument list */
int sustained; /* sustain status in MIDI */
FX_Rec fx; /* effects */
FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
@@ -194,9 +192,9 @@ static voice_info voices[AWE_MAX_VOICES];
static awe_chan_info channels[AWE_MAX_CHANNELS];
-/*----------------------------------------------------------------
+/*
* global variables
- *----------------------------------------------------------------*/
+ */
#ifndef AWE_DEFAULT_BASE_ADDR
#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */
@@ -206,10 +204,13 @@ static awe_chan_info channels[AWE_MAX_CHANNELS];
#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */
#endif
-#define awe_port io
-#define awe_mem_size memsize
int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static int isapnp = 1;
+#else
+static int isapnp = 0;
+#endif
MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
@@ -217,6 +218,8 @@ MODULE_PARM(io, "i");
MODULE_PARM_DESC(io, "base i/o port of Emu8000");
MODULE_PARM(memsize, "i");
MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
+MODULE_PARM(isapnp, "i");
+MODULE_PARM_DESC(isapnp, "use ISAPnP detection");
EXPORT_NO_SYMBOLS;
/* DRAM start offset */
@@ -255,7 +258,7 @@ static struct synth_info awe_info = {
0, /* perc_mode (obsolete) */
AWE_MAX_VOICES, /* nr_voices */
0, /* nr_drums (obsolete) */
- AWE_MAX_INFOS /* instr_bank_size */
+ 400 /* instr_bank_size */
};
@@ -362,8 +365,9 @@ static void awe_sustain_off(int voice, int forced);
static void awe_terminate_and_init(int voice, int forced);
/* voice search */
-static int awe_search_instr(int bank, int preset);
-static int awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist);
+static int awe_search_key(int bank, int preset, int note);
+static awe_voice_list *awe_search_instr(int bank, int preset, int note);
+static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist);
static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
static void awe_alloc_one_voice(int voice, int note, int velocity);
static int awe_clear_voice(void);
@@ -373,6 +377,7 @@ static int awe_open_patch(awe_patch_info *patch, const char *addr, int count);
static int awe_close_patch(awe_patch_info *patch, const char *addr, int count);
static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count);
static int awe_load_info(awe_patch_info *patch, const char *addr, int count);
+static int awe_remove_info(awe_patch_info *patch, const char *addr, int count);
static int awe_load_data(awe_patch_info *patch, const char *addr, int count);
static int awe_replace_data(awe_patch_info *patch, const char *addr, int count);
static int awe_load_map(awe_patch_info *patch, const char *addr, int count);
@@ -381,22 +386,24 @@ static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag
#endif
/*static int awe_probe_info(awe_patch_info *patch, const char *addr, int count);*/
static int awe_probe_data(awe_patch_info *patch, const char *addr, int count);
-static int check_patch_opened(int type, char *name);
-static int awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels);
-static void add_sf_info(int rec);
-static void add_sf_sample(int rec);
-static void purge_old_list(int rec, int next);
-static void add_info_list(int rec);
+static sf_list *check_patch_opened(int type, char *name);
+static int awe_write_wave_data(const char *addr, int offset, awe_sample_list *sp, int channels);
+static int awe_create_sf(int type, char *name);
+static void awe_free_sf(sf_list *sf);
+static void add_sf_info(sf_list *sf, awe_voice_list *rec);
+static void add_sf_sample(sf_list *sf, awe_sample_list *smp);
+static void purge_old_list(awe_voice_list *rec, awe_voice_list *next);
+static void add_info_list(awe_voice_list *rec);
static void awe_remove_samples(int sf_id);
static void rebuild_preset_list(void);
-static short awe_set_sample(awe_voice_info *vp);
-static int search_sample_index(int sf, int sample, int level);
+static short awe_set_sample(awe_voice_list *rec);
+static awe_sample_list *search_sample_index(sf_list *sf, int sample);
+static int is_identical_holder(sf_list *sf1, sf_list *sf2);
#ifdef AWE_ALLOW_SAMPLE_SHARING
-static int is_identical_id(int id1, int id2);
-static int is_identical_name(unsigned char *name, int id);
+static int is_identical_name(unsigned char *name, sf_list *p);
static int is_shared_sf(unsigned char *name);
-static int info_duplicated(awe_voice_list *rec);
+static int info_duplicated(sf_list *sf, awe_voice_list *rec);
#endif /* allow sharing */
/* lowlevel functions */
@@ -410,7 +417,7 @@ static void awe_init_fm(void);
static int awe_open_dram_for_write(int offset, int channels);
static void awe_open_dram_for_check(void);
static void awe_close_dram(void);
-static void awe_write_dram(unsigned short c);
+/*static void awe_write_dram(unsigned short c);*/
static int awe_detect_base(int addr);
static int awe_detect(void);
static void awe_check_dram(void);
@@ -483,9 +490,9 @@ static struct CtrlParmsDef {
static int ctrls[AWE_MD_END];
-/*----------------------------------------------------------------
+/*
* synth operation table
- *----------------------------------------------------------------*/
+ */
static struct synth_operations awe_operations =
{
@@ -513,39 +520,32 @@ static struct synth_operations awe_operations =
};
-/*================================================================
+/*
* General attach / unload interface
- *================================================================*/
+ */
-static int _attach_awe(void)
+static int __init _attach_awe(void)
{
if (awe_present) return 0; /* for OSS38.. called twice? */
/* check presence of AWE32 card */
if (! awe_detect()) {
- printk(KERN_WARNING "AWE32: not detected\n");
+ printk(KERN_ERR "AWE32: not detected\n");
return 0;
}
/* check AWE32 ports are available */
if (awe_check_port()) {
- printk(KERN_WARNING "AWE32: I/O area already used.\n");
+ printk(KERN_ERR "AWE32: I/O area already used.\n");
return 0;
}
/* set buffers to NULL */
- sflists = NULL;
- samples = NULL;
- infos = NULL;
-
- /* allocate sample tables */
- INIT_TABLE(sflists, max_sfs, AWE_MAX_SF_LISTS, sf_list);
- INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list);
- INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list);
+ sfhead = sftail = NULL;
my_dev = sound_alloc_synthdev();
if (my_dev == -1) {
- printk(KERN_WARNING "AWE32 Error: too many synthesizers\n");
+ printk(KERN_ERR "AWE32 Error: too many synthesizers\n");
return 0;
}
@@ -570,8 +570,8 @@ static int _attach_awe(void)
awe_initialize();
sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
- AWEDRV_VERSION, awe_mem_size/1024);
- printk("<SoundBlaster EMU8000 (RAM%dk)>\n", awe_mem_size/1024);
+ AWEDRV_VERSION, memsize/1024);
+ printk(KERN_INFO "<SoundBlaster EMU8000 (RAM%dk)>\n", memsize/1024);
awe_present = TRUE;
@@ -583,33 +583,18 @@ static int _attach_awe(void)
static void free_tables(void)
{
- if(sflists)
- vfree(sflists);
- sflists = NULL; max_sfs = 0;
- if (samples)
- vfree(samples);
- samples = NULL; max_samples = 0;
- if (infos)
- vfree(infos);
- infos = NULL; max_infos = 0;
-}
-
-static void *realloc_block(void *buf, int oldsize, int size)
-{
- void *ptr;
- if (oldsize == size)
- return buf;
- if ((ptr = vmalloc(size)) == NULL)
- return NULL;
- if (oldsize && size)
- memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) );
- if (buf)
- vfree(buf);
- return ptr;
+ if (sftail) {
+ sf_list *p, *prev;
+ for (p = sftail; p; p = prev) {
+ prev = p->prev;
+ awe_free_sf(p);
+ }
+ }
+ sfhead = sftail = NULL;
}
-static void _unload_awe(void)
+static void __exit _unload_awe(void)
{
if (awe_present) {
awe_reset_samples();
@@ -627,96 +612,6 @@ static void _unload_awe(void)
}
}
-/*
- * Linux PnP driver support
- */
-
-#ifdef CONFIG_PNP_DRV
-
-#include <linux/pnp.h>
-
-static int pnp = 1; /* use PnP as default */
-
-#define AWE_NUM_CHIPS 3
-static unsigned int pnp_ids[AWE_NUM_CHIPS] = {
- PNP_EISAID('C','T','L',0x0021),
- PNP_EISAID('C','T','L',0x0022),
- PNP_EISAID('C','T','L',0x0023),
-};
-static struct pnp_driver pnp_awe[AWE_NUM_CHIPS];
-static int awe_pnp_ok = 0;
-
-static void awe_pnp_config(struct pnp_device *d)
-{
- struct pnp_resource *r;
- int port[3];
- int nio = 0;
-
- port[0] = port[1] = port[2] = 0;
- for (r = d->res; r != NULL; r = r->next) {
- if (r->type == PNP_RES_IO) {
- if (nio >= 0 && nio < 3)
- port[nio] = r->start;
- nio++;
- }
- }
- setup_ports(port[0], port[1], port[2]);
- DEBUG(0,printk("AWE32: PnP setup ports: %x:%x:%x\n", port[0], port[1], port[2]));
-}
-
-static int awe_pnp_event (struct pnp_device *d, struct pnp_drv_event *e)
-{
- struct pnp_driver *drv = d->l.k.driver;
-
- switch (e->type) {
- case PNP_DRV_ALLOC:
- drv->flags |= PNP_DRV_INUSE;
- awe_pnp_ok = 1;
- awe_pnp_config(d);
- _attach_awe();
- break;
-
- case PNP_DRV_DISABLE:
- case PNP_DRV_EMERGSTOP:
- drv->flags &= ~PNP_DRV_INUSE;
- awe_pnp_ok = 0;
- _unload_awe();
- break;
-
- case PNP_DRV_CONFIG:
- if (awe_busy) return 1; /* used now */
- awe_release_region();
- awe_pnp_config(d);
- awe_request_region();
- break;
-
- case PNP_DRV_RECONFIG:
- break;
- }
- return 0;
-}
-
-static int awe_initpnp (void)
-{
- int i;
- for (i = 0; i < AWE_NUM_CHIPS; i++) {
- pnp_awe[i].id.type = PNP_HDL_ISA;
- pnp_awe[i].id.t.isa.id = pnp_ids[i];
- pnp_awe[i].id.next = NULL;
- pnp_awe[i].name = "Soundblaster AWE32/AWE64 PnP";
- pnp_awe[i].event = awe_pnp_event;
- pnp_register_driver(&pnp_awe[i], 1);
- }
- return 0;
-}
-
-static void awe_unload_pnp (void)
-{
- int i;
- for (i = 0; i < AWE_NUM_CHIPS; i++)
- pnp_unregister_driver(&pnp_awe[i]);
-}
-#endif /* PnP support */
/*
* clear sample tables
@@ -725,12 +620,8 @@ static void awe_unload_pnp (void)
static void
awe_reset_samples(void)
{
- int i;
-
/* free all bank tables */
- for (i = 0; i < AWE_MAX_PRESETS; i++)
- preset_table[i] = -1;
-
+ memset(preset_table, 0, sizeof(preset_table));
free_tables();
current_sf_id = 0;
@@ -767,7 +658,7 @@ static void setup_ports(int port1, int port2, int port3)
}
/* write 16bit data */
-static inline void
+static void
awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
{
awe_set_cmd(cmd);
@@ -775,7 +666,7 @@ awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
}
/* write 32bit data */
-static inline void
+static void
awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
{
unsigned short addr = awe_ports[port];
@@ -785,7 +676,7 @@ awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
}
/* read 16bit data */
-static inline unsigned short
+static unsigned short
awe_peek(unsigned short cmd, unsigned short port)
{
unsigned short k;
@@ -795,7 +686,7 @@ awe_peek(unsigned short cmd, unsigned short port)
}
/* read 32bit data */
-static inline unsigned int
+static unsigned int
awe_peek_dw(unsigned short cmd, unsigned short port)
{
unsigned int k1, k2;
@@ -837,14 +728,16 @@ static void awe_wait(unsigned short delay)
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
}
+/*
+static void awe_wait(unsigned short delay)
+{
+ udelay(((unsigned long)delay * 1000000L + 44099) / 44100);
+}
+*/
#endif /* wait by loop */
/* write a word data */
-static inline void
-awe_write_dram(unsigned short c)
-{
- awe_poke(AWE_SMLD, c);
-}
+#define awe_write_dram(c) awe_poke(AWE_SMLD, c)
/*
@@ -852,7 +745,7 @@ awe_write_dram(unsigned short c)
* 0x620-623, 0xA20-A23, 0xE20-E23
*/
-static int
+static int __init
awe_check_port(void)
{
if (! port_setuped) return 0;
@@ -861,7 +754,7 @@ awe_check_port(void)
check_region(awe_ports[3], 4));
}
-static void
+static void __init
awe_request_region(void)
{
if (! port_setuped) return;
@@ -870,7 +763,7 @@ awe_request_region(void)
request_region(awe_ports[3], 4, "sound driver (AWE32)");
}
-static void
+static void __exit
awe_release_region(void)
{
if (! port_setuped) return;
@@ -879,9 +772,11 @@ awe_release_region(void)
release_region(awe_ports[3], 4);
}
+
/*
- * AWE32 initialization
+ * initialization of AWE driver
*/
+
static void
awe_initialize(void)
{
@@ -935,7 +830,6 @@ awe_initialize(void)
static void
awe_init_voice_info(awe_voice_info *vp)
{
- vp->sf_id = 0; /* normal mode */
vp->sample = 0;
vp->rate_offset = 0;
@@ -1338,7 +1232,7 @@ awe_note_on(int voice)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
/* A voice sample must assigned before calling */
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
parm = (awe_voice_parm_block*)&vp->parm;
@@ -1457,15 +1351,15 @@ awe_note_on(int voice)
awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
- /* turn on envelope */
- awe_poke(AWE_DCYSUSV(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
- vp->parm.voldcysus));
/* set reverb */
temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
awe_poke_dw(AWE_PTRX(voice), temp);
awe_poke_dw(AWE_CPF(voice), ptarget << 16);
+ /* turn on envelope */
+ awe_poke(AWE_DCYSUSV(voice),
+ FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
+ vp->parm.voldcysus));
voices[voice].state = AWE_ST_ON;
@@ -1568,7 +1462,7 @@ awe_set_volume(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (!IS_PLAYING(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
@@ -1603,7 +1497,7 @@ awe_set_pan(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
/* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
@@ -1622,14 +1516,16 @@ awe_set_pan(int voice, int forced)
}
if (forced || temp != voices[voice].apan) {
voices[voice].apan = temp;
+ if (temp == 0)
+ voices[voice].aaux = 0xff;
+ else
+ voices[voice].aaux = (-temp) & 0xff;
addr = vp->loopstart - 1;
addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
AWE_FX_COARSE_LOOP_START, vp->mode);
temp = (temp<<24) | (unsigned int)addr;
awe_poke_dw(AWE_PSST(voice), temp);
DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
- if (temp == 0) voices[voice].aaux = 0xff;
- else voices[voice].aaux = (-temp)&0xff;
}
}
@@ -1644,7 +1540,7 @@ awe_fx_fmmod(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
awe_poke(AWE_FMMOD(voice),
FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
@@ -1662,7 +1558,7 @@ awe_fx_tremfrq(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
awe_poke(AWE_TREMFRQ(voice),
FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
@@ -1680,7 +1576,7 @@ awe_fx_fm2frq2(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
awe_poke(AWE_FM2FRQ2(voice),
FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
@@ -1700,7 +1596,7 @@ awe_fx_filterQ(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
@@ -1708,12 +1604,12 @@ awe_fx_filterQ(int voice, int forced)
awe_poke_dw(AWE_CCCA(voice), addr);
}
-/*================================================================
+/*
* calculate pitch offset
- *----------------------------------------------------------------
+ *
* 0xE000 is no pitch offset at 44100Hz sample.
* Every 4096 is one octave.
- *================================================================*/
+ */
static void
awe_calc_pitch(int voice)
@@ -1726,9 +1622,9 @@ awe_calc_pitch(int voice)
/* search voice information */
if ((ap = vp->sample) == NULL)
return;
- if (ap->index < 0) {
+ if (ap->index == 0) {
DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample(ap) < 0)
+ if (awe_set_sample((awe_voice_list*)ap) == 0)
return;
}
@@ -1785,9 +1681,9 @@ awe_calc_pitch_from_freq(int voice, int freq)
/* search voice information */
if ((ap = vp->sample) == NULL)
return;
- if (ap->index < 0) {
+ if (ap->index == 0) {
DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample(ap) < 0)
+ if (awe_set_sample((awe_voice_list*)ap) == 0)
return;
}
note = freq_to_note(freq);
@@ -1806,13 +1702,13 @@ awe_calc_pitch_from_freq(int voice, int freq)
#endif /* AWE_HAS_GUS_COMPATIBILITY */
-/*================================================================
+/*
* calculate volume attenuation
- *----------------------------------------------------------------
+ *
* Voice volume is controlled by volume attenuation parameter.
* So volume becomes maximum when avol is 0 (no attenuation), and
* minimum when 255 (-96dB or silence).
- *================================================================*/
+ */
static int vol_table[128] = {
255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
@@ -1887,9 +1783,9 @@ awe_calc_volume(int voice)
return;
ap = vp->sample;
- if (ap->index < 0) {
+ if (ap->index == 0) {
DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample(ap) < 0)
+ if (awe_set_sample((awe_voice_list*)ap) == 0)
return;
}
@@ -2054,8 +1950,6 @@ static void awe_channel_init(int ch, int init_all)
cp->instr = ctrls[AWE_MD_DEF_PRESET];
cp->bank = ctrls[AWE_MD_DEF_BANK];
}
- cp->vrec = -1;
- cp->def_vrec = -1;
}
cp->bender = 0; /* zero tune skew */
@@ -2092,9 +1986,9 @@ static void awe_voice_change(int voice, fx_affect_func func)
}
-/*----------------------------------------------------------------
+/*
* device open / close
- *----------------------------------------------------------------*/
+ */
/* open device:
* reset status of all voices, and clear sample position flag
@@ -2158,13 +2052,13 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
awe_info.nr_voices = awe_max_voices;
else
awe_info.nr_voices = AWE_MAX_CHANNELS;
- memcpy((char*)arg, &awe_info + 0, sizeof(awe_info));
+ memcpy((char*)arg, &awe_info, sizeof(awe_info));
return 0;
break;
case SNDCTL_SEQ_RESETSAMPLES:
- awe_reset_samples();
awe_reset(dev);
+ awe_reset_samples();
return 0;
break;
@@ -2174,10 +2068,10 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
break;
case SNDCTL_SYNTH_MEMAVL:
- return awe_mem_size - awe_free_mem_ptr() * 2;
+ return memsize - awe_free_mem_ptr() * 2;
default:
- printk("AWE32: unsupported ioctl %d\n", cmd);
+ printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd);
return -EINVAL;
}
}
@@ -2358,18 +2252,46 @@ awe_start_note(int dev, int voice, int note, int velocity)
}
-/* search instrument from preset table with the specified bank */
+/* calculate hash key */
static int
-awe_search_instr(int bank, int preset)
+awe_search_key(int bank, int preset, int note)
{
- int i;
+ unsigned int key;
- limitvalue(preset, 0, AWE_MAX_PRESETS-1);
- for (i = preset_table[preset]; i >= 0; i = infos[i].next_bank) {
- if (infos[i].bank == bank)
- return i;
+#if 1 /* new hash table */
+ if (bank == AWE_DRUM_BANK)
+ key = preset + note + 128;
+ else
+ key = bank + preset;
+#else
+ key = preset;
+#endif
+ key %= AWE_MAX_PRESETS;
+
+ return (int)key;
+}
+
+
+/* search instrument from hash table */
+static awe_voice_list *
+awe_search_instr(int bank, int preset, int note)
+{
+ awe_voice_list *p;
+ int key, key2;
+
+ key = awe_search_key(bank, preset, note);
+ for (p = preset_table[key]; p; p = p->next_bank) {
+ if (p->instr == preset && p->bank == bank)
+ return p;
}
- return -1;
+ key2 = awe_search_key(bank, preset, 0); /* search default */
+ if (key == key2)
+ return NULL;
+ for (p = preset_table[key2]; p; p = p->next_bank) {
+ if (p->instr == preset && p->bank == bank)
+ return p;
+ }
+ return NULL;
}
@@ -2390,7 +2312,6 @@ static int
awe_set_instr(int dev, int voice, int instr_no)
{
awe_chan_info *cinfo;
- int def_bank;
if (! voice_in_range(voice))
return -EINVAL;
@@ -2399,26 +2320,8 @@ awe_set_instr(int dev, int voice, int instr_no)
return -EINVAL;
cinfo = &channels[voice];
-
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
- def_bank = AWE_DRUM_BANK; /* always search drumset */
- else
- def_bank = cinfo->bank;
-
- cinfo->vrec = -1;
- cinfo->def_vrec = -1;
- cinfo->vrec = awe_search_instr(def_bank, instr_no);
- if (def_bank == AWE_DRUM_BANK) /* search default drumset */
- cinfo->def_vrec = awe_search_instr(def_bank, ctrls[AWE_MD_DEF_DRUM]);
- else /* search default preset */
- cinfo->def_vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr_no);
-
- if (cinfo->vrec < 0 && cinfo->def_vrec < 0) {
- DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no));
- }
-
cinfo->instr = instr_no;
- DEBUG(2,printk("AWE32: [program(%d) %d/%d]\n", voice, instr_no, def_bank));
+ DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no));
return 0;
}
@@ -2576,7 +2479,7 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event)
switch (cmd) {
case _AWE_DEBUG_MODE:
ctrls[AWE_MD_DEBUG_MODE] = p1;
- printk("AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
+ printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
break;
case _AWE_REVERB_MODE:
ctrls[AWE_MD_REVERB_MODE] = p1;
@@ -2590,6 +2493,7 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event)
case _AWE_REMOVE_LAST_SAMPLES:
DEBUG(0,printk("AWE32: remove last samples\n"));
+ awe_reset(0);
if (locked_sf_id > 0)
awe_remove_samples(locked_sf_id);
break;
@@ -2772,6 +2676,8 @@ awe_controller(int dev, int voice, int ctrl_num, int value)
if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
!ctrls[AWE_MD_TOGGLE_DRUM_BANK])
break;
+ if (value < 0 || value > 255)
+ break;
cinfo->bank = value;
if (cinfo->bank == AWE_DRUM_BANK)
DRUM_CHANNEL_ON(cinfo->channel);
@@ -2920,10 +2826,10 @@ awe_bender(int dev, int voice, int value)
}
-/*----------------------------------------------------------------
+/*
* load a sound patch:
* three types of patches are accepted: AWE, GUS, and SYSEX.
- *----------------------------------------------------------------*/
+ */
static int
awe_load_patch(int dev, int format, const char *addr,
@@ -2941,20 +2847,21 @@ awe_load_patch(int dev, int format, const char *addr,
/* no system exclusive message supported yet */
return 0;
} else if (format != AWE_PATCH) {
- printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format);
+ printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format);
return -EINVAL;
}
if (count < AWE_PATCH_INFO_SIZE) {
- printk("AWE32 Error: Patch header too short\n");
+ printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
return -EINVAL;
}
- copy_from_user(((char*)&patch) + offs, addr + offs,
- AWE_PATCH_INFO_SIZE - offs);
+ if (copy_from_user(((char*)&patch) + offs, addr + offs,
+ AWE_PATCH_INFO_SIZE - offs))
+ return -EFAULT;
count -= AWE_PATCH_INFO_SIZE;
if (count < patch.len) {
- printk("AWE32: sample: Patch record too short (%d<%d)\n",
+ printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n",
count, patch.len);
return -EINVAL;
}
@@ -2987,6 +2894,9 @@ awe_load_patch(int dev, int format, const char *addr,
case AWE_PROBE_DATA:
rc = awe_probe_data(&patch, addr, count);
break;
+ case AWE_REMOVE_INFO:
+ rc = awe_remove_info(&patch, addr, count);
+ break;
case AWE_LOAD_CHORUS_FX:
rc = awe_load_chorus_fx(&patch, addr, count);
break;
@@ -2995,7 +2905,7 @@ awe_load_patch(int dev, int format, const char *addr,
break;
default:
- printk("AWE32 Error: unknown patch format type %d\n",
+ printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n",
patch.type);
rc = -EINVAL;
}
@@ -3004,7 +2914,7 @@ awe_load_patch(int dev, int format, const char *addr,
}
-/* create an sflist record */
+/* create an sf list record */
static int
awe_create_sf(int type, char *name)
{
@@ -3012,40 +2922,43 @@ awe_create_sf(int type, char *name)
/* terminate sounds */
awe_reset(0);
- if (current_sf_id >= max_sfs) {
- int newsize = max_sfs + AWE_MAX_SF_LISTS;
- sf_list *newlist = realloc_block(sflists, sizeof(sf_list)*max_sfs,
- sizeof(sf_list)*newsize);
- if (newlist == NULL)
- return 1;
- sflists = newlist;
- max_sfs = newsize;
- }
- rec = &sflists[current_sf_id];
+ rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL);
+ if (rec == NULL)
+ return 1; /* no memory */
rec->sf_id = current_sf_id + 1;
rec->type = type;
- if (current_sf_id == 0 || (type & AWE_PAT_LOCKED) != 0)
+ if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0)
locked_sf_id = current_sf_id + 1;
rec->num_info = awe_free_info();
rec->num_sample = awe_free_sample();
rec->mem_ptr = awe_free_mem_ptr();
- rec->infos = -1;
- rec->samples = -1;
+ rec->infos = rec->last_infos = NULL;
+ rec->samples = rec->last_samples = NULL;
+
+ /* add to linked-list */
+ rec->next = NULL;
+ rec->prev = sftail;
+ if (sftail)
+ sftail->next = rec;
+ else
+ sfhead = rec;
+ sftail = rec;
+ current_sf_id++;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- rec->shared = 0;
+ rec->shared = NULL;
if (name)
memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
else
strcpy(rec->name, "*TEMPORARY*");
- if (current_sf_id > 0 && name && (type & AWE_PAT_SHARED) != 0) {
+ if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) {
/* is the current font really a shared font? */
if (is_shared_sf(rec->name)) {
/* check if the shared font is already installed */
- int i;
- for (i = current_sf_id; i > 0; i--) {
- if (is_identical_name(rec->name, i)) {
- rec->shared = i;
+ sf_list *p;
+ for (p = rec->prev; p; p = p->prev) {
+ if (is_identical_name(rec->name, p)) {
+ rec->shared = p;
break;
}
}
@@ -3053,8 +2966,6 @@ awe_create_sf(int type, char *name)
}
#endif /* allow sharing */
- current_sf_id++;
-
return 0;
}
@@ -3065,37 +2976,31 @@ awe_create_sf(int type, char *name)
#define ASC_TO_KEY(c) ((c) - 'A' + 1)
static int is_shared_sf(unsigned char *name)
{
- static unsigned char id_head[6] = {
+ static unsigned char id_head[4] = {
ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
AWE_MAJOR_VERSION,
- AWE_MINOR_VERSION,
- AWE_TINY_VERSION,
};
- if (memcmp(name, id_head, 6) == 0)
+ if (memcmp(name, id_head, 4) == 0)
return TRUE;
return FALSE;
}
/* check if the given name matches to the existing list */
-static int is_identical_name(unsigned char *name, int sf)
+static int is_identical_name(unsigned char *name, sf_list *p)
{
- char *id = sflists[sf-1].name;
+ char *id = p->name;
if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
return TRUE;
return FALSE;
}
/* check if the given voice info exists */
-static int info_duplicated(awe_voice_list *rec)
+static int info_duplicated(sf_list *sf, awe_voice_list *rec)
{
- int j, sf_id;
- sf_list *sf;
-
/* search for all sharing lists */
- for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) {
- sf = &sflists[sf_id - 1];
- for (j = sf->infos; j >= 0; j = infos[j].next) {
- awe_voice_list *p = &infos[j];
+ for (; sf; sf = sf->shared) {
+ awe_voice_list *p;
+ for (p = sf->infos; p; p = p->next) {
if (p->type == V_ST_NORMAL &&
p->bank == rec->bank &&
p->instr == rec->instr &&
@@ -3111,6 +3016,29 @@ static int info_duplicated(awe_voice_list *rec)
#endif /* AWE_ALLOW_SAMPLE_SHARING */
+/* free sf_list record */
+/* linked-list in this function is not cared */
+static void
+awe_free_sf(sf_list *sf)
+{
+ if (sf->infos) {
+ awe_voice_list *p, *next;
+ for (p = sf->infos; p; p = next) {
+ next = p->next;
+ kfree(p);
+ }
+ }
+ if (sf->samples) {
+ awe_sample_list *p, *next;
+ for (p = sf->samples; p; p = next) {
+ next = p->next;
+ kfree(p);
+ }
+ }
+ kfree(sf);
+}
+
+
/* open patch; create sf list and set opened flag */
static int
awe_open_patch(awe_patch_info *patch, const char *addr, int count)
@@ -3118,13 +3046,14 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
awe_open_parm parm;
int shared;
- copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm));
+ if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm)))
+ return -EFAULT;
shared = FALSE;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (current_sf_id > 0 && (parm.type & AWE_PAT_SHARED) != 0) {
+ if (sftail && (parm.type & AWE_PAT_SHARED) != 0) {
/* is the previous font the same font? */
- if (is_identical_name(parm.name, current_sf_id)) {
+ if (is_identical_name(parm.name, sftail)) {
/* then append to the previous */
shared = TRUE;
awe_reset(0);
@@ -3135,8 +3064,8 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
#endif /* allow sharing */
if (! shared) {
if (awe_create_sf(parm.type, parm.name)) {
- printk("AWE32: can't open: failed to alloc new list\n");
- return -ENOSPC;
+ printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n");
+ return -ENOMEM;
}
}
patch_opened = TRUE;
@@ -3144,28 +3073,30 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
}
/* check if the patch is already opened */
-static int
+static sf_list *
check_patch_opened(int type, char *name)
{
if (! patch_opened) {
if (awe_create_sf(type, name)) {
- printk("AWE32: failed to alloc new list\n");
- return -ENOSPC;
+ printk(KERN_ERR "AWE32: failed to alloc new list\n");
+ return NULL;
}
patch_opened = TRUE;
- return current_sf_id;
+ return sftail;
}
- return current_sf_id;
+ return sftail;
}
/* close the patch; if no voice is loaded, remove the patch */
static int
awe_close_patch(awe_patch_info *patch, const char *addr, int count)
{
- if (patch_opened && current_sf_id > 0) {
+ if (patch_opened && sftail) {
/* if no voice is loaded, release the current patch */
- if (sflists[current_sf_id-1].infos == -1)
+ if (sftail->infos == NULL) {
+ awe_reset(0);
awe_remove_samples(current_sf_id - 1);
+ }
}
patch_opened = 0;
return 0;
@@ -3176,52 +3107,39 @@ awe_close_patch(awe_patch_info *patch, const char *addr, int count)
static int
awe_unload_patch(awe_patch_info *patch, const char *addr, int count)
{
- if (current_sf_id > 0 && current_sf_id > locked_sf_id)
+ if (current_sf_id > 0 && current_sf_id > locked_sf_id) {
+ awe_reset(0);
awe_remove_samples(current_sf_id - 1);
+ }
return 0;
}
/* allocate voice info list records */
-static int alloc_new_info(int nvoices)
+static awe_voice_list *
+alloc_new_info(void)
{
- int newsize, free_info;
awe_voice_list *newlist;
- free_info = awe_free_info();
- if (free_info + nvoices >= max_infos) {
- do {
- newsize = max_infos + AWE_MAX_INFOS;
- } while (free_info + nvoices >= newsize);
- newlist = realloc_block(infos, sizeof(awe_voice_list)*max_infos,
- sizeof(awe_voice_list)*newsize);
- if (newlist == NULL) {
- printk("AWE32: can't alloc info table\n");
- return -ENOSPC;
- }
- infos = newlist;
- max_infos = newsize;
+
+ newlist = (awe_voice_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
+ if (newlist == NULL) {
+ printk(KERN_ERR "AWE32: can't alloc info table\n");
+ return NULL;
}
- return 0;
+ return newlist;
}
/* allocate sample info list records */
-static int alloc_new_sample(void)
+static awe_sample_list *
+alloc_new_sample(void)
{
- int newsize, free_sample;
awe_sample_list *newlist;
- free_sample = awe_free_sample();
- if (free_sample >= max_samples) {
- newsize = max_samples + AWE_MAX_SAMPLES;
- newlist = realloc_block(samples,
- sizeof(awe_sample_list)*max_samples,
- sizeof(awe_sample_list)*newsize);
- if (newlist == NULL) {
- printk("AWE32: can't alloc sample table\n");
- return -ENOSPC;
- }
- samples = newlist;
- max_samples = newsize;
+
+ newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
+ if (newlist == NULL) {
+ printk(KERN_ERR "AWE32: can't alloc sample table\n");
+ return NULL;
}
- return 0;
+ return newlist;
}
/* load voice map */
@@ -3229,35 +3147,33 @@ static int
awe_load_map(awe_patch_info *patch, const char *addr, int count)
{
awe_voice_map map;
- awe_voice_list *rec;
- int p, free_info;
+ awe_voice_list *rec, *p;
+ sf_list *sf;
/* get the link info */
if (count < sizeof(map)) {
- printk("AWE32 Error: invalid patch info length\n");
+ printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
return -EINVAL;
}
- copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
+ if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
+ return -EFAULT;
/* check if the identical mapping already exists */
- p = awe_search_instr(map.map_bank, map.map_instr);
- for (; p >= 0; p = infos[p].next_instr) {
- if (p >= 0 && infos[p].type == V_ST_MAPPED &&
- infos[p].v.low == map.map_key &&
- infos[p].v.start == map.src_instr &&
- infos[p].v.end == map.src_bank &&
- infos[p].v.fixkey == map.src_key)
+ p = awe_search_instr(map.map_bank, map.map_instr, map.map_key);
+ for (; p; p = p->next_instr) {
+ if (p->type == V_ST_MAPPED &&
+ p->v.start == map.src_instr &&
+ p->v.end == map.src_bank &&
+ p->v.fixkey == map.src_key)
return 0; /* already present! */
}
- if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0)
- return -ENOSPC;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL)
+ return -ENOMEM;
- if (alloc_new_info(1) < 0)
- return -ENOSPC;
+ if ((rec = alloc_new_info()) == NULL)
+ return -ENOMEM;
- free_info = awe_free_info();
- rec = &infos[free_info];
rec->bank = map.map_bank;
rec->instr = map.map_instr;
rec->type = V_ST_MAPPED;
@@ -3270,9 +3186,8 @@ awe_load_map(awe_patch_info *patch, const char *addr, int count)
rec->v.start = map.src_instr;
rec->v.end = map.src_bank;
rec->v.fixkey = map.src_key;
- rec->v.sf_id = current_sf_id;
- add_info_list(free_info);
- add_sf_info(free_info);
+ add_sf_info(sf, rec);
+ add_info_list(rec);
return 0;
}
@@ -3284,25 +3199,28 @@ awe_probe_info(awe_patch_info *patch, const char *addr, int count)
{
#ifdef AWE_ALLOW_SAMPLE_SHARING
awe_voice_map map;
- int p;
+ awe_voice_list *p;
if (! patch_opened)
return -EINVAL;
/* get the link info */
if (count < sizeof(map)) {
- printk("AWE32 Error: invalid patch info length\n");
+ printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
return -EINVAL;
}
- copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
+ if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
+ return -EFAULT;
/* check if the identical mapping already exists */
- p = awe_search_instr(map.src_bank, map.src_instr);
- for (; p >= 0; p = infos[p].next_instr) {
- if (p >= 0 && infos[p].type == V_ST_NORMAL &&
- is_identical_id(infos[p].v.sf_id, current_sf_id) &&
- infos[p].v.low <= map.src_key &&
- infos[p].v.high >= map.src_key)
+ if (sftail == NULL)
+ return -EINVAL;
+ p = awe_search_instr(map.src_bank, map.src_instr, map.src_key);
+ for (; p; p = p->next_instr) {
+ if (p->type == V_ST_NORMAL &&
+ is_identical_holder(p->holder, sftail) &&
+ p->v.low <= map.src_key &&
+ p->v.high >= map.src_key)
return 0; /* already present! */
}
#endif /* allow sharing */
@@ -3319,12 +3237,40 @@ awe_probe_data(awe_patch_info *patch, const char *addr, int count)
return -EINVAL;
/* search the specified sample by optarg */
- if (search_sample_index(current_sf_id, patch->optarg, 0) >= 0)
+ if (search_sample_index(sftail, patch->optarg) != NULL)
return 0;
#endif /* allow sharing */
return -EINVAL;
}
+
+/* remove the present instrument layers */
+static int
+remove_info(sf_list *sf, int bank, int instr)
+{
+ awe_voice_list *prev, *next, *p;
+ int removed = 0;
+
+ prev = NULL;
+ for (p = sf->infos; p; prev = p, p = next) {
+ next = p->next;
+ if (p->type == V_ST_NORMAL &&
+ p->bank == bank && p->instr == instr) {
+ /* remove this layer */
+ if (prev)
+ prev->next = next;
+ else
+ sf->infos = next;
+ if (p == sf->last_infos)
+ sf->last_infos = prev;
+ sf->num_info--;
+ removed++;
+ kfree(p);
+ }
+ }
+ return removed;
+}
+
/* load voice information data */
static int
awe_load_info(awe_patch_info *patch, const char *addr, int count)
@@ -3333,125 +3279,154 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count)
awe_voice_rec_hdr hdr;
int i;
int total_size;
+ sf_list *sf;
+ awe_voice_list *rec;
if (count < AWE_VOICE_REC_SIZE) {
- printk("AWE32 Error: invalid patch info length\n");
+ printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
return -EINVAL;
}
offset = AWE_PATCH_INFO_SIZE;
- copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE);
+ if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE))
+ return -EFAULT;
offset += AWE_VOICE_REC_SIZE;
if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
- printk("AWE32 Error: Illegal voice number %d\n", hdr.nvoices);
+ printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices);
return -EINVAL;
}
total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
if (count < total_size) {
- printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
+ printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
count, hdr.nvoices);
return -EINVAL;
}
- if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
- return -ENOSPC;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
+ return -ENOMEM;
-#if 0 /* it looks like not so useful.. */
- /* check if the same preset already exists in the info list */
- for (i = sflists[current_sf_id-1].infos; i >= 0; i = infos[i].next) {
- if (infos[i].disabled) continue;
- if (infos[i].bank == hdr.bank && infos[i].instr == hdr.instr) {
- /* in exclusive mode, do skip loading this */
- if (hdr.write_mode == AWE_WR_EXCLUSIVE)
- return 0;
- /* in replace mode, disable the old data */
- else if (hdr.write_mode == AWE_WR_REPLACE)
- infos[i].disabled = TRUE;
+ switch (hdr.write_mode) {
+ case AWE_WR_EXCLUSIVE:
+ /* exclusive mode - if the instrument already exists,
+ return error */
+ for (rec = sf->infos; rec; rec = rec->next) {
+ if (rec->type == V_ST_NORMAL &&
+ rec->bank == hdr.bank &&
+ rec->instr == hdr.instr)
+ return -EINVAL;
}
+ break;
+ case AWE_WR_REPLACE:
+ /* replace mode - remoe the instrument if it already exists */
+ remove_info(sf, hdr.bank, hdr.instr);
+ break;
}
- if (hdr.write_mode == AWE_WR_REPLACE)
- rebuild_preset_list();
-#endif
-
- if (alloc_new_info(hdr.nvoices) < 0)
- return -ENOSPC;
+ /* append new layers */
for (i = 0; i < hdr.nvoices; i++) {
- int rec = awe_free_info();
+ rec = alloc_new_info();
+ if (rec == NULL)
+ return -ENOMEM;
- infos[rec].bank = hdr.bank;
- infos[rec].instr = hdr.instr;
- infos[rec].type = V_ST_NORMAL;
- infos[rec].disabled = FALSE;
+ rec->bank = hdr.bank;
+ rec->instr = hdr.instr;
+ rec->type = V_ST_NORMAL;
+ rec->disabled = FALSE;
/* copy awe_voice_info parameters */
- copy_from_user(&infos[rec].v, addr + offset, AWE_VOICE_INFO_SIZE);
+ if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) {
+ kfree(rec);
+ return -EFAULT;
+ }
offset += AWE_VOICE_INFO_SIZE;
- infos[rec].v.sf_id = current_sf_id;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (sflists[current_sf_id-1].shared) {
- if (info_duplicated(&infos[rec]))
+ if (sf && sf->shared) {
+ if (info_duplicated(sf, rec)) {
+ kfree(rec);
continue;
+ }
}
#endif /* allow sharing */
- if (infos[rec].v.mode & AWE_MODE_INIT_PARM)
- awe_init_voice_parm(&infos[rec].v.parm);
- awe_set_sample(&infos[rec].v);
+ if (rec->v.mode & AWE_MODE_INIT_PARM)
+ awe_init_voice_parm(&rec->v.parm);
+ add_sf_info(sf, rec);
+ awe_set_sample(rec);
add_info_list(rec);
- add_sf_info(rec);
}
return 0;
}
+/* remove instrument layers */
+static int
+awe_remove_info(awe_patch_info *patch, const char *addr, int count)
+{
+ unsigned char bank, instr;
+ sf_list *sf;
+
+ if (! patch_opened || (sf = sftail) == NULL) {
+ printk(KERN_WARNING "AWE32: remove_info: patch not opened\n");
+ return -EINVAL;
+ }
+
+ bank = ((unsigned short)patch->optarg >> 8) & 0xff;
+ instr = (unsigned short)patch->optarg & 0xff;
+ if (! remove_info(sf, bank, instr))
+ return -EINVAL;
+ return 0;
+}
+
+
/* load wave sample data */
static int
awe_load_data(awe_patch_info *patch, const char *addr, int count)
{
int offset, size;
- int rc, free_sample;
- awe_sample_info tmprec, *rec;
+ int rc;
+ awe_sample_info tmprec;
+ awe_sample_list *rec;
+ sf_list *sf;
- if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
- return -ENOSPC;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
+ return -ENOMEM;
size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
offset = AWE_PATCH_INFO_SIZE;
- copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE);
+ if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE))
+ return -EFAULT;
offset += AWE_SAMPLE_INFO_SIZE;
if (size != tmprec.size) {
- printk("AWE32: load: sample size differed (%d != %d)\n",
+ printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n",
tmprec.size, size);
return -EINVAL;
}
- if (search_sample_index(current_sf_id, tmprec.sample, 0) >= 0) {
+ if (search_sample_index(sf, tmprec.sample) != NULL) {
#ifdef AWE_ALLOW_SAMPLE_SHARING
/* if shared sample, skip this data */
- if (sflists[current_sf_id-1].type & AWE_PAT_SHARED)
+ if (sf->type & AWE_PAT_SHARED)
return 0;
#endif /* allow sharing */
DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
return -EINVAL;
}
- if (alloc_new_sample() < 0)
- return -ENOSPC;
+ if ((rec = alloc_new_sample()) == NULL)
+ return -ENOMEM;
- free_sample = awe_free_sample();
- rec = &samples[free_sample].v;
- *rec = tmprec;
+ memcpy(&rec->v, &tmprec, sizeof(tmprec));
- if (rec->size > 0)
- if ((rc = awe_write_wave_data(addr, offset, rec, -1)) != 0)
+ if (rec->v.size > 0) {
+ if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) {
+ kfree(rec);
return rc;
+ }
+ sf->mem_ptr += rc;
+ }
- rec->sf_id = current_sf_id;
-
- add_sf_sample(free_sample);
-
+ add_sf_sample(sf, rec);
return 0;
}
@@ -3462,55 +3437,57 @@ awe_replace_data(awe_patch_info *patch, const char *addr, int count)
{
int offset;
int size;
- int rc, i;
+ int rc;
int channels;
awe_sample_info cursmp;
int save_mem_ptr;
+ sf_list *sf;
+ awe_sample_list *rec;
- if (! patch_opened) {
- printk("AWE32: replace: patch not opened\n");
+ if (! patch_opened || (sf = sftail) == NULL) {
+ printk(KERN_WARNING "AWE32: replace: patch not opened\n");
return -EINVAL;
}
size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
offset = AWE_PATCH_INFO_SIZE;
- copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE);
+ if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE))
+ return -EFAULT;
offset += AWE_SAMPLE_INFO_SIZE;
if (cursmp.size == 0 || size != cursmp.size) {
- printk("AWE32: replace: illegal sample size (%d!=%d)\n",
+ printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n",
cursmp.size, size);
return -EINVAL;
}
channels = patch->optarg;
if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
- printk("AWE32: replace: illegal channels %d\n", channels);
+ printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels);
return -EINVAL;
}
- for (i = sflists[current_sf_id-1].samples;
- i >= 0; i = samples[i].next) {
- if (samples[i].v.sample == cursmp.sample)
+ for (rec = sf->samples; rec; rec = rec->next) {
+ if (rec->v.sample == cursmp.sample)
break;
}
- if (i < 0) {
- printk("AWE32: replace: cannot find existing sample data %d\n",
+ if (rec == NULL) {
+ printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n",
cursmp.sample);
return -EINVAL;
}
- if (samples[i].v.size != cursmp.size) {
- printk("AWE32: replace: exiting size differed (%d!=%d)\n",
- samples[i].v.size, cursmp.size);
+ if (rec->v.size != cursmp.size) {
+ printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n",
+ rec->v.size, cursmp.size);
return -EINVAL;
}
save_mem_ptr = awe_free_mem_ptr();
- sflists[current_sf_id-1].mem_ptr = samples[i].v.start - awe_mem_start;
- memcpy(&samples[i].v, &cursmp, sizeof(cursmp));
- if ((rc = awe_write_wave_data(addr, offset, &samples[i].v, channels)) != 0)
+ sftail->mem_ptr = rec->v.start - awe_mem_start;
+ memcpy(&rec->v, &cursmp, sizeof(cursmp));
+ rec->v.sf_id = current_sf_id;
+ if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0)
return rc;
- sflists[current_sf_id-1].mem_ptr = save_mem_ptr;
- samples[i].v.sf_id = current_sf_id;
+ sftail->mem_ptr = save_mem_ptr;
return 0;
}
@@ -3521,28 +3498,11 @@ awe_replace_data(awe_patch_info *patch, const char *addr, int count)
static const char *readbuf_addr;
static int readbuf_offs;
static int readbuf_flags;
-#ifdef MALLOC_LOOP_DATA
-static unsigned short *readbuf_loop;
-static int readbuf_loopstart, readbuf_loopend;
-#endif
/* initialize read buffer */
static int
readbuf_init(const char *addr, int offset, awe_sample_info *sp)
{
-#ifdef MALLOC_LOOP_DATA
- readbuf_loop = NULL;
- readbuf_loopstart = sp->loopstart;
- readbuf_loopend = sp->loopend;
- if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
- int looplen = sp->loopend - sp->loopstart;
- readbuf_loop = vmalloc(looplen * 2);
- if (readbuf_loop == NULL) {
- printk("AWE32: can't malloc temp buffer\n");
- return -ENOSPC;
- }
- }
-#endif
readbuf_addr = addr;
readbuf_offs = offset;
readbuf_flags = sp->mode_flags;
@@ -3557,59 +3517,31 @@ readbuf_word(int pos)
/* read from user buffer */
if (readbuf_flags & AWE_SAMPLE_8BITS) {
unsigned char cc;
- get_user(cc, (unsigned char*)&(readbuf_addr)[readbuf_offs + pos]);
- c = cc << 8; /* convert 8bit -> 16bit */
+ get_user(cc, (unsigned char*)(readbuf_addr + readbuf_offs + pos));
+ c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */
} else {
- get_user(c, (unsigned short*)&(readbuf_addr)[readbuf_offs + pos * 2]);
+ get_user(c, (unsigned short*)(readbuf_addr + readbuf_offs + pos * 2));
}
if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
c ^= 0x8000; /* unsigned -> signed */
-#ifdef MALLOC_LOOP_DATA
- /* write on cache for reverse loop */
- if (readbuf_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
- if (pos >= readbuf_loopstart && pos < readbuf_loopend)
- readbuf_loop[pos - readbuf_loopstart] = c;
- }
-#endif
return c;
}
-#ifdef MALLOC_LOOP_DATA
-/* read from cache */
-static unsigned short
-readbuf_word_cache(int pos)
-{
- if (pos >= readbuf_loopstart && pos < readbuf_loopend)
- return readbuf_loop[pos - readbuf_loopstart];
- return 0;
-}
-
-static void
-readbuf_end(void)
-{
- if (readbuf_loop)
- vfree(readbuf_loop);
- readbuf_loop = NULL;
-}
-
-#else
-
#define readbuf_word_cache readbuf_word
#define readbuf_end() /**/
-#endif
-
/*----------------------------------------------------------------*/
#define BLANK_LOOP_START 8
#define BLANK_LOOP_END 40
#define BLANK_LOOP_SIZE 48
-/* loading onto memory */
+/* loading onto memory - return the actual written size */
static int
-awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels)
+awe_write_wave_data(const char *addr, int offset, awe_sample_list *list, int channels)
{
int i, truesize, dram_offset;
+ awe_sample_info *sp = &list->v;
int rc;
/* be sure loop points start < end */
@@ -3621,11 +3553,11 @@ awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int chann
/* compute true data size to be loaded */
truesize = sp->size;
- if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP)
+ if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))
truesize += sp->loopend - sp->loopstart;
if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
truesize += BLANK_LOOP_SIZE;
- if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) {
+ if (awe_free_mem_ptr() + truesize >= memsize/2) {
DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
return -ENOSPC;
}
@@ -3686,13 +3618,12 @@ awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int chann
}
}
- sflists[current_sf_id-1].mem_ptr += truesize;
awe_close_dram();
/* initialize FM */
awe_init_fm();
- return 0;
+ return truesize;
}
@@ -3728,33 +3659,36 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
struct patch_info patch;
awe_voice_info *rec;
awe_sample_info *smp;
+ awe_voice_list *vrec;
+ awe_sample_list *smprec;
int sizeof_patch;
- int note, free_sample, free_info;
- int rc;
+ int note, rc;
+ sf_list *sf;
sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
if (size < sizeof_patch) {
- printk("AWE32 Error: Patch header too short\n");
+ printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
return -EINVAL;
}
- copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs);
+ if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs))
+ return -EFAULT;
size -= sizeof_patch;
if (size < patch.len) {
- printk("AWE32 Warning: Patch record too short (%d<%d)\n",
+ printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n",
size, patch.len);
return -EINVAL;
}
- if (check_patch_opened(AWE_PAT_TYPE_GUS, NULL) < 0)
- return -ENOSPC;
- if (alloc_new_sample() < 0)
- return -ENOSPC;
- if (alloc_new_info(1))
- return -ENOSPC;
-
- free_sample = awe_free_sample();
- smp = &samples[free_sample].v;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL)
+ return -ENOMEM;
+ if ((smprec = alloc_new_sample()) == NULL)
+ return -ENOMEM;
+ if ((vrec = alloc_new_info()) == NULL) {
+ kfree(smprec);
+ return -ENOMEM;
+ }
- smp->sample = free_sample;
+ smp = &smprec->v;
+ smp->sample = sf->num_sample;
smp->start = 0;
smp->end = patch.len;
smp->loopstart = patch.loop_start;
@@ -3786,17 +3720,15 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
smp->checksum_flag = 0;
smp->checksum = 0;
- if ((rc = awe_write_wave_data(addr, sizeof_patch, smp, -1)) != 0)
+ if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0)
return rc;
-
- smp->sf_id = current_sf_id;
- add_sf_sample(free_sample);
+ sf->mem_ptr += rc;
+ add_sf_sample(sf, smprec);
/* set up voice info */
- free_info = awe_free_info();
- rec = &infos[free_info].v;
+ rec = &vrec->v;
awe_init_voice_info(rec);
- rec->sample = free_sample; /* the last sample */
+ rec->sample = sf->num_info; /* the last sample */
rec->rate_offset = calc_rate_offset(patch.base_freq);
note = freq_to_note(patch.base_note);
rec->root = note / 100;
@@ -3831,8 +3763,8 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
release += calc_gus_envelope_time
(patch.env_rate[5], patch.env_offset[4],
patch.env_offset[5]);
- rec->parm.volatkhld = (calc_parm_attack(attack) << 8) |
- calc_parm_hold(hold);
+ rec->parm.volatkhld = (calc_parm_hold(hold) << 8) |
+ calc_parm_attack(attack);
rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
calc_parm_decay(decay);
rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
@@ -3860,17 +3792,16 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
/* scale_freq, scale_factor, volume, and fractions not implemented */
/* append to the tail of the list */
- infos[free_info].bank = ctrls[AWE_MD_GUS_BANK];
- infos[free_info].instr = patch.instr_no;
- infos[free_info].disabled = FALSE;
- infos[free_info].type = V_ST_NORMAL;
- infos[free_info].v.sf_id = current_sf_id;
+ vrec->bank = ctrls[AWE_MD_GUS_BANK];
+ vrec->instr = patch.instr_no;
+ vrec->disabled = FALSE;
+ vrec->type = V_ST_NORMAL;
- add_info_list(free_info);
- add_sf_info(free_info);
+ add_sf_info(sf, vrec);
+ add_info_list(vrec);
/* set the voice index */
- awe_set_sample(rec);
+ awe_set_sample(vrec);
return 0;
}
@@ -3881,96 +3812,100 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
* sample and voice list handlers
*/
-/* append this to the sf list */
-static void add_sf_info(int rec)
+/* append this to the current sf list */
+static void add_sf_info(sf_list *sf, awe_voice_list *rec)
{
- int sf_id = infos[rec].v.sf_id;
- if (sf_id <= 0) return;
- sf_id--;
- if (sflists[sf_id].infos < 0)
- sflists[sf_id].infos = rec;
- else {
- int i, prev;
- prev = sflists[sf_id].infos;
- while ((i = infos[prev].next) >= 0)
- prev = i;
- infos[prev].next = rec;
- }
- infos[rec].next = -1;
- sflists[sf_id].num_info++;
+ if (sf == NULL)
+ return;
+ rec->holder = sf;
+ rec->v.sf_id = sf->sf_id;
+ if (sf->last_infos)
+ sf->last_infos->next = rec;
+ else
+ sf->infos = rec;
+ sf->last_infos = rec;
+ rec->next = NULL;
+ sf->num_info++;
}
/* prepend this sample to sf list */
-static void add_sf_sample(int rec)
+static void add_sf_sample(sf_list *sf, awe_sample_list *rec)
{
- int sf_id = samples[rec].v.sf_id;
- if (sf_id <= 0) return;
- sf_id--;
- samples[rec].next = sflists[sf_id].samples;
- sflists[sf_id].samples = rec;
- sflists[sf_id].num_sample++;
+ if (sf == NULL)
+ return;
+ rec->holder = sf;
+ rec->v.sf_id = sf->sf_id;
+ if (sf->last_samples)
+ sf->last_samples->next = rec;
+ else
+ sf->samples = rec;
+ sf->last_samples = rec;
+ rec->next = NULL;
+ sf->num_sample++;
}
/* purge the old records which don't belong with the same file id */
-static void purge_old_list(int rec, int next)
+static void purge_old_list(awe_voice_list *rec, awe_voice_list *next)
{
- infos[rec].next_instr = next;
- if (infos[rec].bank == AWE_DRUM_BANK) {
+ rec->next_instr = next;
+ if (rec->bank == AWE_DRUM_BANK) {
/* remove samples with the same note range */
- int cur, *prevp = &infos[rec].next_instr;
- int low = infos[rec].v.low;
- int high = infos[rec].v.high;
- for (cur = next; cur >= 0; cur = infos[cur].next_instr) {
- if (infos[cur].v.low == low &&
- infos[cur].v.high == high &&
- ! is_identical_id(infos[cur].v.sf_id, infos[rec].v.sf_id))
- *prevp = infos[cur].next_instr;
- prevp = &infos[cur].next_instr;
+ awe_voice_list *cur, *prev = rec;
+ int low = rec->v.low;
+ int high = rec->v.high;
+ for (cur = next; cur; cur = cur->next_instr) {
+ if (cur->v.low == low &&
+ cur->v.high == high &&
+ ! is_identical_holder(cur->holder, rec->holder))
+ prev->next_instr = cur->next_instr;
+ else
+ prev = cur;
}
} else {
- if (! is_identical_id(infos[next].v.sf_id, infos[rec].v.sf_id))
- infos[rec].next_instr = -1;
+ if (! is_identical_holder(next->holder, rec->holder))
+ /* remove all samples */
+ rec->next_instr = NULL;
}
}
/* prepend to top of the preset table */
-static void add_info_list(int rec)
+static void add_info_list(awe_voice_list *rec)
{
- int *prevp, cur;
- int instr;
- int bank;
+ awe_voice_list *prev, *cur;
+ int key;
- if (infos[rec].disabled)
+ if (rec->disabled)
return;
- instr = infos[rec].instr;
- bank = infos[rec].bank;
- limitvalue(instr, 0, AWE_MAX_PRESETS-1);
- prevp = &preset_table[instr];
- cur = *prevp;
- while (cur >= 0) {
+ key = awe_search_key(rec->bank, rec->instr, rec->v.low);
+ prev = NULL;
+ for (cur = preset_table[key]; cur; cur = cur->next_bank) {
/* search the first record with the same bank number */
- if (infos[cur].bank == bank) {
+ if (cur->instr == rec->instr && cur->bank == rec->bank) {
/* replace the list with the new record */
- infos[rec].next_bank = infos[cur].next_bank;
- *prevp = rec;
+ rec->next_bank = cur->next_bank;
+ if (prev)
+ prev->next_bank = rec;
+ else
+ preset_table[key] = rec;
purge_old_list(rec, cur);
return;
}
- prevp = &infos[cur].next_bank;
- cur = infos[cur].next_bank;
+ prev = cur;
}
/* this is the first bank record.. just add this */
- infos[rec].next_instr = -1;
- infos[rec].next_bank = preset_table[instr];
- preset_table[instr] = rec;
+ rec->next_instr = NULL;
+ rec->next_bank = preset_table[key];
+ preset_table[key] = rec;
}
/* remove samples later than the specified sf_id */
static void
awe_remove_samples(int sf_id)
{
+ sf_list *p, *prev;
+
if (sf_id <= 0) {
awe_reset_samples();
return;
@@ -3979,6 +3914,20 @@ awe_remove_samples(int sf_id)
if (current_sf_id <= sf_id)
return;
+ for (p = sftail; p; p = prev) {
+ if (p->sf_id <= sf_id)
+ break;
+ prev = p->prev;
+ awe_free_sf(p);
+ }
+ sftail = p;
+ if (sftail) {
+ sf_id = sftail->sf_id;
+ sftail->next = NULL;
+ } else {
+ sf_id = 0;
+ sfhead = NULL;
+ }
current_sf_id = sf_id;
if (locked_sf_id > sf_id)
locked_sf_id = sf_id;
@@ -3989,33 +3938,36 @@ awe_remove_samples(int sf_id)
/* rebuild preset search list */
static void rebuild_preset_list(void)
{
- int i, j;
+ sf_list *p;
+ awe_voice_list *rec;
- for (i = 0; i < AWE_MAX_PRESETS; i++)
- preset_table[i] = -1;
+ memset(preset_table, 0, sizeof(preset_table));
- for (i = 0; i < current_sf_id; i++) {
- for (j = sflists[i].infos; j >= 0; j = infos[j].next)
- add_info_list(j);
+ for (p = sfhead; p; p = p->next) {
+ for (rec = p->infos; rec; rec = rec->next)
+ add_info_list(rec);
}
}
/* compare the given sf_id pair */
-static int is_identical_id(int id1, int id2)
+static int is_identical_holder(sf_list *sf1, sf_list *sf2)
{
- if (id1 == id2)
- return TRUE;
- if (id1 <= 0 || id2 <= 0) /* this must not happen.. */
+ if (sf1 == NULL || sf2 == NULL)
return FALSE;
+ if (sf1 == sf2)
+ return TRUE;
#ifdef AWE_ALLOW_SAMPLE_SHARING
{
/* compare with the sharing id */
- int i;
- if (id1 < id2) { /* make sure id1 > id2 */
- int tmp; tmp = id1; id1 = id2; id2 = tmp;
+ sf_list *p;
+ int counter = 0;
+ if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */
+ sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp;
}
- for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) {
- if (i == id2)
+ for (p = sf1->shared; p; p = p->shared) {
+ if (counter++ > current_sf_id)
+ break; /* strange sharing loop.. quit */
+ if (p == sf2)
return TRUE;
}
}
@@ -4024,73 +3976,81 @@ static int is_identical_id(int id1, int id2)
}
/* search the sample index matching with the given sample id */
-static int search_sample_index(int sf, int sample, int level)
+static awe_sample_list *
+search_sample_index(sf_list *sf, int sample)
{
- int i;
-
- if (sf <= 0 || sf > current_sf_id)
- return -1; /* this must not happen */
-
- for (i = sflists[sf-1].samples; i >= 0; i = samples[i].next) {
- if (samples[i].v.sample == sample)
- return i;
- }
+ awe_sample_list *p;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */
- if (level > current_sf_id)
- return -1; /* strange sharing loop.. quit */
- return search_sample_index(i, sample, level + 1);
+ int counter = 0;
+ while (sf) {
+ for (p = sf->samples; p; p = p->next) {
+ if (p->v.sample == sample)
+ return p;
+ }
+ sf = sf->shared;
+ if (counter++ > current_sf_id)
+ break; /* strange sharing loop.. quit */
+ }
+#else
+ if (sf) {
+ for (p = sf->samples; p; p = p->next) {
+ if (p->v.sample == sample)
+ return p;
+ }
}
#endif
- return -1;
+ return NULL;
}
/* search the specified sample */
+/* non-zero = found */
static short
-awe_set_sample(awe_voice_info *vp)
+awe_set_sample(awe_voice_list *rec)
{
- int i;
+ awe_sample_list *smp;
+ awe_voice_info *vp = &rec->v;
- vp->index = -1;
- if ((i = search_sample_index(vp->sf_id, vp->sample, 0)) < 0)
- return -1;
+ vp->index = 0;
+ if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL)
+ return 0;
/* set the actual sample offsets */
- vp->start += samples[i].v.start;
- vp->end += samples[i].v.end;
- vp->loopstart += samples[i].v.loopstart;
- vp->loopend += samples[i].v.loopend;
+ vp->start += smp->v.start;
+ vp->end += smp->v.end;
+ vp->loopstart += smp->v.loopstart;
+ vp->loopend += smp->v.loopend;
/* copy mode flags */
- vp->mode = samples[i].v.mode_flags;
- /* set index */
- vp->index = i;
+ vp->mode = smp->v.mode_flags;
+ /* set flag */
+ vp->index = 1;
- return i;
+ return 1;
}
-/*----------------------------------------------------------------
+/*
* voice allocation
- *----------------------------------------------------------------*/
+ */
/* look for all voices associated with the specified note & velocity */
static int
-awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist)
+awe_search_multi_voices(awe_voice_list *rec, int note, int velocity,
+ awe_voice_info **vlist)
{
int nvoices;
nvoices = 0;
- for (; rec >= 0; rec = infos[rec].next_instr) {
- if (note >= infos[rec].v.low &&
- note <= infos[rec].v.high &&
- velocity >= infos[rec].v.vellow &&
- velocity <= infos[rec].v.velhigh) {
- if (infos[rec].type == V_ST_MAPPED) {
+ for (; rec; rec = rec->next_instr) {
+ if (note >= rec->v.low &&
+ note <= rec->v.high &&
+ velocity >= rec->v.vellow &&
+ velocity <= rec->v.velhigh) {
+ if (rec->type == V_ST_MAPPED) {
/* mapper */
- vlist[0] = &infos[rec].v;
+ vlist[0] = &rec->v;
return -1;
}
- vlist[nvoices++] = &infos[rec].v;
+ vlist[nvoices++] = &rec->v;
if (nvoices >= AWE_MAX_VOICES)
break;
}
@@ -4103,29 +4063,45 @@ awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist)
the note number if necessary.
*/
static int
-really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_info **vlist, int level)
+really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist)
{
int nvoices;
-
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- if (nvoices == 0)
- nvoices = awe_search_multi_voices(def_vrec, *note, velocity, vlist);
- if (nvoices < 0) { /* mapping */
- int preset = vlist[0]->start;
- int bank = vlist[0]->end;
- int key = vlist[0]->fixkey;
- if (level > 5) {
- printk("AWE32: too deep mapping level\n");
- return 0;
+ awe_voice_list *vrec;
+ int level = 0;
+
+ for (;;) {
+ vrec = awe_search_instr(bank, instr, *note);
+ nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+ if (nvoices == 0) {
+ if (bank == AWE_DRUM_BANK)
+ /* search default drumset */
+ vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note);
+ else
+ /* search default preset */
+ vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note);
+ nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
}
- vrec = awe_search_instr(bank, preset);
- if (bank == AWE_DRUM_BANK)
- def_vrec = awe_search_instr(bank, 0);
- else
- def_vrec = awe_search_instr(0, preset);
- if (key >= 0)
- *note = key;
- return really_alloc_voices(vrec, def_vrec, note, velocity, vlist, level+1);
+ if (nvoices == 0) {
+ if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0)
+ /* search default drumset */
+ vrec = awe_search_instr(bank, 0, *note);
+ else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0)
+ /* search default preset */
+ vrec = awe_search_instr(0, instr, *note);
+ nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+ }
+ if (nvoices < 0) { /* mapping */
+ int key = vlist[0]->fixkey;
+ instr = vlist[0]->start;
+ bank = vlist[0]->end;
+ if (level++ > 5) {
+ printk(KERN_ERR "AWE32: too deep mapping level\n");
+ return 0;
+ }
+ if (key >= 0)
+ *note = key;
+ } else
+ break;
}
return nvoices;
@@ -4135,15 +4111,17 @@ really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_i
static void
awe_alloc_multi_voices(int ch, int note, int velocity, int key)
{
- int i, v, nvoices;
+ int i, v, nvoices, bank;
awe_voice_info *vlist[AWE_MAX_VOICES];
- if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
- awe_set_instr(0, ch, channels[ch].instr);
+ if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch))
+ bank = AWE_DRUM_BANK; /* always search drumset */
+ else
+ bank = channels[ch].bank;
/* check the possible voices; note may be changeable if mapped */
- nvoices = really_alloc_voices(channels[ch].vrec, channels[ch].def_vrec,
- &note, velocity, vlist, 0);
+ nvoices = really_alloc_voices(bank, channels[ch].instr,
+ &note, velocity, vlist);
/* set the voices */
current_alloc_time++;
@@ -4169,78 +4147,62 @@ awe_alloc_multi_voices(int ch, int note, int velocity, int key)
}
-/* search the best voice from the specified status condition */
+/* search an empty voice.
+ if no empty voice is found, at least terminate a voice
+ */
static int
-search_best_voice(int condition)
+awe_clear_voice(void)
{
- int i, time, best;
- int vtarget = 0xffff, min_vtarget = 0xffff;
+ enum {
+ OFF=0, RELEASED, SUSTAINED, PLAYING, END
+ };
+ struct voice_candidate_t {
+ int best;
+ int time;
+ int vtarget;
+ } candidate[END];
+ int i, type, vtarget;
+
+ vtarget = 0xffff;
+ for (type = OFF; type < END; type++) {
+ candidate[type].best = -1;
+ candidate[type].time = current_alloc_time + 1;
+ candidate[type].vtarget = vtarget;
+ }
- best = -1;
- time = current_alloc_time + 1;
for (i = 0; i < awe_max_voices; i++) {
- if (! (voices[i].state & condition))
+ if (voices[i].state & AWE_ST_OFF)
+ type = OFF;
+ else if (voices[i].state & AWE_ST_RELEASED)
+ type = RELEASED;
+ else if (voices[i].state & AWE_ST_SUSTAINED)
+ type = SUSTAINED;
+ else if (voices[i].state & ~AWE_ST_MARK)
+ type = PLAYING;
+ else
continue;
#ifdef AWE_CHECK_VTARGET
/* get current volume */
vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
#endif
- if (best < 0 || vtarget < min_vtarget ||
- (vtarget == min_vtarget && voices[i].time < time)) {
- best = i;
- time = voices[i].time;
- min_vtarget = vtarget;
+ if (candidate[type].best < 0 ||
+ vtarget < candidate[type].vtarget ||
+ (vtarget == candidate[type].vtarget &&
+ voices[i].time < candidate[type].time)) {
+ candidate[type].best = i;
+ candidate[type].time = voices[i].time;
+ candidate[type].vtarget = vtarget;
}
}
- /* clear voice */
- if (best >= 0) {
- if (voices[best].state != AWE_ST_OFF)
- awe_terminate(best);
- awe_voice_init(best, TRUE);
- }
-
- return best;
-}
-/* search an empty voice.
- if no empty voice is found, at least terminate a voice
- */
-static int
-awe_clear_voice(void)
-{
- int best;
-
- /* looking for the oldest empty voice */
- if ((best = search_best_voice(AWE_ST_OFF)) >= 0)
- return best;
- if ((best = search_best_voice(AWE_ST_RELEASED)) >= 0)
- return best;
- /* looking for the oldest sustained voice */
- if ((best = search_best_voice(AWE_ST_SUSTAINED)) >= 0)
- return best;
-
- if (MULTI_LAYER_MODE() && ctrls[AWE_MD_CHN_PRIOR]) {
- int ch = -1;
- int time = current_alloc_time + 1;
- int i;
- /* looking for the voices from high channel (except drum ch) */
- for (i = 0; i < awe_max_voices; i++) {
- if (IS_DRUM_CHANNEL(voices[i].ch)) continue;
- if (voices[i].ch < ch) continue;
- if (voices[i].state != AWE_ST_MARK &&
- (voices[i].ch > ch || voices[i].time < time)) {
- best = i;
- time = voices[i].time;
- ch = voices[i].ch;
- }
+ for (type = OFF; type < END; type++) {
+ if ((i = candidate[type].best) >= 0) {
+ if (voices[i].state != AWE_ST_OFF)
+ awe_terminate(i);
+ awe_voice_init(i, TRUE);
+ return i;
}
}
- if (best < 0)
- best = search_best_voice(~AWE_ST_MARK);
-
- if (best >= 0)
- return best;
-
return 0;
}
@@ -4251,16 +4213,17 @@ awe_clear_voice(void)
static void
awe_alloc_one_voice(int voice, int note, int velocity)
{
- int ch, nvoices;
+ int ch, nvoices, bank;
awe_voice_info *vlist[AWE_MAX_VOICES];
ch = voices[voice].ch;
- if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
- awe_set_instr(0, ch, channels[ch].instr);
+ if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
+ bank = AWE_DRUM_BANK; /* always search drumset */
+ else
+ bank = voices[voice].cinfo->bank;
- nvoices = really_alloc_voices(voices[voice].cinfo->vrec,
- voices[voice].cinfo->def_vrec,
- &note, velocity, vlist, 0);
+ nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr,
+ &note, velocity, vlist);
if (nvoices > 0) {
voices[voice].time = ++current_alloc_time;
voices[voice].sample = vlist[0]; /* use the first one */
@@ -4271,9 +4234,9 @@ awe_alloc_one_voice(int voice, int note, int velocity)
}
-/*----------------------------------------------------------------
+/*
* sequencer2 functions
- *----------------------------------------------------------------*/
+ */
/* search an empty voice; used by sequencer2 */
static int
@@ -4331,14 +4294,14 @@ static struct mixer_operations awe_mixer_operations = {
awe_mixer_ioctl,
};
-static void attach_mixer(void)
+static void __init attach_mixer(void)
{
if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
mixer_devs[my_mixerdev] = &awe_mixer_operations;
}
}
-static void unload_mixer(void)
+static void __exit unload_mixer(void)
{
if (my_mixerdev >= 0)
sound_unload_mixerdev(my_mixerdev);
@@ -4352,7 +4315,7 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
if (((cmd >> 8) & 0xff) != 'M')
return -EINVAL;
- level = (int) *(int *)arg;
+ level = *(int*)arg;
level = ((level & 0xff) + (level >> 8)) / 2;
DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
@@ -4408,13 +4371,13 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
level = 0;
break;
}
- return *(int *)arg = level;
+ return *(int*)arg = level;
}
#endif /* CONFIG_AWE32_MIXER */
/*
- * initialization of AWE32
+ * initialization of Emu8000
*/
/* intiailize audio channels */
@@ -4636,7 +4599,7 @@ awe_init_fm(void)
{
#ifndef AWE_ALWAYS_INIT_FM
/* if no extended memory is on board.. */
- if (awe_mem_size <= 0)
+ if (memsize <= 0)
return;
#endif
DEBUG(3,printk("AWE32: initializing FM\n"));
@@ -4731,7 +4694,8 @@ awe_open_dram_for_write(int offset, int channels)
awe_poke_dw(AWE_CCCA(vidx[i]), 0);
voices[vidx[i]].state = AWE_ST_OFF;
}
- return -ENOSPC;
+ printk("awe: not ready to write..\n");
+ return -EPERM;
}
/* set address to write */
@@ -4784,13 +4748,13 @@ awe_close_dram(void)
}
-/*================================================================
+/*
* detect presence of AWE32 and check memory size
- *================================================================*/
+ */
/* detect emu8000 chip on the specified address; from VV's guide */
-static int
+static int __init
awe_detect_base(int addr)
{
setup_ports(addr, 0, 0);
@@ -4804,16 +4768,79 @@ awe_detect_base(int addr)
return 1;
}
-static int
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static struct {
+ unsigned short vendor;
+ unsigned short function;
+ char *name;
+} isapnp_awe_list[] __initdata = {
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), "AWE32 WaveTable"},
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), "AWE64 WaveTable"},
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), "AWE64 Gold WaveTable"},
+ {0,}
+};
+
+static struct pci_dev *idev = NULL;
+
+static int __init awe_probe_isapnp(int *port)
+{
+ int i;
+
+ for (i = 0; isapnp_awe_list[i].vendor != 0; i++) {
+ while ((idev = isapnp_find_dev(NULL,
+ isapnp_awe_list[i].vendor,
+ isapnp_awe_list[i].function,
+ idev))) {
+ if (idev->prepare(idev) < 0)
+ continue;
+ if (idev->activate(idev) < 0 ||
+ !idev->resource[0].start) {
+ idev->deactivate(idev);
+ idev->deactivate(idev);
+ continue;
+ }
+ *port = idev->resource[0].start;
+ break;
+ }
+ if (!idev)
+ continue;
+ printk(KERN_INFO "ISAPnP reports %s at i/o %#x\n",
+ isapnp_awe_list[i].name, *port);
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static void __exit awe_deactivate_isapnp(void)
+{
+#if 1
+ if (idev) {
+ idev->deactivate(idev);
+ idev = NULL;
+ }
+#endif
+}
+
+#endif
+
+static int __init
awe_detect(void)
{
int base;
- if (port_setuped) /* already initialized by PnP */
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+ if (isapnp) {
+ if (awe_probe_isapnp(&io) < 0) {
+ printk(KERN_ERR "AWE32: No ISAPnP cards found\n");
+ return 0;
+ }
+ setup_ports(io, 0, 0);
return 1;
+ }
+#endif /* isapnp */
- if (awe_port) /* use default i/o port value */
- setup_ports(awe_port, 0, 0);
+ if (io) /* use default i/o port value */
+ setup_ports(io, 0, 0);
else { /* probe it */
for (base = 0x620; base <= 0x680; base += 0x20)
if (awe_detect_base(base))
@@ -4826,36 +4853,36 @@ awe_detect(void)
}
-/*================================================================
+/*
* check dram size on AWE board
- *================================================================*/
+ */
/* any three numbers you like */
#define UNIQUE_ID1 0x1234
#define UNIQUE_ID2 0x4321
#define UNIQUE_ID3 0xFFFF
-static void
+static void __init
awe_check_dram(void)
{
if (awe_present) /* already initialized */
return;
- if (awe_mem_size >= 0) { /* given by config file or module option */
- awe_mem_size *= 1024; /* convert to Kbytes */
+ if (memsize >= 0) { /* given by config file or module option */
+ memsize *= 1024; /* convert to Kbytes */
return;
}
awe_open_dram_for_check();
- awe_mem_size = 0;
+ memsize = 0;
/* set up unique two id numbers */
awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
awe_poke(AWE_SMLD, UNIQUE_ID1);
awe_poke(AWE_SMLD, UNIQUE_ID2);
- while (awe_mem_size < AWE_MAX_DRAM_SIZE) {
+ while (memsize < AWE_MAX_DRAM_SIZE) {
awe_wait(5);
/* read a data on the DRAM start address */
awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
@@ -4864,33 +4891,35 @@ awe_check_dram(void)
break;
if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
break;
- awe_mem_size += 512; /* increment 512kbytes */
+ memsize += 512; /* increment 512kbytes */
/* Write a unique data on the test address;
* if the address is out of range, the data is written on
* 0x200000(=AWE_DRAM_OFFSET). Then the two id words are
* broken by this data.
*/
- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + awe_mem_size*512L);
+ awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L);
awe_poke(AWE_SMLD, UNIQUE_ID3);
awe_wait(5);
/* read a data on the just written DRAM address */
- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + awe_mem_size*512L);
+ awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L);
awe_peek(AWE_SMLD); /* discard stale data */
if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
break;
}
awe_close_dram();
- DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", awe_mem_size));
+ DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize));
/* convert to Kbytes */
- awe_mem_size *= 1024;
+ memsize *= 1024;
}
-/*================================================================
+/*----------------------------------------------------------------*/
+
+/*
* chorus and reverb controls; from VV's guide
- *================================================================*/
+ */
/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
static char chorus_defined[AWE_CHORUS_NUMBERS];
@@ -4909,15 +4938,16 @@ static int
awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count)
{
if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
- printk("AWE32 Error: illegal chorus mode %d for uploading\n", patch->optarg);
+ printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg);
return -EINVAL;
}
if (count < sizeof(awe_chorus_fx_rec)) {
- printk("AWE32 Error: too short chorus fx parameters\n");
+ printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n");
return -EINVAL;
}
- copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_chorus_fx_rec));
+ if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+ sizeof(awe_chorus_fx_rec)))
+ return -EFAULT;
chorus_defined[patch->optarg] = TRUE;
return 0;
}
@@ -5016,15 +5046,16 @@ static int
awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count)
{
if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
- printk("AWE32 Error: illegal reverb mode %d for uploading\n", patch->optarg);
+ printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg);
return -EINVAL;
}
if (count < sizeof(awe_reverb_fx_rec)) {
- printk("AWE32 Error: too short reverb fx parameters\n");
+ printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n");
return -EINVAL;
}
- copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_reverb_fx_rec));
+ if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+ sizeof(awe_reverb_fx_rec)))
+ return -EFAULT;
reverb_defined[patch->optarg] = TRUE;
return 0;
}
@@ -5047,9 +5078,9 @@ awe_update_reverb_mode(void)
awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
}
-/*================================================================
+/*
* treble/bass equalizer control
- *================================================================*/
+ */
static unsigned short bass_parm[12][3] = {
{0xD26A, 0xD36A, 0x0000}, /* -12 dB */
@@ -5113,15 +5144,17 @@ static void awe_update_equalizer(void)
}
+/*----------------------------------------------------------------*/
+
#ifdef CONFIG_AWE32_MIDIEMU
-/*================================================================
+/*
* Emu8000 MIDI Emulation
- *================================================================*/
+ */
-/*================================================================
+/*
* midi queue record
- *================================================================*/
+ */
/* queue type */
enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
@@ -5149,9 +5182,9 @@ typedef struct {
} ConvTable;
-/*================================================================
+/*
* prototypes
- *================================================================*/
+ */
static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
static void awe_midi_close(int dev);
@@ -5183,9 +5216,9 @@ static int xg_control_change(MidiStatus *st, int cmd, int val);
#define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
-/*================================================================
+/*
* OSS Midi device record
- *================================================================*/
+ */
static struct midi_operations awe_midi_operations =
{
@@ -5204,7 +5237,7 @@ static struct midi_operations awe_midi_operations =
static int my_mididev = -1;
-static void attach_midiemu(void)
+static void __init attach_midiemu(void)
{
if ((my_mididev = sound_alloc_mididev()) < 0)
printk ("Sound: Too many midi devices detected\n");
@@ -5212,7 +5245,7 @@ static void attach_midiemu(void)
midi_devs[my_mididev] = &awe_midi_operations;
}
-static void unload_midiemu(void)
+static void __exit unload_midiemu(void)
{
if (my_mididev >= 0)
sound_unload_mididev(my_mididev);
@@ -5632,9 +5665,9 @@ static void midi_select_bank(MidiStatus *st, int val)
}
-/*================================================================
+/*
* RPN events
- *================================================================*/
+ */
static void midi_rpn_event(MidiStatus *st)
{
@@ -5686,10 +5719,10 @@ static void midi_detune(int chan, int coarse, int fine)
}
-/*================================================================
+/*
* system exclusive message
* GM/GS/XG macros are accepted
- *================================================================*/
+ */
static void midi_system_exclusive(MidiStatus *st)
{
@@ -5784,6 +5817,8 @@ static void midi_system_exclusive(MidiStatus *st)
}
+/*----------------------------------------------------------------*/
+
/*
* convert NRPN/control values
*/
@@ -6006,9 +6041,9 @@ static ConvTable gs_effects[] =
static int num_gs_effects = numberof(gs_effects);
-/*================================================================
+/*
* NRPN events: accept as AWE32/SC88 specific controls
- *================================================================*/
+ */
static void midi_nrpn_event(MidiStatus *st)
{
@@ -6026,9 +6061,9 @@ static void midi_nrpn_event(MidiStatus *st)
}
-/*----------------------------------------------------------------
+/*
* XG control effects; still experimental
- *----------------------------------------------------------------*/
+ */
/* cutoff: quarter semitone step, max=255 */
static unsigned short xg_cutoff(int val)
@@ -6071,45 +6106,42 @@ static int xg_control_change(MidiStatus *st, int cmd, int val)
#endif /* CONFIG_AWE32_MIDIEMU */
-/* new type interface */
-static int __init attach_awe(void)
+
+/*----------------------------------------------------------------*/
+
+/*
+ * device / lowlevel (module) interface
+ */
+
+int __init attach_awe(void)
{
-#ifdef CONFIG_PNP_DRV
- if (pnp) {
- awe_initpnp();
- if (awe_pnp_ok)
- return 0;
- }
-#endif /* pnp */
-
- _attach_awe();
-
- return 0;
-}
+ return _attach_awe() ? 0 : -ENODEV;
+}
-static void __exit unload_awe(void)
+void __exit unload_awe(void)
{
-#ifdef CONFIG_PNP_DRV
- if (pnp)
- awe_unload_pnp();
-#endif
-
_unload_awe();
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+ if (isapnp)
+ awe_deactivate_isapnp();
+#endif /* isapnp */
}
+
module_init(attach_awe);
module_exit(unload_awe);
#ifndef MODULE
static int __init setup_awe(char *str)
{
- /* io, memsize */
- int ints[3];
+ /* io, memsize, isapnp */
+ int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
io = ints[1];
memsize = ints[2];
+ isapnp = ints[3];
return 1;
}
diff --git a/drivers/sound/awe_wave.h b/drivers/sound/awe_wave.h
index 0984da765..a3aa01811 100644
--- a/drivers/sound/awe_wave.h
+++ b/drivers/sound/awe_wave.h
@@ -2,7 +2,7 @@
* sound/awe_config.h
*
* Configuration of AWE32/SB32/AWE64 wave table synth driver.
- * version 0.4.3; Mar. 1, 1998
+ * version 0.4.4; Jan. 4, 2000
*
* Copyright (C) 1996-1998 Takashi Iwai
*
@@ -68,20 +68,10 @@
/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */
/*
- * maximum size of soundfont list table
+ * AWE driver version number
*/
-
-#define AWE_MAX_SF_LISTS 16
-
-/*
- * chunk size of sample and voice tables
- */
-
-#define AWE_MAX_SAMPLES 400
-#define AWE_MAX_INFOS 800
-
#define AWE_MAJOR_VERSION 0
#define AWE_MINOR_VERSION 4
-#define AWE_TINY_VERSION 3
+#define AWE_TINY_VERSION 4
#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
-#define AWEDRV_VERSION "0.4.3"
+#define AWEDRV_VERSION "0.4.4"
diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h
index 282e644a3..6e24d6e89 100644
--- a/drivers/sound/sb.h
+++ b/drivers/sound/sb.h
@@ -151,6 +151,7 @@ int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio);
int sb_dsp_init (struct address_info *hw_config);
void sb_dsp_unload(struct address_info *hw_config, int sbmpu);
int sb_mixer_init(sb_devc *devc);
+void sb_mixer_unload(sb_devc *devc);
void sb_mixer_set_stereo (sb_devc *devc, int mode);
void smw_mixer_init(sb_devc *devc);
void sb_dsp_midi_init (sb_devc *devc);
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index c471163ef..557a971a4 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -29,6 +29,10 @@
* 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup
* Alessandro Zummo <azummo@ita.flashnet.it>
*
+ * 13-03-2000 Added some more cards, thanks to Torsten Werner.
+ * Removed joystick and wavetable code, there are better places for them.
+ * Code cleanup plus some fixes.
+ *
*/
#include <linux/config.h>
@@ -145,10 +149,7 @@ static struct address_info cfg;
static struct address_info cfg_mpu;
struct pci_dev *sb_dev = NULL,
- *wss_dev = NULL,
- *jp_dev = NULL,
- *mpu_dev = NULL,
- *wt_dev = NULL;
+ *mpu_dev = NULL;
/*
* Note DMA2 of -1 has the right meaning in the SB16 driver as well
* as here. It will cause either an error if it is needed or a fallback
@@ -166,10 +167,9 @@ static int __initdata type = 0; /* Can set this to a specific card type */
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
static int isapnp = 1;
static int isapnpjump = 0;
-static int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be
- in the kernel tree */
+static int activated = 1;
#else
-int isapnp = 0;
+static int isapnp = 0;
#endif
MODULE_DESCRIPTION("Soundblaster driver");
@@ -187,10 +187,8 @@ MODULE_PARM(acer, "i");
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
MODULE_PARM(isapnp, "i");
MODULE_PARM(isapnpjump, "i");
-MODULE_PARM(nosbwave, "i");
MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled");
MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
-MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver.");
#endif
MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
@@ -213,12 +211,13 @@ static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev
{
int err;
+ /* Device already active? Let's use it */
+
if(dev->active)
{
- printk(KERN_INFO "sb: %s %s already in use\n", devname, resname);
- return(NULL);
+ activated = 0;
+ return(dev);
}
-
if((err = dev->activate(dev)) < 0)
{
printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err);
@@ -324,42 +323,6 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
else
printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n");
-
- /* @P@:Gameport
- */
-
- if((jp_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- jp_dev->prepare(jp_dev);
-
- if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev)))
- show_base("CMI8330", "gameport", &jp_dev->resource[0]);
- }
- else
- printk(KERN_ERR "sb: CMI8330 panic: gameport not found\n");
-
- /* @@@0001:OPL3
- */
-
-#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
- if((wss_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- wss_dev->prepare(wss_dev);
-
- /* Let's disable IRQ and DMA for WSS device */
-
- wss_dev->irq_resource[0].flags = 0;
- wss_dev->dma_resource[0].flags = 0;
-
- if((wss_dev = activate_dev("CMI8330", "opl3", wss_dev)))
- show_base("CMI8330", "opl3", &wss_dev->resource[1]);
- }
- else
- printk(KERN_ERR "sb: CMI8330 panic: opl3 not found\n");
-#endif
-
printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
return(sb_dev);
@@ -391,7 +354,6 @@ static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card
}
if(!sb_dev) return(NULL);
-
}
else
printk(KERN_ERR "sb: DT0197H panic: sb base not found\n");
@@ -413,169 +375,100 @@ static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card
else
printk(KERN_ERR "sb: DT0197H panic: mpu not found\n");
-
- /* @P@:Gameport
- */
-
- if((jp_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- jp_dev->prepare(jp_dev);
-
- if((jp_dev = activate_dev("DT0197H", "gameport", jp_dev)))
- show_base("DT0197H", "gameport", &jp_dev->resource[0]);
- }
- else
- printk(KERN_ERR "sb: DT0197H panic: gameport not found\n");
-
- /* @H@0001:OPL3
- */
-
-#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
- if((wss_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- wss_dev->prepare(wss_dev);
-
- /* Let's disable IRQ and DMA for WSS device */
-
- wss_dev->irq_resource[0].flags = 0;
- wss_dev->dma_resource[0].flags = 0;
-
- if((wss_dev = activate_dev("DT0197H", "opl3", wss_dev)))
- show_base("DT0197H", "opl3", &wss_dev->resource[0]);
- }
- else
- printk(KERN_ERR "sb: DT0197H panic: opl3 not found\n");
-#endif
-
printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner <twerner@intercomm.de>\n");
return(sb_dev);
}
-/* Specific support for awe will be dropped when:
- * a) The new awe_wawe driver with PnP support will be introduced in the kernel
- * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-)
- */
-
-static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_als(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
{
- /* CTL0042:Audio SB64
- * CTL0031:Audio SB32
- * CTL0045:Audio SB64
+ /*
+ * ALS100
+ * very similar to both ones above above
*/
- if( (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) ||
- (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) ||
- (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL)) )
+ /* @@@0001:Soundblaster.
+ */
+
+ if((sb_dev = isapnp_find_dev(bus,
+ ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
sb_dev->prepare(sb_dev);
- if((sb_dev = activate_dev("AWE", "sb", sb_dev)))
+ if((sb_dev = activate_dev("ALS100", "sb", sb_dev)))
{
hw_config->io_base = sb_dev->resource[0].start;
hw_config->irq = sb_dev->irq_resource[0].start;
- hw_config->dma = sb_dev->dma_resource[0].start;
- hw_config->dma2 = sb_dev->dma_resource[1].start;
+ hw_config->dma = sb_dev->dma_resource[1].start;
+ hw_config->dma2 = sb_dev->dma_resource[0].start;
- mpu_config->io_base = sb_dev->resource[1].start;
-
- show_base("AWE", "sb", &sb_dev->resource[0]);
- show_base("AWE", "mpu", &sb_dev->resource[1]);
- show_base("AWE", "opl3", &sb_dev->resource[2]);
+ show_base("ALS100", "sb", &sb_dev->resource[0]);
}
- else
- return(NULL);
- }
- else
- printk(KERN_ERR "sb: AWE panic: sb base not found\n");
-
-
- /* CTL7002:Game SB64
- * CTL7001:Game SB32
- */
- if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) ||
- (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) )
- {
- jp_dev->prepare(jp_dev);
-
- if((jp_dev = activate_dev("AWE", "gameport", jp_dev)))
- show_base("AWE", "gameport", &jp_dev->resource[0]);
+ if(!sb_dev) return(NULL);
}
else
- printk(KERN_ERR "sb: AWE panic: gameport not found\n");
+ printk(KERN_ERR "sb: ALS100 panic: sb base not found\n");
-
- /* CTL0022:WaveTable SB64
- * CTL0021:WaveTable SB32
- * CTL0023:WaveTable Sb64
+ /* @X@0001:mpu
*/
- if( nosbwave == 0 &&
- ( ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) ||
- ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) ||
- ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) ))
+ if((mpu_dev = isapnp_find_dev(bus,
+ ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
- wt_dev->prepare(wt_dev);
-
- if((wt_dev = activate_dev("AWE", "wavetable", wt_dev)))
+ mpu_dev->prepare(mpu_dev);
+
+ if((mpu_dev = activate_dev("ALS100", "mpu", mpu_dev)))
{
- show_base("AWE", "wavetable", &wt_dev->resource[0]);
- show_base("AWE", "wavetable", &wt_dev->resource[1]);
- show_base("AWE", "wavetable", &wt_dev->resource[2]);
+ show_base("ALS100", "mpu", &mpu_dev->resource[0]);
+ mpu_config->io_base = mpu_dev->resource[0].start;
}
}
else
- printk(KERN_ERR "sb: AWE panic: wavetable not found\n");
+ printk(KERN_ERR "sb: ALS100 panic: mpu not found\n");
- printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
+ printk(KERN_INFO "sb: ALS100 mail reports to Torsten Werner <twerner@intercomm.de>\n");
return(sb_dev);
}
-#define SBF_DEV 0x01
+#define SBF_DEV 0x01 /* Please notice that cards without this flag are on the top in the list */
static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
-isapnp_sb_list[] __initdata = {
+sb_isapnp_list[] __initdata = {
+ {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
+ {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" },
+ {ISAPNP_VENDOR('A','L','S'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_als, "ALS 100" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV, &sb_init_ess, "ESS 1688" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" },
- {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
- {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" },
{0}
};
-static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
+static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
{
struct pci_dev *idev = NULL;
/* You missed the init func? That's bad. */
- if(isapnp_sb_list[slot].initfunc)
+ if(sb_isapnp_list[slot].initfunc)
{
- char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name;
+ char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
printk(KERN_INFO "sb: %s detected\n", busname);
/* Initialize this baby. */
- if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config)))
+ if((idev = sb_isapnp_list[slot].initfunc(bus, card, hw_config, mpu_config)))
{
/* We got it. */
@@ -600,12 +493,12 @@ static int __init sb_init_isapnp(struct address_info *hw_config, struct address_
Should this be fixed? - azummo
*/
-int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config)
+int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config)
{
int i;
- /* Count entries in isapnp_sb_list */
- for (i = 0; isapnp_sb_list[i].vendor != 0; i++);
+ /* Count entries in sb_isapnp_list */
+ for (i = 0; sb_isapnp_list[i].vendor != 0; i++);
/* Check and adjust isapnpjump */
if( isapnpjump < 0 || isapnpjump > ( i - 1 ) )
@@ -614,18 +507,18 @@ int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *
isapnpjump = 0;
}
- for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
+ for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
- if(!(isapnp_sb_list[i].flags & SBF_DEV))
+ if(!(sb_isapnp_list[i].flags & SBF_DEV))
{
struct pci_bus *bus = NULL;
while ((bus = isapnp_find_card(
- isapnp_sb_list[i].vendor,
- isapnp_sb_list[i].function,
+ sb_isapnp_list[i].vendor,
+ sb_isapnp_list[i].function,
bus))) {
- if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i))
+ if(sb_isapnp_init(hw_config, mpu_config, bus, NULL, i))
return 0;
}
}
@@ -635,18 +528,18 @@ int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *
* that matches any entry marked with SBF_DEV in the table.
*/
- for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
+ for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
- if(isapnp_sb_list[i].flags & SBF_DEV)
+ if(sb_isapnp_list[i].flags & SBF_DEV)
{
struct pci_dev *card = NULL;
while ((card = isapnp_find_dev(NULL,
- isapnp_sb_list[i].vendor,
- isapnp_sb_list[i].function,
+ sb_isapnp_list[i].vendor,
+ sb_isapnp_list[i].function,
card))) {
- if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i))
+ if(sb_isapnp_init(hw_config, mpu_config, card->bus, card, i))
return 0;
}
}
@@ -665,7 +558,7 @@ static int __init init_sb(void)
*/
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
- if(isapnp && (sb_probe_isapnp(&cfg, &cfg_mpu) < 0) ) {
+ if(isapnp && (sb_isapnp_probe(&cfg, &cfg_mpu) < 0) ) {
printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
isapnp = 0;
}
@@ -707,11 +600,13 @@ static void __exit cleanup_sb(void)
unload_sbmpu(&cfg_mpu);
SOUND_LOCK_END;
- if(sb_dev) sb_dev->deactivate(sb_dev);
- if(jp_dev) jp_dev->deactivate(jp_dev);
- if(wt_dev) wt_dev->deactivate(wt_dev);
- if(mpu_dev) mpu_dev->deactivate(mpu_dev);
- if(wss_dev) wss_dev->deactivate(wss_dev);
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+ if(activated)
+ {
+ if(sb_dev) sb_dev->deactivate(sb_dev);
+ if(mpu_dev) mpu_dev->deactivate(mpu_dev);
+ }
+#endif
}
module_init(init_sb);
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index 5fb40f46d..80c282a5d 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -908,13 +908,10 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
}
if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI))
{
- extern int sbmixnum;
-
if (devc->irq > 0)
free_irq(devc->irq, devc);
- sound_unload_mixerdev(devc->my_mixerdev);
- sbmixnum--;
+ sb_mixer_unload(devc);
/* We don't have to do this bit any more the UART401 is its own
master -- Krzysztof Halasa */
/* But we have to do it, if UART401 is not detected */
diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c
index f441be0aa..a955db7e3 100644
--- a/drivers/sound/sb_mixer.c
+++ b/drivers/sound/sb_mixer.c
@@ -740,3 +740,9 @@ int sb_mixer_init(sb_devc * devc)
sb_mixer_reset(devc);
return 1;
}
+
+void sb_mixer_unload(sb_devc *devc)
+{
+ sound_unload_mixerdev(devc->my_mixerdev);
+ sbmixnum--;
+}
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 012a27187..28ad96481 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -43,6 +43,7 @@ comment 'USB Devices'
dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB m
if [ "$CONFIG_USB_STORAGE" != "n" ]; then
bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 6e9e99714..06b0a4648 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_CPIA) += cpia.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o
obj-$(CONFIG_USB_DC2XX) += dc2xx.o
+obj-$(CONFIG_USB_MDC800) += mdc800.o
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
diff --git a/drivers/usb/hid-debug.h b/drivers/usb/hid-debug.h
index 8aaf4be81..b72565fb9 100644
--- a/drivers/usb/hid-debug.h
+++ b/drivers/usb/hid-debug.h
@@ -105,6 +105,7 @@ static struct hid_usage_entry hid_usage_table[] = {
{0, 0x35, "Tap"},
{0, 0x39, "TabletFunctionKey"},
{0, 0x3a, "ProgramChangeKey"},
+ {0, 0x3c, "Invert"},
{0, 0x42, "TipSwitch"},
{0, 0x43, "SecondaryTipSwitch"},
{0, 0x44, "BarrelSwitch"},
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index c7bb34e4d..b8af56051 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -802,6 +802,11 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
case 0x30: /* TipPressure */
+ if (!test_bit(BTN_TOUCH, input->keybit)) {
+ device->quirks |= HID_QUIRK_NOTOUCH;
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_TOUCH, input->keybit);
+ }
usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
usage->code = ABS_PRESSURE;
clear_bit(usage->code, bit);
@@ -817,10 +822,18 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
}
break;
+ case 0x3c: /* Invert */
+
+ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+ usage->code = BTN_TOOL_RUBBER;
+ clear_bit(usage->code, bit);
+ break;
+
case 0x33: /* Touch */
case 0x42: /* TipSwitch */
case 0x43: /* TipSwitch2 */
+ device->quirks &= ~HID_QUIRK_NOTOUCH;
usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
usage->code = BTN_TOUCH;
clear_bit(usage->code, bit);
@@ -930,7 +943,7 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
}
}
-static void hid_process_event(struct input_dev *input, int flags, struct hid_usage *usage, __s32 value)
+static void hid_process_event(struct input_dev *input, int *quirks, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
hid_dump_input(usage, value);
@@ -941,9 +954,30 @@ static void hid_process_event(struct input_dev *input, int flags, struct hid_usa
return;
}
+ if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
+ *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
+ return;
+ }
+
+ if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
+ if (value) {
+ input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
+ return;
+ }
+ input_event(input, usage->type, usage->code, 0);
+ input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
+ return;
+ }
+
+ if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
+ int a = field->logical_minimum;
+ int b = field->logical_maximum;
+ input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
+ }
+
input_event(input, usage->type, usage->code, value);
- if ((flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
+ if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
input_event(input, usage->type, usage->code, 0);
}
@@ -986,19 +1020,21 @@ static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u
} else {
if (value[n] == field->value[n]) continue;
}
- hid_process_event(&dev->input, field->flags, &field->usage[n], value[n]);
+ hid_process_event(&dev->input, &dev->quirks, field, &field->usage[n], value[n]);
} else {
if (field->value[n] >= min && field->value[n] <= max /* non-NULL value */
&& field->usage[field->value[n] - min].hid /* nonzero usage */
&& search(value, field->value[n], count))
- hid_process_event(&dev->input, field->flags, &field->usage[field->value[n] - min], 0);
+ hid_process_event(&dev->input, &dev->quirks, field,
+ &field->usage[field->value[n] - min], 0);
if (value[n] >= min && value[n] <= max /* non-NULL value */
&& field->usage[value[n] - min].hid /* nonzero usage */
&& search(field->value, value[n], count))
- hid_process_event(&dev->input, field->flags, &field->usage[value[n] - min], 1);
+ hid_process_event(&dev->input, &dev->quirks,
+ field, &field->usage[value[n] - min], 1);
}
}
@@ -1261,14 +1297,18 @@ static void hid_init_input(struct hid_device *hid)
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS 0x0021
+#define USB_DEVICE_ID_WACOM_INTUOS 0x0020
struct hid_blacklist {
__u16 idVendor;
__u16 idProduct;
} hid_blacklist[] = {
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1},
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
{ 0, 0 }
};
diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h
index 4a4caf401..18e7481c2 100644
--- a/drivers/usb/hid.h
+++ b/drivers/usb/hid.h
@@ -179,6 +179,13 @@ struct hid_item {
#define HID_FEATURE_REPORT 2
/*
+ * HID device quirks.
+ */
+
+#define HID_QUIRK_INVERT 0x01
+#define HID_QUIRK_NOTOUCH 0x02
+
+/*
* This is the global enviroment of the parser. This information is
* persistent for main-items. The global enviroment can be saved and
* restored with PUSH/POP statements.
@@ -285,6 +292,7 @@ struct hid_device { /* device report descriptor */
struct urb urb; /* USB URB structure */
struct urb urbout; /* Output URB */
struct input_dev input; /* input device structure */
+ int quirks; /* Various nasty tricks the device can pull on us */
};
#define HID_GLOBAL_STACK_SIZE 4
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index 2aef212cb..7c94c185b 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -58,7 +58,8 @@ static unsigned char keybdev_mac_codes[256] =
#endif
-struct input_handler keybdev_handler;
+static struct input_handler keybdev_handler;
+static int keybdev_alt = 0;
void keybdev_ledfunc(unsigned int led)
{
@@ -93,14 +94,22 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int
handle_scancode(0x1d, down);
handle_scancode(0x45, down);
} else if (code >= 96) {
- handle_scancode(0xe0, 1);
- handle_scancode(keybdev_x86_e0s[code - 96], down);
- if (code == 99) {
+ if (code == 99 && keybdev_alt) {
+ handle_scancode(84, down);
+ } else {
handle_scancode(0xe0, 1);
- handle_scancode(0x37, down);
+ handle_scancode(keybdev_x86_e0s[code - 96], down);
+ if (code == 99) {
+ handle_scancode(0xe0, 1);
+ handle_scancode(0x37, down);
+ }
}
+ } else if (code == 84) {
+ handle_scancode(43, down);
} else handle_scancode(code, down);
+ if (code == 56 || code == 100) keybdev_alt = down;
+
#elif CONFIG_ADB_KEYBOARD
if (code < 128 && keybdev_mac_codes[code])
@@ -152,7 +161,7 @@ static void keybdev_disconnect(struct input_handle *handle)
kfree(handle);
}
-struct input_handler keybdev_handler = {
+static struct input_handler keybdev_handler = {
event: keybdev_event,
connect: keybdev_connect,
disconnect: keybdev_disconnect,
diff --git a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c
new file mode 100644
index 000000000..c8063c927
--- /dev/null
+++ b/drivers/usb/mdc800.c
@@ -0,0 +1,931 @@
+/*
+ * copyright (C) 1999/2000 by Henning Zabel <henning@uni-paderborn.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * USB-Kernel Driver for the Mustek MDC800 Digital Camera
+ * (c) 1999/2000 Henning Zabel <henning@uni-paderborn.de>
+ *
+ *
+ * The driver brings the USB functions of the MDC800 to Linux.
+ * To use the Camera you must support the USB Protocoll of the camera
+ * to the Kernel Node.
+ * The Driver uses a misc device Node. Create it with :
+ * mknod /dev/mustek c 10 171
+ *
+ * The driver supports only one camera.
+ *
+ * version 0.7.1
+ * The Init und Exit Module Function are updated.
+ * (01/03/2000)
+ *
+ * version 0.7.0
+ * Rewrite of the driver : The driver now uses URB's. The old stuff
+ * has been removed.
+ *
+ * version 0.6.0
+ * Rewrite of this driver: The Emulation of the rs232 protocoll
+ * has been removed from the driver. A special executeCommand function
+ * for this driver is included to gphoto.
+ * The driver supports two kind of communication to bulk endpoints.
+ * Either with the dev->bus->ops->bulk... or with callback function.
+ * (09/11/1999)
+ *
+ * version 0.5.0:
+ * first Version that gets a version number. Most of the needed
+ * functions work.
+ * (20/10/1999)
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/spinlock.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 <linux/module.h>
+
+#include <linux/usb.h>
+
+#define VERSION "0.7.1"
+#define RELEASE_DATE "(01/03/2000)"
+
+/* Vendor and Product Information */
+#define MDC800_VENDOR_ID 0x055f
+#define MDC800_PRODUCT_ID 0xa800
+
+/* Timeouts (msec) */
+#define TO_READ_FROM_IRQ 4000
+#define TO_GET_READY 2000
+#define TO_DOWNLOAD_GET_READY 1500
+#define TO_DOWNLOAD_GET_BUSY 1500
+#define TO_WRITE_GET_READY 3000
+#define TO_DEFAULT_COMMAND 5000
+
+/* Minor Number of the device (create with mknod /dev/mustek c 10 171) */
+#define MDC800_DEVICE_MINOR 171
+
+
+/**************************************************************************
+ Data and structs
+***************************************************************************/
+
+
+typedef enum {
+ NOT_CONNECTED, READY, WORKING, DOWNLOAD
+} mdc800_state;
+
+
+/* Data for the driver */
+struct mdc800_data
+{
+ struct usb_device * dev; // Device Data
+ mdc800_state state;
+
+ unsigned int endpoint [4];
+
+ purb_t irq_urb;
+ wait_queue_head_t irq_wait;
+ char* irq_urb_buffer;
+
+ int camera_busy; // is camera busy ?
+ int camera_request_ready; // Status to synchronize with irq
+ char camera_response [8]; // last Bytes send after busy
+
+ purb_t write_urb;
+ char* write_urb_buffer;
+ wait_queue_head_t write_wait;
+
+
+ purb_t download_urb;
+ char* download_urb_buffer;
+ wait_queue_head_t download_wait;
+ int download_left; // Bytes left to download ?
+
+
+ /* Device Data */
+ char out [64]; // Answer Buffer
+ int out_ptr; // Index to the first not readen byte
+ int out_count; // Bytes in the buffer
+
+ int open; // Camera device open ?
+ int rw_lock; // Block read <-> write
+
+ char in [8]; // Command Input Buffer
+ int in_count;
+
+ int pic_index; // Cache for the Imagesize (-1 for nothing cached )
+ int pic_len;
+};
+
+
+/* Specification of the Endpoints */
+static struct usb_endpoint_descriptor mdc800_ed [4] =
+{
+ { 0,0, 0x01, 0x02, 8, 0,0,0 },
+ { 0,0, 0x82, 0x03, 8, 0,0,0 },
+ { 0,0, 0x03, 0x02, 64, 0,0,0 },
+ { 0,0, 0x84, 0x02, 64, 0,0,0 }
+};
+
+
+/* The Variable used by the driver */
+static struct mdc800_data* mdc800=0;
+
+
+/***************************************************************************
+ The USB Part of the driver
+****************************************************************************/
+
+static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b)
+{
+ return (
+ ( a->bEndpointAddress == b->bEndpointAddress )
+ && ( a->bmAttributes == b->bmAttributes )
+ && ( a->wMaxPacketSize == b->wMaxPacketSize )
+ );
+}
+
+
+/*
+ * Checks wether the camera responds busy
+ */
+static int mdc800_isBusy (char* ch)
+{
+ int i=0;
+ while (i<8)
+ {
+ if (ch [i] != (char)0x99)
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+
+/*
+ * Checks wether the Camera is ready
+ */
+static int mdc800_isReady (char *ch)
+{
+ int i=0;
+ while (i<8)
+ {
+ if (ch [i] != (char)0xbb)
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+
+
+/*
+ * USB IRQ Handler for InputLine
+ */
+static void mdc800_usb_irq (struct urb *urb)
+{
+ int data_received=0, wake_up;
+ unsigned char* b=urb->transfer_buffer;
+ struct mdc800_data* mdc800=urb->context;
+
+ if (urb->status >= 0)
+ {
+
+ //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+ if (mdc800_isBusy (b))
+ {
+ if (!mdc800->camera_busy)
+ {
+ mdc800->camera_busy=1;
+ dbg ("gets busy");
+ }
+ }
+ else
+ {
+ if (mdc800->camera_busy && mdc800_isReady (b))
+ {
+ mdc800->camera_busy=0;
+ dbg ("gets ready");
+ }
+ }
+ if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
+ {
+ /* Store Data in camera_answer field */
+ dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+ memcpy (mdc800->camera_response,b,8);
+ data_received=1;
+ }
+ }
+ wake_up= ( mdc800->camera_request_ready > 0 )
+ &&
+ (
+ ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy))
+ ||
+ ((mdc800->camera_request_ready == 2) && data_received)
+ ||
+ ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
+ ||
+ (urb->status < 0)
+ );
+
+ if (wake_up)
+ {
+ mdc800->camera_request_ready=0;
+ wake_up_interruptible (&mdc800->irq_wait);
+ }
+}
+
+
+/*
+ * Waits a while until the irq responds that camera is ready
+ *
+ * mode : 0: Wait for camera gets ready
+ * 1: Wait for receiving data
+ * 2: Wait for camera gets busy
+ *
+ * msec: Time to wait
+ */
+static int mdc800_usb_waitForIRQ (int mode, int msec)
+{
+ mdc800->camera_request_ready=1+mode;
+
+ interruptible_sleep_on_timeout (&mdc800->irq_wait, msec*HZ/1000);
+
+ if (mdc800->camera_request_ready>0)
+ {
+ mdc800->camera_request_ready=0;
+ err ("timeout waiting for camera.");
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * The write_urb callback function
+ */
+static void mdc800_usb_write_notify (struct urb *urb)
+{
+ struct mdc800_data* mdc800=urb->context;
+
+ if (urb->status != 0)
+ {
+ err ("writing command fails (status=%i)", urb->status);
+ }
+ mdc800->state=READY;
+ wake_up_interruptible (&mdc800->write_wait);
+}
+
+
+/*
+ * The download_urb callback function
+ */
+static void mdc800_usb_download_notify (struct urb *urb)
+{
+ struct mdc800_data* mdc800=urb->context;
+
+ if (urb->status == 0)
+ {
+ /* Fill output buffer with these data */
+ memcpy (mdc800->out, urb->transfer_buffer, 64);
+ mdc800->out_count=64;
+ mdc800->out_ptr=0;
+ mdc800->download_left-=64;
+ if (mdc800->download_left == 0)
+ {
+ mdc800->state=READY;
+ }
+ }
+ else
+ {
+ err ("request bytes fails (status:%i)", urb->status);
+ mdc800->state=READY;
+ }
+ wake_up_interruptible (&mdc800->download_wait);
+}
+
+
+/***************************************************************************
+ Probing for the Camera
+ ***************************************************************************/
+
+static struct usb_driver mdc800_usb_driver;
+
+/*
+ * Callback to search the Mustek MDC800 on the USB Bus
+ */
+static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
+{
+ int i,j;
+ struct usb_interface_descriptor *intf_desc;
+ int irq_interval=0;
+
+ dbg ("(mdc800_usb_probe) called.");
+
+ if (mdc800->dev != 0)
+ {
+ warn ("only one Mustek MDC800 is supported.");
+ return 0;
+ }
+
+ if (dev->descriptor.idVendor != MDC800_VENDOR_ID)
+ return 0;
+ if (dev->descriptor.idProduct != MDC800_PRODUCT_ID)
+ return 0;
+
+ if (dev->descriptor.bNumConfigurations != 1)
+ {
+ err ("probe fails -> wrong Number of Configuration");
+ return 0;
+ }
+ intf_desc=&dev->actconfig->interface[ifnum].altsetting[0];
+
+ if (
+ ( intf_desc->bInterfaceClass != 0xff )
+ || ( intf_desc->bInterfaceSubClass != 0 )
+ || ( intf_desc->bInterfaceProtocol != 0 )
+ || ( intf_desc->bNumEndpoints != 4)
+ )
+ {
+ err ("probe fails -> wrong Interface");
+ return 0;
+ }
+
+ /* Check the Endpoints */
+ for (i=0; i<4; i++)
+ {
+ mdc800->endpoint[i]=-1;
+ for (j=0; j<4; j++)
+ {
+ if (mdc800_endpoint_equals (&intf_desc->endpoint [j],&mdc800_ed [i]))
+ {
+ mdc800->endpoint[i]=intf_desc->endpoint [j].bEndpointAddress ;
+ if (i==1)
+ {
+ irq_interval=intf_desc->endpoint [j].bInterval;
+ }
+
+ continue;
+ }
+ }
+ if (mdc800->endpoint[i] == -1)
+ {
+ err ("probe fails -> Wrong Endpoints.");
+ return 0;
+ }
+ }
+
+
+ usb_driver_claim_interface (&mdc800_usb_driver, &dev->actconfig->interface[ifnum], mdc800);
+ if (usb_set_interface (dev, ifnum, 0) < 0)
+ {
+ err ("MDC800 Configuration fails.");
+ return 0;
+ }
+
+ info ("Found Mustek MDC800 on USB.");
+
+ mdc800->dev=dev;
+ mdc800->state=READY;
+
+ /* Setup URB Structs */
+ FILL_INT_URB (
+ mdc800->irq_urb,
+ mdc800->dev,
+ usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]),
+ mdc800->irq_urb_buffer,
+ 8,
+ mdc800_usb_irq,
+ mdc800,
+ irq_interval
+ );
+
+ FILL_BULK_URB (
+ mdc800->write_urb,
+ mdc800->dev,
+ usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]),
+ mdc800->write_urb_buffer,
+ 8,
+ mdc800_usb_write_notify,
+ mdc800
+ );
+
+ FILL_BULK_URB (
+ mdc800->download_urb,
+ mdc800->dev,
+ usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]),
+ mdc800->download_urb_buffer,
+ 64,
+ mdc800_usb_download_notify,
+ mdc800
+ );
+
+ return mdc800;
+}
+
+
+/*
+ * Disconnect USB device (maybe the MDC800)
+ */
+static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
+{
+ struct mdc800_data* mdc800=(struct mdc800_data*) ptr;
+
+ dbg ("(mdc800_usb_disconnect) called");
+
+ if (mdc800->state == NOT_CONNECTED)
+ return;
+
+ mdc800->state=NOT_CONNECTED;
+ mdc800->open=0;
+ mdc800->rw_lock=0;
+
+ usb_unlink_urb (mdc800->irq_urb);
+ usb_unlink_urb (mdc800->write_urb);
+ usb_unlink_urb (mdc800->download_urb);
+
+ usb_driver_release_interface (&mdc800_usb_driver, &dev->actconfig->interface[1]);
+
+ mdc800->dev=0;
+ info ("Mustek MDC800 disconnected from USB.");
+}
+
+
+/***************************************************************************
+ The Misc device Part (file_operations)
+****************************************************************************/
+
+/*
+ * This Function calc the Answersize for a command.
+ */
+static int mdc800_getAnswerSize (char command)
+{
+ switch ((unsigned char) command)
+ {
+ case 0x2a:
+ case 0x49:
+ case 0x51:
+ case 0x0d:
+ case 0x20:
+ case 0x07:
+ case 0x01:
+ case 0x25:
+ case 0x00:
+ return 8;
+
+ case 0x05:
+ case 0x3e:
+ return mdc800->pic_len;
+
+ case 0x09:
+ return 4096;
+
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ * Init the device: (1) alloc mem (2) Increase MOD Count ..
+ */
+static int mdc800_device_open (struct inode* inode, struct file *file)
+{
+ int retval=0;
+ if (mdc800->state == NOT_CONNECTED)
+ return -EBUSY;
+
+ if (mdc800->open)
+ return -EBUSY;
+
+ mdc800->rw_lock=0;
+ mdc800->in_count=0;
+ mdc800->out_count=0;
+ mdc800->out_ptr=0;
+ mdc800->pic_index=0;
+ mdc800->pic_len=-1;
+ mdc800->download_left=0;
+
+ mdc800->camera_busy=0;
+ mdc800->camera_request_ready=0;
+
+ retval=0;
+ if (usb_submit_urb (mdc800->irq_urb))
+ {
+ err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+ return -EIO;
+ }
+
+ MOD_INC_USE_COUNT;
+ mdc800->open=1;
+
+ dbg ("Mustek MDC800 device opened.");
+ return 0;
+}
+
+
+/*
+ * Close the Camera and release Memory
+ */
+static int mdc800_device_release (struct inode* inode, struct file *file)
+{
+ int retval=0;
+ dbg ("Mustek MDC800 device closed.");
+
+ if (mdc800->open && (mdc800->state != NOT_CONNECTED))
+ {
+ mdc800->open=0;
+ usb_unlink_urb (mdc800->irq_urb);
+ usb_unlink_urb (mdc800->write_urb);
+ usb_unlink_urb (mdc800->download_urb);
+ }
+ else
+ {
+ retval=-EIO;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ return retval;
+}
+
+
+/*
+ * The Device read callback Function
+ */
+static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
+{
+ int left=len, sts=len; /* single transfer size */
+ char* ptr=buf;
+
+ if (mdc800->state == NOT_CONNECTED)
+ return -EBUSY;
+
+ if (!mdc800->open || mdc800->rw_lock)
+ return -EBUSY;
+ mdc800->rw_lock=1;
+
+ while (left)
+ {
+ if (signal_pending (current)) {
+ mdc800->rw_lock=0;
+ return -EINTR;
+ }
+
+ sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
+
+ if (sts <= 0)
+ {
+ /* Too less Data in buffer */
+ if (mdc800->state == DOWNLOAD)
+ {
+ mdc800->out_count=0;
+ mdc800->out_ptr=0;
+
+ /* Download -> Request new bytes */
+ if (usb_submit_urb (mdc800->download_urb))
+ {
+ err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return len-left;
+ }
+ interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000);
+ if (mdc800->download_urb->status != 0)
+ {
+ err ("requesting bytes fails (status=%i)",mdc800->download_urb->status);
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return len-left;
+ }
+ }
+ else
+ {
+ /* No more bytes -> that's an error*/
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+ }
+ else
+ {
+ /* memcpy Bytes */
+ memcpy (ptr, &mdc800->out [mdc800->out_ptr], sts);
+ ptr+=sts;
+ left-=sts;
+ mdc800->out_ptr+=sts;
+ }
+ }
+
+ mdc800->rw_lock=0;
+ return len-left;
+}
+
+
+/*
+ * The Device write callback Function
+ * If a 8Byte Command is received, it will be send to the camera.
+ * After this the driver initiates the request for the answer or
+ * just waits until the camera becomes ready.
+ */
+static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
+{
+ int i=0;
+
+ if (mdc800->state != READY)
+ return -EBUSY;
+
+ if (!mdc800->open || mdc800->rw_lock)
+ return -EBUSY;
+ mdc800->rw_lock=1;
+
+ while (i<len)
+ {
+ if (signal_pending (current)) {
+ mdc800->rw_lock=0;
+ return -EINTR;
+ }
+
+ /* check for command start */
+ if (buf [i] == (char) 0x55)
+ {
+ mdc800->in_count=0;
+ mdc800->out_count=0;
+ mdc800->out_ptr=0;
+ mdc800->download_left=0;
+ }
+
+ /* save command byte */
+ if (mdc800->in_count < 8)
+ {
+ mdc800->in[mdc800->in_count]=buf[i];
+ mdc800->in_count++;
+ }
+ else
+ {
+ err ("Command is to long !\n");
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+
+ /* Command Buffer full ? -> send it to camera */
+ if (mdc800->in_count == 8)
+ {
+ int answersize;
+
+ mdc800_usb_waitForIRQ (0,TO_GET_READY);
+
+ answersize=mdc800_getAnswerSize (mdc800->in[1]);
+
+ mdc800->state=WORKING;
+ memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
+ if (usb_submit_urb (mdc800->write_urb))
+ {
+ err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+ mdc800->rw_lock=0;
+ mdc800->state=READY;
+ return -EIO;
+ }
+ interruptible_sleep_on_timeout (&mdc800->write_wait, TO_DEFAULT_COMMAND*HZ/1000);
+ if (mdc800->state == WORKING)
+ {
+ usb_unlink_urb (mdc800->write_urb);
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+
+ switch ((unsigned char) mdc800->in[1])
+ {
+ case 0x05: /* Download Image */
+ case 0x3e: /* Take shot in Fine Mode (WCam Mode) */
+ if (mdc800->pic_len < 0)
+ {
+ err ("call 0x07 before 0x05,0x3e");
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+ mdc800->pic_len=-1;
+
+ case 0x09: /* Download Thumbnail */
+ mdc800->download_left=answersize+64;
+ mdc800->state=DOWNLOAD;
+ mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY);
+ break;
+
+
+ default:
+ if (answersize)
+ {
+
+ if (!mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
+ {
+ err ("requesting answer from irq fails");
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+
+ /* Write dummy data, (this is ugly but part of the USB Protokoll */
+ /* if you use endpoint 1 as bulk and not as irq */
+ memcpy (mdc800->out, mdc800->camera_response,8);
+
+ /* This is the interpreted answer */
+ memcpy (&mdc800->out[8], mdc800->camera_response,8);
+
+ mdc800->out_ptr=0;
+ mdc800->out_count=16;
+
+ /* Cache the Imagesize, if command was getImageSize */
+ if (mdc800->in [1] == (char) 0x07)
+ {
+ mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
+
+ dbg ("cached imagesize = %i",mdc800->pic_len);
+ }
+
+ }
+ else
+ {
+ if (!mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
+ {
+ err ("Command Timeout.");
+ mdc800->rw_lock=0;
+ mdc800->state=READY;
+ return -EIO;
+ }
+ }
+ mdc800->state=READY;
+ break;
+ }
+ }
+ i++;
+ }
+ mdc800->rw_lock=0;
+ return i;
+}
+
+
+/***************************************************************************
+ Init and Cleanup this driver (Structs and types)
+****************************************************************************/
+
+
+/*
+ * USB Driver Struct for this device
+ */
+static struct usb_driver mdc800_usb_driver =
+{
+ "mdc800",
+ mdc800_usb_probe,
+ mdc800_usb_disconnect,
+ { 0,0 },
+ 0,
+ 0
+};
+
+
+/* File Operations of this drivers */
+static struct file_operations mdc800_device_ops =
+{
+ 0, /* llseek */
+ mdc800_device_read,
+ mdc800_device_write,
+ 0, /* readdir */
+ 0, /* poll */
+ 0, /* ioctl, this can be used to detect USB ! */
+ 0, /* mmap */
+ mdc800_device_open,
+ 0, /* flush */
+ mdc800_device_release,
+ 0, /* async */
+ 0, /* fasync */
+ 0, /* check_media_change */
+// 0, /* revalidate */
+// 0 /* lock */
+};
+
+
+/*
+ * The Misc Device Configuration Struct
+ */
+static struct miscdevice mdc800_device =
+{
+ MDC800_DEVICE_MINOR,
+ "USB Mustek MDC800 Camera",
+ &mdc800_device_ops
+};
+
+
+/************************************************************************
+ Init and Cleanup this driver (Main Functions)
+*************************************************************************/
+
+#define try(A) if ((A) == 0) goto cleanup_on_fail;
+#define try_free_mem(A) if (A != 0) { kfree (A); A=0; }
+#define try_free_urb(A) if (A != 0) { usb_free_urb (A); A=0; }
+
+int __init usb_mdc800_init (void)
+{
+ /* Allocate Memory */
+ try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
+
+ mdc800->dev=0;
+ mdc800->open=0;
+ mdc800->state=NOT_CONNECTED;
+ memset(mdc800, 0, sizeof(struct mdc800_data));
+
+ init_waitqueue_head (&mdc800->irq_wait);
+ init_waitqueue_head (&mdc800->write_wait);
+ init_waitqueue_head (&mdc800->download_wait);
+
+ try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
+ try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
+ try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL));
+
+ try (mdc800->irq_urb=usb_alloc_urb (0));
+ try (mdc800->download_urb=usb_alloc_urb (0));
+ try (mdc800->write_urb=usb_alloc_urb (0));
+
+ /* Register the driver */
+ if (usb_register (&mdc800_usb_driver) < 0)
+ goto cleanup_on_fail;
+ if (misc_register (&mdc800_device) < 0)
+ goto cleanup_on_misc_register_fail;
+
+ info ("Mustek Digital Camera Driver " VERSION " (MDC800)");
+ info (RELEASE_DATE " Henning Zabel <henning@uni-paderborn.de>");
+
+ return 0;
+
+ /* Clean driver up, when something fails */
+
+cleanup_on_misc_register_fail:
+ usb_deregister (&mdc800_usb_driver);
+
+cleanup_on_fail:
+
+ if (mdc800 != 0)
+ {
+ err ("can't alloc memory!");
+
+ try_free_mem (mdc800->download_urb_buffer);
+ try_free_mem (mdc800->write_urb_buffer);
+ try_free_mem (mdc800->irq_urb_buffer);
+
+ try_free_urb (mdc800->write_urb);
+ try_free_urb (mdc800->download_urb);
+ try_free_urb (mdc800->irq_urb);
+
+ kfree (mdc800);
+ }
+ mdc800=0;
+ return -1;
+}
+
+
+void __exit usb_mdc800_cleanup (void)
+{
+ usb_deregister (&mdc800_usb_driver);
+ misc_deregister (&mdc800_device);
+
+ usb_free_urb (mdc800->irq_urb);
+ usb_free_urb (mdc800->download_urb);
+ usb_free_urb (mdc800->write_urb);
+
+ kfree (mdc800->irq_urb_buffer);
+ kfree (mdc800->write_urb_buffer);
+ kfree (mdc800->download_urb_buffer);
+
+ kfree (mdc800);
+ mdc800=0;
+}
+
+
+MODULE_AUTHOR ("Henning Zabel <henning@uni-paderborn.de>");
+MODULE_DESCRIPTION ("USB Driver for Mustek MDC800 Digital Camera");
+
+module_init (usb_mdc800_init);
+module_exit (usb_mdc800_cleanup);
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index 607782829..bfdc4ab3d 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -95,8 +95,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
break;
case ABS_Y:
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
- list->dy += (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
- list->oldy += list->dy * size;
+ list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+ list->oldy -= list->dy * size;
break;
}
break;
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 2d5de6f73..764f1c055 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -16,12 +16,9 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.3.3 2000/03/13 Written by Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.3.5 2000/03/21 Written by Petko Manolov (petkan@spct.net)\n";
-#define ADMTEK_VENDOR_ID 0x07a6
-#define ADMTEK_DEVICE_ID_PEGASUS 0x0986
-
#define PEGASUS_MTU 1500
#define PEGASUS_MAX_MTU 1536
#define PEGASUS_TX_TIMEOUT (HZ*5)
@@ -38,6 +35,13 @@ struct pegasus {
unsigned char ALIGN(intr_buff[8]);
};
+struct usb_eth_dev {
+ char *name;
+ __u16 vendor;
+ __u16 device;
+ void *private;
+};
+
static int loopback = 0;
static int multicast_filter_limit = 32;
@@ -46,6 +50,16 @@ MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i");
+static struct usb_eth_dev usb_dev_id[] = {
+ { "D-Link DSB-650TX", 0x2001, 0x4001, NULL },
+ { "Linksys USB100TX", 0x066b, 0x2203, NULL },
+ { "SMC 202 USB Ethernet", 0x0707, 0x0200, NULL },
+ { "ADMtek AN986 (Pegasus) USB Ethernet", 0x07a6, 0x0986, NULL },
+ { "Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL },
+ { NULL, 0, 0, NULL }
+};
+
+
#define pegasus_get_registers(dev, indx, size, data)\
usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ);
#define pegasus_set_registers(dev, indx, size, data)\
@@ -164,8 +178,8 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
return 4;
if ((partmedia & 0x1f) != 1) {
- err("party FAIL %x", partmedia);
- return 5;
+ warn("party FAIL %x", partmedia);
+ /* return 5; FIXME */
}
data[0] = 0xc9;
@@ -374,13 +388,25 @@ static void pegasus_set_rx_mode(struct net_device *net)
netif_wake_queue(net);
}
+static int check_device_ids( __u16 vendor, __u16 product )
+{
+ int i=0;
+
+ while ( usb_dev_id[i].name ) {
+ if ( (usb_dev_id[i].vendor == vendor) &&
+ (usb_dev_id[i].device == product) )
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
{
struct net_device *net;
struct pegasus *pegasus;
- if (dev->descriptor.idVendor != ADMTEK_VENDOR_ID ||
- dev->descriptor.idProduct != ADMTEK_DEVICE_ID_PEGASUS) {
+ if ( check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct) ) {
return NULL;
}
diff --git a/drivers/usb/serial/Makefile-keyspan_pda_fw b/drivers/usb/serial/Makefile-keyspan_pda_fw
index 219708e46..c20baf728 100644
--- a/drivers/usb/serial/Makefile-keyspan_pda_fw
+++ b/drivers/usb/serial/Makefile-keyspan_pda_fw
@@ -5,7 +5,7 @@
all: keyspan_pda_fw.h
-%.asm: %.s
+%.asm: %.S
gcc -x assembler-with-cpp -P -E -o $@ $<
%.hex: %.asm
diff --git a/drivers/usb/serial/keyspan_pda.S b/drivers/usb/serial/keyspan_pda.S
new file mode 100644
index 000000000..10c99eadd
--- /dev/null
+++ b/drivers/usb/serial/keyspan_pda.S
@@ -0,0 +1,1124 @@
+/* $Id: loop.s,v 1.23 2000/03/20 09:49:06 warner Exp $
+ *
+ * Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on
+ * the EzUSB microcontroller.
+ *
+ * (C) Copyright 2000 Brian Warner <warner@lothar.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.
+ *
+ * "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the
+ * company.
+ *
+ * This serial adapter is basically an EzUSB chip and an RS-232 line driver
+ * in a little widget that has a DB-9 on one end and a USB plug on the other.
+ * It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2
+ * as a baud-rate generator. The wiring is:
+ * PC0/RxD0 <- rxd (DB9 pin 2) PC4 <- dsr pin 6
+ * PC1/TxD0 -> txd pin 3 PC5 <- ri pin 9
+ * PC2 -> rts pin 7 PC6 <- dcd pin 1
+ * PC3 <- cts pin 8 PC7 -> dtr pin 4
+ * PB1 -> line driver standby
+ *
+ * The EzUSB register constants below come from their excellent documentation
+ * and sample code (which used to be available at www.anchorchips.com, but
+ * that has now been absorbed into Cypress' site and the CD-ROM contents
+ * don't appear to be available online anymore). If we get multiple
+ * EzUSB-based drivers into the kernel, it might be useful to pull them out
+ * into a separate .h file.
+ *
+ * THEORY OF OPERATION:
+ *
+ * There are two 256-byte ring buffers, one for tx, one for rx.
+ *
+ * EP2out is pure tx data. When it appears, the data is copied into the tx
+ * ring and serial transmission is started if it wasn't already running. The
+ * "tx buffer empty" interrupt may kick off another character if the ring
+ * still has data. If the host is tx-blocked because the ring filled up,
+ * it will request a "tx unthrottle" interrupt. If sending a serial character
+ * empties the ring below the desired threshold, we set a bit that will send
+ * up the tx unthrottle message as soon as the rx buffer becomes free.
+ *
+ * EP2in (interrupt) is used to send both rx chars and rx status messages
+ * (only "tx unthrottle" at this time) back up to the host. The first byte
+ * of the rx message indicates data (0) or status msg (1). Status messages
+ * are sent before any data.
+ *
+ * Incoming serial characters are put into the rx ring by the serial
+ * interrupt, and the EP2in buffer sent if it wasn't already in transit.
+ * When the EP2in buffer returns, the interrupt prompts us to send more
+ * rx chars (or status messages) if they are pending.
+ *
+ * Device control happens through "vendor specific" control messages on EP0.
+ * All messages are destined for the "Interface" (with the index always 0,
+ * so that if their two-port device might someday use similar firmware, we
+ * can use index=1 to refer to the second port). The messages defined are:
+ *
+ * bRequest = 0 : set baud/bits/parity
+ * 1 : unused
+ * 2 : reserved for setting HW flow control (CTSRTS)
+ * 3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc)
+ * 4 : set break (on/off)
+ * 5 : reserved for requesting interrupts on pin state change
+ * 6 : query buffer room or chars in tx buffer
+ * 7 : request tx unthrottle interrupt
+ *
+ * The host-side driver is set to recognize the device ID values stashed in
+ * serial EEPROM (0x06cd, 0x0103), program this firmware into place, then
+ * start it running. This firmware will use EzUSB's "renumeration" trick by
+ * simulating a bus disconnect, then reconnect with a different device ID
+ * (encoded in the desc_device descriptor below). The host driver then
+ * recognizes the new device ID and glues it to the real serial driver code.
+ *
+ * USEFUL DOCS:
+ * EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ * 8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
+ * basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
+ * use totally different registers!
+ * USB 1.1 spec: www.usb.org
+ *
+ * HOW TO BUILD:
+ * gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s
+ * as31 -l keyspan_pda.asm
+ * mv keyspan_pda.obj keyspan_pda.hex
+ * perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h
+ * Get as31 from <http://www.pjrc.com/tech/8051/index.html>, and hack on it
+ * a bit to make it build.
+ *
+ * THANKS:
+ * Greg Kroah-Hartman, for coordinating the whole usb-serial thing.
+ * AnchorChips, for making such an incredibly useful little microcontroller.
+ * KeySpan, for making a handy, cheap ($40) widget that was so easy to take
+ * apart and trace with an ohmmeter.
+ *
+ * TODO:
+ * lots. grep for TODO. Interrupt safety needs stress-testing. Better flow
+ * control. Interrupting host upon change in DCD, etc, counting transitions.
+ * Need to find a safe device id to use (the one used by the Keyspan firmware
+ * under Windows would be ideal.. can anyone figure out what it is?). Parity.
+ * More baud rates. Oh, and the string-descriptor-length silicon bug
+ * workaround should be implemented, but I'm lazy, and the consequence is
+ * that the device name strings that show up in your kernel log will have
+ * lots of trailing binary garbage in them (appears as ????). Device strings
+ * should be made more accurate.
+ *
+ * Questions, bugs, patches to Brian.
+ *
+ * -Brian Warner <warner@lothar.com>
+ *
+ */
+
+#define HIGH(x) (((x) & 0xff00) / 256)
+#define LOW(x) ((x) & 0xff)
+
+#define dpl1 0x84
+#define dph1 0x85
+#define dps 0x86
+
+;;; our bit assignments
+#define TX_RUNNING 0
+#define DO_TX_UNTHROTTLE 1
+
+ ;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60
+#define STACK #0x60-1
+
+#define EXIF 0x91
+#define EIE 0xe8
+ .flag EUSB, EIE.0
+ .flag ES0, IE.4
+
+#define EP0CS #0x7fb4
+#define EP0STALLbit #0x01
+#define IN0BUF #0x7f00
+#define IN0BC #0x7fb5
+#define OUT0BUF #0x7ec0
+#define OUT0BC #0x7fc5
+#define IN2BUF #0x7e00
+#define IN2BC #0x7fb9
+#define IN2CS #0x7fb8
+#define OUT2BC #0x7fc9
+#define OUT2CS #0x7fc8
+#define OUT2BUF #0x7dc0
+#define IN4BUF #0x7d00
+#define IN4BC #0x7fbd
+#define IN4CS #0x7fbc
+#define OEB #0x7f9d
+#define OUTB #0x7f97
+#define OEC #0x7f9e
+#define OUTC #0x7f98
+#define PINSC #0x7f9b
+#define PORTCCFG #0x7f95
+#define IN07IRQ #0x7fa9
+#define OUT07IRQ #0x7faa
+#define IN07IEN #0x7fac
+#define OUT07IEN #0x7fad
+#define USBIRQ #0x7fab
+#define USBIEN #0x7fae
+#define USBBAV #0x7faf
+#define USBCS #0x7fd6
+#define SUDPTRH #0x7fd4
+#define SUDPTRL #0x7fd5
+#define SETUPDAT #0x7fe8
+
+ ;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91)
+
+ .org 0
+ ljmp start
+ ;; interrupt vectors
+ .org 23H
+ ljmp serial_int
+ .byte 0
+
+ .org 43H
+ ljmp USB_Jump_Table
+ .byte 0 ; filled in by the USB core
+
+;;; local variables. These are not initialized properly: do it by hand.
+ .org 30H
+rx_ring_in: .byte 0
+rx_ring_out: .byte 0
+tx_ring_in: .byte 0
+tx_ring_out: .byte 0
+tx_unthrottle_threshold: .byte 0
+
+ .org 0x100H ; wants to be on a page boundary
+USB_Jump_Table:
+ ljmp ISR_Sudav ; Setup Data Available
+ .byte 0
+ ljmp 0 ; Start of Frame
+ .byte 0
+ ljmp 0 ; Setup Data Loading
+ .byte 0
+ ljmp 0 ; Global Suspend
+ .byte 0
+ ljmp 0 ; USB Reset
+ .byte 0
+ ljmp 0 ; Reserved
+ .byte 0
+ ljmp 0 ; End Point 0 In
+ .byte 0
+ ljmp 0 ; End Point 0 Out
+ .byte 0
+ ljmp 0 ; End Point 1 In
+ .byte 0
+ ljmp 0 ; End Point 1 Out
+ .byte 0
+ ljmp ISR_Ep2in
+ .byte 0
+ ljmp ISR_Ep2out
+ .byte 0
+
+
+ .org 0x200
+
+start: mov SP,STACK-1 ; set stack
+ ;; clear local variables
+ clr a
+ mov tx_ring_in, a
+ mov tx_ring_out, a
+ mov rx_ring_in, a
+ mov rx_ring_out, a
+ mov tx_unthrottle_threshold, a
+ clr TX_RUNNING
+ clr DO_TX_UNTHROTTLE
+
+ ;; clear fifo with "fe"
+ mov r1, 0
+ mov a, #0xfe
+ mov dptr, #tx_ring
+clear_tx_ring_loop:
+ movx @dptr, a
+ inc dptr
+ djnz r1, clear_tx_ring_loop
+
+ mov a, #0xfd
+ mov dptr, #rx_ring
+clear_rx_ring_loop:
+ movx @dptr, a
+ inc dptr
+ djnz r1, clear_rx_ring_loop
+
+;;; turn on the RS-232 driver chip (bring the STANDBY pin low)
+ ;; set OEB.1
+ mov a, #02H
+ mov dptr,OEB
+ movx @dptr,a
+ ;; clear PB1
+ mov a, #00H
+ mov dptr,OUTB
+ movx @dptr,a
+ ;; set OEC.[127]
+ mov a, #0x86
+ mov dptr,OEC
+ movx @dptr,a
+ ;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port
+ mov dptr, PORTCCFG
+ mov a, #0x03
+ movx @dptr, a
+
+ ;; set up interrupts, autovectoring
+ mov dptr, USBBAV
+ movx a,@dptr
+ setb acc.0 ; AVEN bit to 0
+ movx @dptr, a
+
+ mov a,#0x01 ; enable SUDAV: setup data available (for ep0)
+ mov dptr, USBIRQ
+ movx @dptr, a ; clear SUDAVI
+ mov dptr, USBIEN
+ movx @dptr, a
+
+ mov dptr, IN07IEN
+ mov a,#0x04 ; enable IN2 int
+ movx @dptr, a
+
+ mov dptr, OUT07IEN
+ mov a,#0x04 ; enable OUT2 int
+ movx @dptr, a
+ mov dptr, OUT2BC
+ movx @dptr, a ; arm OUT2
+
+ mov a, #0x84 ; turn on RTS, DTR
+ mov dptr,OUTC
+ movx @dptr, a
+ ;; setup the serial port. 9600 8N1.
+ mov a,#01010011 ; mode 1, enable rx, clear int
+ mov SCON, a
+ ;; using timer2, in 16-bit baud-rate-generator mode
+ ;; (xtal 12MHz, internal fosc 24MHz)
+ ;; RCAP2H,RCAP2L = 65536 - fosc/(32*baud)
+ ;; 57600: 0xFFF2.F, say 0xFFF3
+ ;; 9600: 0xFFB1.E, say 0xFFB2
+ ;; 300: 0xF63C
+#define BAUD 9600
+#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate))
+#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate))
+#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate))
+
+ mov T2CON, #030h ; rclk=1,tclk=1,cp=0,tr2=0(enable later)
+ mov r3, #5
+ acall set_baud
+ setb TR2
+ mov SCON, #050h
+
+#if 0
+ mov r1, #0x40
+ mov a, #0x41
+send:
+ mov SBUF, a
+ inc a
+ anl a, #0x3F
+ orl a, #0x40
+; xrl a, #0x02
+wait1:
+ jnb TI, wait1
+ clr TI
+ djnz r1, send
+;done: sjmp done
+
+#endif
+
+ setb EUSB
+ setb EA
+ setb ES0
+ ;acall dump_stat
+
+ ;; hey, what say we RENUMERATE! (TRM p.62)
+ mov a, #0
+ mov dps, a
+ mov dptr, USBCS
+ mov a, #0x02 ; DISCON=0, DISCOE=0, RENUM=1
+ movx @dptr, a
+ ;; now presence pin is floating, simulating disconnect. wait 0.5s
+ mov r1, #46
+renum_wait1:
+ mov r2, #0
+renum_wait2:
+ mov r3, #0
+renum_wait3:
+ djnz r3, renum_wait3
+ djnz r2, renum_wait2
+ djnz r1, renum_wait1 ; wait about n*(256^2) 6MHz clocks
+ mov a, #0x06 ; DISCON=0, DISCOE=1, RENUM=1
+ movx @dptr, a
+ ;; we are back online. the host device will now re-query us
+
+
+main: sjmp main
+
+
+
+ISR_Sudav:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ mov a,EXIF
+ clr acc.4
+ mov EXIF,a ; clear INT2 first
+ mov dptr, USBIRQ ; clear USB int
+ mov a,#01h
+ movx @dptr,a
+
+ ;; get request type
+ mov dptr, SETUPDAT
+ movx a, @dptr
+ mov r1, a ; r1 = bmRequestType
+ inc dptr
+ movx a, @dptr
+ mov r2, a ; r2 = bRequest
+ inc dptr
+ movx a, @dptr
+ mov r3, a ; r3 = wValueL
+ inc dptr
+ movx a, @dptr
+ mov r4, a ; r4 = wValueH
+
+ ;; main switch on bmRequest.type: standard or vendor
+ mov a, r1
+ anl a, #0x60
+ cjne a, #0x00, setup_bmreq_type_not_standard
+ ;; standard request: now main switch is on bRequest
+ ljmp setup_bmreq_is_standard
+
+setup_bmreq_type_not_standard:
+ ;; a still has bmreq&0x60
+ cjne a, #0x40, setup_bmreq_type_not_vendor
+ ;; Anchor reserves bRequest 0xa0-0xaf, we use small ones
+ ;; switch on bRequest. bmRequest will always be 0x41 or 0xc1
+ cjne r2, #0x00, setup_ctrl_not_00
+ ;; 00 is set baud, wValue[0] has baud rate index
+ lcall set_baud ; index in r3, carry set if error
+ jc setup_bmreq_type_not_standard__do_stall
+ ljmp setup_done_ack
+setup_bmreq_type_not_standard__do_stall:
+ ljmp setup_stall
+setup_ctrl_not_00:
+ cjne r2, #0x01, setup_ctrl_not_01
+ ;; 01 is reserved for set bits (parity). TODO
+ ljmp setup_stall
+setup_ctrl_not_01:
+ cjne r2, #0x02, setup_ctrl_not_02
+ ;; 02 is set HW flow control. TODO
+ ljmp setup_stall
+setup_ctrl_not_02:
+ cjne r2, #0x03, setup_ctrl_not_03
+ ;; 03 is control pins (RTS, DTR).
+ ljmp control_pins ; will jump to setup_done_ack,
+ ; or setup_return_one_byte
+setup_ctrl_not_03:
+ cjne r2, #0x04, setup_ctrl_not_04
+ ;; 04 is send break (really "turn break on/off"). TODO
+ cjne r3, #0x00, setup_ctrl_do_break_on
+ ;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port
+ mov dptr, PORTCCFG
+ movx a, @dptr
+ orl a, #0x02
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_ctrl_do_break_on:
+ ;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low)
+ mov dptr, OUTC
+ movx a, @dptr
+ anl a, #0xfd ; ~0x02
+ movx @dptr, a
+ mov dptr, PORTCCFG
+ movx a, @dptr
+ anl a, #0xfd ; ~0x02
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_ctrl_not_04:
+ cjne r2, #0x05, setup_ctrl_not_05
+ ;; 05 is set desired interrupt bitmap. TODO
+ ljmp setup_stall
+setup_ctrl_not_05:
+ cjne r2, #0x06, setup_ctrl_not_06
+ ;; 06 is query room
+ cjne r3, #0x00, setup_ctrl_06_not_00
+ ;; 06, wValue[0]=0 is query write_room
+ mov a, tx_ring_out
+ setb c
+ subb a, tx_ring_in ; out-1-in = 255 - (in-out)
+ ljmp setup_return_one_byte
+setup_ctrl_06_not_00:
+ cjne r3, #0x01, setup_ctrl_06_not_01
+ ;; 06, wValue[0]=1 is query chars_in_buffer
+ mov a, tx_ring_in
+ clr c
+ subb a, tx_ring_out ; in-out
+ ljmp setup_return_one_byte
+setup_ctrl_06_not_01:
+ ljmp setup_stall
+setup_ctrl_not_06:
+ cjne r2, #0x07, setup_ctrl_not_07
+ ;; 07 is request tx unthrottle interrupt
+ mov tx_unthrottle_threshold, r3; wValue[0] is threshold value
+ ljmp setup_done_ack
+setup_ctrl_not_07:
+ ljmp setup_stall
+
+setup_bmreq_type_not_vendor:
+ ljmp setup_stall
+
+
+setup_bmreq_is_standard:
+ cjne r2, #0x00, setup_breq_not_00
+ ;; 00: Get_Status (sub-switch on bmRequestType: device, ep, int)
+ cjne r1, #0x80, setup_Get_Status_not_device
+ ;; Get_Status(device)
+ ;; are we self-powered? no. can we do remote wakeup? no
+ ;; so return two zero bytes. This is reusable
+setup_return_two_zero_bytes:
+ mov dptr, IN0BUF
+ clr a
+ movx @dptr, a
+ inc dptr
+ movx @dptr, a
+ mov dptr, IN0BC
+ mov a, #2
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_Get_Status_not_device:
+ cjne r1, #0x82, setup_Get_Status_not_endpoint
+ ;; Get_Status(endpoint)
+ ;; must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0
+ ;; for now: cheat. TODO
+ sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_endpoint:
+ cjne r1, #0x81, setup_Get_Status_not_interface
+ ;; Get_Status(interface): return two zeros
+ sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_interface:
+ ljmp setup_stall
+
+setup_breq_not_00:
+ cjne r2, #0x01, setup_breq_not_01
+ ;; 01: Clear_Feature (sub-switch on wValueL: stall, remote wakeup)
+ cjne r3, #0x00, setup_Clear_Feature_not_stall
+ ;; Clear_Feature(stall). should clear a stall bit. TODO
+ ljmp setup_stall
+setup_Clear_Feature_not_stall:
+ cjne r3, #0x01, setup_Clear_Feature_not_rwake
+ ;; Clear_Feature(remote wakeup). ignored.
+ ljmp setup_done_ack
+setup_Clear_Feature_not_rwake:
+ ljmp setup_stall
+
+setup_breq_not_01:
+ cjne r2, #0x03, setup_breq_not_03
+ ;; 03: Set_Feature (sub-switch on wValueL: stall, remote wakeup)
+ cjne r3, #0x00, setup_Set_Feature_not_stall
+ ;; Set_Feature(stall). Should set a stall bit. TODO
+ ljmp setup_stall
+setup_Set_Feature_not_stall:
+ cjne r3, #0x01, setup_Set_Feature_not_rwake
+ ;; Set_Feature(remote wakeup). ignored.
+ ljmp setup_done_ack
+setup_Set_Feature_not_rwake:
+ ljmp setup_stall
+
+setup_breq_not_03:
+ cjne r2, #0x06, setup_breq_not_06
+ ;; 06: Get_Descriptor (s-switch on wValueH: dev, config[n], string[n])
+ cjne r4, #0x01, setup_Get_Descriptor_not_device
+ ;; Get_Descriptor(device)
+ mov dptr, SUDPTRH
+ mov a, #HIGH(desc_device)
+ movx @dptr, a
+ mov dptr, SUDPTRL
+ mov a, #LOW(desc_device)
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_Get_Descriptor_not_device:
+ cjne r4, #0x02, setup_Get_Descriptor_not_config
+ ;; Get_Descriptor(config[n])
+ cjne r3, #0x00, setup_stall; only handle n==0
+ ;; Get_Descriptor(config[0])
+ mov dptr, SUDPTRH
+ mov a, #HIGH(desc_config1)
+ movx @dptr, a
+ mov dptr, SUDPTRL
+ mov a, #LOW(desc_config1)
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_Get_Descriptor_not_config:
+ cjne r4, #0x03, setup_Get_Descriptor_not_string
+ ;; Get_Descriptor(string[wValueL])
+ ;; if (wValueL >= maxstrings) stall
+ mov a, #((desc_strings_end-desc_strings)/2)
+ clr c
+ subb a,r3 ; a=4, r3 = 0..3 . if a<=0 then stall
+ jc setup_stall
+ jz setup_stall
+ mov a, r3
+ add a, r3 ; a = 2*wValueL
+ mov dptr, #desc_strings
+ add a, dpl
+ mov dpl, a
+ mov a, #0
+ addc a, dph
+ mov dph, a ; dph = desc_strings[a]. big endian! (handy)
+ ;; it looks like my adapter uses a revision of the EZUSB that
+ ;; contains "rev D errata number 8", as hinted in the EzUSB example
+ ;; code. I cannot find an actual errata description on the Cypress
+ ;; web site, but from the example code it looks like this bug causes
+ ;; the length of string descriptors to be read incorrectly, possibly
+ ;; sending back more characters than the descriptor has. The workaround
+ ;; is to manually send out all of the data. The consequence of not
+ ;; using the workaround is that the strings gathered by the kernel
+ ;; driver are too long and are filled with trailing garbage (including
+ ;; leftover strings). Writing this out by hand is a nuisance, so for
+ ;; now I will just live with the bug.
+ movx a, @dptr
+ mov r1, a
+ inc dptr
+ movx a, @dptr
+ mov r2, a
+ mov dptr, SUDPTRH
+ mov a, r1
+ movx @dptr, a
+ mov dptr, SUDPTRL
+ mov a, r2
+ movx @dptr, a
+ ;; done
+ ljmp setup_done_ack
+
+setup_Get_Descriptor_not_string:
+ ljmp setup_stall
+
+setup_breq_not_06:
+ cjne r2, #0x08, setup_breq_not_08
+ ;; Get_Configuration. always 1. return one byte.
+ ;; this is reusable
+ mov a, #1
+setup_return_one_byte:
+ mov dptr, IN0BUF
+ movx @dptr, a
+ mov a, #1
+ mov dptr, IN0BC
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_breq_not_08:
+ cjne r2, #0x09, setup_breq_not_09
+ ;; 09: Set_Configuration. ignored.
+ ljmp setup_done_ack
+setup_breq_not_09:
+ cjne r2, #0x0a, setup_breq_not_0a
+ ;; 0a: Get_Interface. get the current altsetting for int[wIndexL]
+ ;; since we only have one interface, ignore wIndexL, return a 0
+ mov a, #0
+ ljmp setup_return_one_byte
+setup_breq_not_0a:
+ cjne r2, #0x0b, setup_breq_not_0b
+ ;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored
+ ljmp setup_done_ack
+setup_breq_not_0b:
+ ljmp setup_stall
+
+
+setup_done_ack:
+ ;; now clear HSNAK
+ mov dptr, EP0CS
+ mov a, #0x02
+ movx @dptr, a
+ sjmp setup_done
+setup_stall:
+ ;; unhandled. STALL
+ ;EP0CS |= bmEPSTALL
+ mov dptr, EP0CS
+ movx a, @dptr
+ orl a, EP0STALLbit
+ movx @dptr, a
+ sjmp setup_done
+
+setup_done:
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+;;; ==============================================================
+
+set_baud: ; baud index in r3
+ ;; verify a < 10
+ mov a, r3
+ jb ACC.7, set_baud__badbaud
+ clr c
+ subb a, #10
+ jnc set_baud__badbaud
+ mov a, r3
+ rl a ; a = index*2
+ add a, #LOW(baud_table)
+ mov dpl, a
+ mov a, #HIGH(baud_table)
+ addc a, #0
+ mov dph, a
+ ;; TODO: shut down xmit/receive
+ ;; TODO: wait for current xmit char to leave
+ ;; TODO: shut down timer to avoid partial-char glitch
+ movx a,@dptr ; BAUD_HIGH
+ mov RCAP2H, a
+ mov TH2, a
+ inc dptr
+ movx a,@dptr ; BAUD_LOW
+ mov RCAP2L, a
+ mov TL2, a
+ ;; TODO: restart xmit/receive
+ ;; TODO: reenable interrupts, resume tx if pending
+ clr c ; c=0: success
+ ret
+set_baud__badbaud:
+ setb c ; c=1: failure
+ ret
+
+;;; ==================================================
+control_pins:
+ cjne r1, #0x41, control_pins_in
+control_pins_out:
+ mov a, r3 ; wValue[0] holds new bits: b7 is new DTR, b2 is new RTS
+ xrl a, #0xff ; 1 means active, 0V, +12V ?
+ anl a, #0x84
+ mov r3, a
+ mov dptr, OUTC
+ movx a, @dptr ; only change bits 7 and 2
+ anl a, #0x7b ; ~0x84
+ orl a, r3
+ movx @dptr, a ; other pins are inputs, bits ignored
+ ljmp setup_done_ack
+control_pins_in:
+ mov dptr, PINSC
+ movx a, @dptr
+ xrl a, #0xff
+ ljmp setup_return_one_byte
+
+;;; ========================================
+
+ISR_Ep2in:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ mov a,EXIF
+ clr acc.4
+ mov EXIF,a ; clear INT2 first
+ mov dptr, IN07IRQ ; clear USB int
+ mov a,#04h
+ movx @dptr,a
+
+ ;; do stuff
+ lcall start_in
+
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+ISR_Ep2out:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ mov a,EXIF
+ clr acc.4
+ mov EXIF,a ; clear INT2 first
+ mov dptr, OUT07IRQ ; clear USB int
+ mov a,#04h
+ movx @dptr,a
+
+ ;; do stuff
+
+ ;; copy data into buffer. for now, assume we will have enough space
+ mov dptr, OUT2BC ; get byte count
+ movx a,@dptr
+ mov r1, a
+ clr a
+ mov dps, a
+ mov dptr, OUT2BUF ; load DPTR0 with source
+ mov dph1, #HIGH(tx_ring) ; load DPTR1 with target
+ mov dpl1, tx_ring_in
+OUT_loop:
+ movx a,@dptr ; read
+ inc dps ; switch to DPTR1: target
+ inc dpl1 ; target = tx_ring_in+1
+ movx @dptr,a ; store
+ mov a,dpl1
+ cjne a, tx_ring_out, OUT_no_overflow
+ sjmp OUT_overflow
+OUT_no_overflow:
+ inc tx_ring_in ; tx_ring_in++
+ inc dps ; switch to DPTR0: source
+ inc dptr
+ djnz r1, OUT_loop
+ sjmp OUT_done
+OUT_overflow:
+ ;; signal overflow
+ ;; fall through
+OUT_done:
+ ;; ack
+ mov dptr,OUT2BC
+ movx @dptr,a
+
+ ;; start tx
+ acall maybe_start_tx
+ ;acall dump_stat
+
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+dump_stat:
+ ;; fill in EP4in with a debugging message:
+ ;; tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out
+ ;; tx_active
+ ;; tx_ring[0..15]
+ ;; 0xfc
+ ;; rx_ring[0..15]
+ clr a
+ mov dps, a
+
+ mov dptr, IN4CS
+ movx a, @dptr
+ jb acc.1, dump_stat__done; busy: cannot dump, old one still pending
+ mov dptr, IN4BUF
+
+ mov a, tx_ring_in
+ movx @dptr, a
+ inc dptr
+ mov a, tx_ring_out
+ movx @dptr, a
+ inc dptr
+
+ mov a, rx_ring_in
+ movx @dptr, a
+ inc dptr
+ mov a, rx_ring_out
+ movx @dptr, a
+ inc dptr
+
+ clr a
+ jnb TX_RUNNING, dump_stat__no_tx_running
+ inc a
+dump_stat__no_tx_running:
+ movx @dptr, a
+ inc dptr
+ ;; tx_ring[0..15]
+ inc dps
+ mov dptr, #tx_ring ; DPTR1: source
+ mov r1, #16
+dump_stat__tx_ring_loop:
+ movx a, @dptr
+ inc dptr
+ inc dps
+ movx @dptr, a
+ inc dptr
+ inc dps
+ djnz r1, dump_stat__tx_ring_loop
+ inc dps
+
+ mov a, #0xfc
+ movx @dptr, a
+ inc dptr
+
+ ;; rx_ring[0..15]
+ inc dps
+ mov dptr, #rx_ring ; DPTR1: source
+ mov r1, #16
+dump_stat__rx_ring_loop:
+ movx a, @dptr
+ inc dptr
+ inc dps
+ movx @dptr, a
+ inc dptr
+ inc dps
+ djnz r1, dump_stat__rx_ring_loop
+
+ ;; now send it
+ clr a
+ mov dps, a
+ mov dptr, IN4BC
+ mov a, #38
+ movx @dptr, a
+dump_stat__done:
+ ret
+
+;;; ============================================================
+
+maybe_start_tx:
+ ;; make sure the tx process is running.
+ jb TX_RUNNING, start_tx_done
+start_tx:
+ ;; is there work to be done?
+ mov a, tx_ring_in
+ cjne a,tx_ring_out, start_tx__work
+ ret ; no work
+start_tx__work:
+ ;; tx was not running. send the first character, setup the TI int
+ inc tx_ring_out ; [++tx_ring_out]
+ mov dph, #HIGH(tx_ring)
+ mov dpl, tx_ring_out
+ movx a, @dptr
+ mov sbuf, a
+ setb TX_RUNNING
+start_tx_done:
+ ;; can we unthrottle the host tx process?
+ ;; step 1: do we care?
+ mov a, #0
+ cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx
+ ;; nope
+start_tx_really_done:
+ ret
+start_tx__maybe_unthrottle_tx:
+ ;; step 2: is there now room?
+ mov a, tx_ring_out
+ setb c
+ subb a, tx_ring_in
+ ;; a is now write_room. If thresh >= a, we can unthrottle
+ clr c
+ subb a, tx_unthrottle_threshold
+ jc start_tx_really_done ; nope
+ ;; yes, we can unthrottle. remove the threshold and mark a request
+ mov tx_unthrottle_threshold, #0
+ setb DO_TX_UNTHROTTLE
+ ;; prod rx, which will actually send the message when in2 becomes free
+ ljmp start_in
+
+
+serial_int:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ jnb TI, serial_int__not_tx
+ ;; tx finished. send another character if we have one
+ clr TI ; clear int
+ clr TX_RUNNING
+ lcall start_tx
+serial_int__not_tx:
+ jnb RI, serial_int__not_rx
+ lcall get_rx_char
+ clr RI ; clear int
+serial_int__not_rx:
+ ;; return
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+get_rx_char:
+ mov dph, #HIGH(rx_ring)
+ mov dpl, rx_ring_in
+ inc dpl ; target = rx_ring_in+1
+ mov a, sbuf
+ movx @dptr, a
+ ;; check for overflow before incrementing rx_ring_in
+ mov a, dpl
+ cjne a, rx_ring_out, get_rx_char__no_overflow
+ ;; signal overflow
+ ret
+get_rx_char__no_overflow:
+ inc rx_ring_in
+ ;; kick off USB INpipe
+ acall start_in
+ ret
+
+start_in:
+ ;; check if the inpipe is already running.
+ mov dptr, IN2CS
+ movx a, @dptr
+ jb acc.1, start_in__done; int will handle it
+ jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle
+ ;; see if there is any work to do. a serial interrupt might occur
+ ;; during this sequence?
+ mov a, rx_ring_in
+ cjne a, rx_ring_out, start_in__have_work
+ ret ; nope
+start_in__have_work:
+ ;; now copy as much data as possible into the pipe. 63 bytes max.
+ clr a
+ mov dps, a
+ mov dph, #HIGH(rx_ring) ; load DPTR0 with source
+ inc dps
+ mov dptr, IN2BUF ; load DPTR1 with target
+ movx @dptr, a ; in[0] signals that rest of IN is rx data
+ inc dptr
+ inc dps
+ ;; loop until we run out of data, or we have copied 64 bytes
+ mov r1, #1 ; INbuf size counter
+start_in__loop:
+ mov a, rx_ring_in
+ cjne a, rx_ring_out, start_in__still_copying
+ sjmp start_in__kick
+start_in__still_copying:
+ inc rx_ring_out
+ mov dpl, rx_ring_out
+ movx a, @dptr
+ inc dps
+ movx @dptr, a ; write into IN buffer
+ inc dptr
+ inc dps
+ inc r1
+ cjne r1, #64, start_in__loop; loop
+start_in__kick:
+ ;; either we ran out of data, or we copied 64 bytes. r1 has byte count
+ ;; kick off IN
+ mov dptr, IN2BC
+ mov a, r1
+ jz start_in__done
+ movx @dptr, a
+ ;; done
+start_in__done:
+ ;acall dump_stat
+ ret
+start_in__do_tx_unthrottle:
+ ;; special sequence: send a tx unthrottle message
+ clr DO_TX_UNTHROTTLE
+ clr a
+ mov dps, a
+ mov dptr, IN2BUF
+ mov a, #1
+ movx @dptr, a
+ inc dptr
+ mov a, #2
+ movx @dptr, a
+ mov dptr, IN2BC
+ movx @dptr, a
+ ret
+
+putchar:
+ clr TI
+ mov SBUF, a
+putchar_wait:
+ jnb TI, putchar_wait
+ clr TI
+ ret
+
+
+baud_table: ; baud_high, then baud_low
+ ;; baud[0]: 110
+ .byte BAUD_HIGH(110)
+ .byte BAUD_LOW(110)
+ ;; baud[1]: 300
+ .byte BAUD_HIGH(300)
+ .byte BAUD_LOW(300)
+ ;; baud[2]: 1200
+ .byte BAUD_HIGH(1200)
+ .byte BAUD_LOW(1200)
+ ;; baud[3]: 2400
+ .byte BAUD_HIGH(2400)
+ .byte BAUD_LOW(2400)
+ ;; baud[4]: 4800
+ .byte BAUD_HIGH(4800)
+ .byte BAUD_LOW(4800)
+ ;; baud[5]: 9600
+ .byte BAUD_HIGH(9600)
+ .byte BAUD_LOW(9600)
+ ;; baud[6]: 19200
+ .byte BAUD_HIGH(19200)
+ .byte BAUD_LOW(19200)
+ ;; baud[7]: 38400
+ .byte BAUD_HIGH(38400)
+ .byte BAUD_LOW(38400)
+ ;; baud[8]: 57600
+ .byte BAUD_HIGH(57600)
+ .byte BAUD_LOW(57600)
+ ;; baud[9]: 115200
+ .byte BAUD_HIGH(115200)
+ .byte BAUD_LOW(115200)
+
+desc_device:
+ .byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40
+ .byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01
+;;; The "real" device id, which must match the host driver, is that
+;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104
+
+desc_config1:
+ .byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32
+ .byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00
+ .byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01
+ .byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
+
+desc_strings:
+ .word string_langids, string_mfg, string_product, string_serial
+desc_strings_end:
+
+string_langids: .byte string_langids_end-string_langids
+ .byte 3
+ .word 0
+string_langids_end:
+
+ ;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now
+ ;; *that* is a pain in the ass to encode. And they are little-endian
+ ;; too. Use this perl snippet to get the bytecodes:
+ /* while (<>) {
+ @c = split(//);
+ foreach $c (@c) {
+ printf("0x%02x, 0x00, ", ord($c));
+ }
+ }
+ */
+
+string_mfg: .byte string_mfg_end-string_mfg
+ .byte 3
+; .byte "ACME usb widgets"
+ .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00
+string_mfg_end:
+
+string_product: .byte string_product_end-string_product
+ .byte 3
+; .byte "ACME USB serial widget"
+ .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00
+string_product_end:
+
+string_serial: .byte string_serial_end-string_serial
+ .byte 3
+; .byte "47"
+ .byte 0x34, 0x00, 0x37, 0x00
+string_serial_end:
+
+;;; ring buffer memory
+ ;; tx_ring_in+1 is where the next input byte will go
+ ;; [tx_ring_out] has been sent
+ ;; if tx_ring_in == tx_ring_out, theres no work to do
+ ;; there are (tx_ring_in - tx_ring_out) chars to be written
+ ;; dont let _in lap _out
+ ;; cannot inc if tx_ring_in+1 == tx_ring_out
+ ;; write [tx_ring_in+1] then tx_ring_in++
+ ;; if (tx_ring_in+1 == tx_ring_out), overflow
+ ;; else tx_ring_in++
+ ;; read/send [tx_ring_out+1], then tx_ring_out++
+
+ ;; rx_ring_in works the same way
+
+ .org 0x1000
+tx_ring:
+ .skip 0x100 ; 256 bytes
+rx_ring:
+ .skip 0x100 ; 256 bytes
+
+
+ .END
+
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 6effcc048..021754994 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -14,6 +14,16 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (03/19/2000) gkh
+ * Fixed oops that could happen when device was removed while a program
+ * was talking to the device.
+ * Removed the static urbs and now all urbs are created and destroyed
+ * dynamically.
+ * Reworked the internal interface. Now everything is based on the
+ * usb_serial_port structure instead of the larger usb_serial structure.
+ * This fixes the bug that a multiport device could not have more than
+ * one port open at one time.
+ *
* (03/17/2000) gkh
* Added config option for debugging messages.
* Added patch for keyspan pda from Brian Warner.
@@ -220,10 +230,9 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
static struct usb_driver usb_serial_driver = {
- "serial",
- usb_serial_probe,
- usb_serial_disconnect,
- { NULL, NULL }
+ name: "serial",
+ probe: usb_serial_probe,
+ disconnect: usb_serial_disconnect,
};
static int serial_refcount;
@@ -233,11 +242,50 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
+static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
+{
+ if (!serial) {
+ dbg("%s - serial == NULL", function);
+ return -1;
+ }
+ if (serial->magic != USB_SERIAL_MAGIC) {
+ dbg("%s - bad magic number for serial", function);
+ return -1;
+ }
+ if (!serial->type) {
+ dbg("%s - serial->type == NULL!", function);
+ return -1;
+ }
+
+ return 0;
+}
-static struct usb_serial *get_serial_by_minor (int minor)
+
+static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
{
- dbg("get_serial_by_minor %d", minor);
+ if (!port) {
+ dbg("%s - port == NULL", function);
+ return -1;
+ }
+ if (port->magic != USB_SERIAL_PORT_MAGIC) {
+ dbg("%s - bad magic number for port", function);
+ return -1;
+ }
+ if (!port->serial) {
+ dbg("%s - port->serial == NULL", function);
+ return -1;
+ }
+ if (!port->tty) {
+ dbg("%s - port->tty == NULL", function);
+ return -1;
+ }
+ return 0;
+}
+
+
+static struct usb_serial *get_serial_by_minor (int minor)
+{
return serial_table[minor];
}
@@ -267,6 +315,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
return NULL;
}
memset(serial, 0, sizeof(struct usb_serial));
+ serial->magic = USB_SERIAL_MAGIC;
serial_table[i] = serial;
*minor = i;
dbg("minor base = %d", *minor);
@@ -337,6 +386,8 @@ static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
static int serial_open (struct tty_struct *tty, struct file * filp)
{
struct usb_serial *serial;
+ struct usb_serial_port *port;
+ int portNumber;
dbg("serial_open");
@@ -346,180 +397,182 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
/* get the serial object associated with this tty pointer */
serial = get_serial_by_minor (MINOR(tty->device));
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
- }
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+ if (serial_paranoia_check (serial, "serial_open")) {
+ return -ENODEV;
}
- /* make the tty driver remember our serial object, and us it */
- tty->driver_data = serial;
- serial->tty = tty;
+ /* set up our port structure */
+ portNumber = MINOR(tty->device) - serial->minor;
+ port = &serial->port[portNumber];
+ port->number = portNumber;
+ port->serial = serial;
+ port->magic = USB_SERIAL_PORT_MAGIC;
+
+ /* make the tty driver remember our port object, and us it */
+ tty->driver_data = port;
+ port->tty = tty;
/* pass on to the driver specific version of this function if it is available */
if (serial->type->open) {
- return (serial->type->open(tty, filp));
+ return (serial->type->open(port, filp));
} else {
- return (generic_serial_open(tty, filp));
+ return (generic_open(port, filp));
}
}
static void serial_close(struct tty_struct *tty, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
dbg("serial_close");
- if (!serial) {
- dbg("serial == NULL!");
+ if (port_paranoia_check (port, "serial_close")) {
return;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_close port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_close")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not opened");
+
+ dbg("serial_close port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not opened");
return;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->close) {
- serial->type->close(tty, filp);
+ serial->type->close(port, filp);
} else {
- generic_serial_close(tty, filp);
+ generic_close(port, filp);
}
}
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- dbg("serial_write port %d, %d byte(s)", port, count);
-
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
+ dbg("serial_write");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not opened");
- return (-EINVAL);
+
+ dbg("serial_write port %d, %d byte(s)", port->number, count);
+
+ if (!port->active) {
+ dbg ("port not opened");
+ return -EINVAL;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->write) {
- return (serial->type->write(tty, from_user, buf, count));
+ return (serial->type->write(port, from_user, buf, count));
} else {
- return (generic_serial_write(tty, from_user, buf, count));
+ return (generic_write(port, from_user, buf, count));
}
}
static int serial_write_room (struct tty_struct *tty)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_write_room port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
+ dbg("serial_write_room");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
- return (-EINVAL);
+
+ dbg("serial_write_room port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return -EINVAL;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->write_room) {
- return (serial->type->write_room(tty));
+ return (serial->type->write_room(port));
} else {
- return (generic_write_room(tty));
+ return (generic_write_room(port));
}
}
static int serial_chars_in_buffer (struct tty_struct *tty)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_chars_in_buffer port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
+ dbg("serial_chars_in_buffer");
+
+ if (port_paranoia_check (port, "serial_chars_in_buffer")) {
+ return -ENODEV;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+ return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
- return (-EINVAL);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return -EINVAL;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->chars_in_buffer) {
- return (serial->type->chars_in_buffer(tty));
+ return (serial->type->chars_in_buffer(port));
} else {
- return (generic_chars_in_buffer(tty));
+ return (generic_chars_in_buffer(port));
}
}
static void serial_throttle (struct tty_struct * tty)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_throttle port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
+ dbg("serial_throttle");
+
+ if (port_paranoia_check (port, "serial_throttle")) {
return;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_throttle")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_throttle port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function */
if (serial->type->throttle) {
- serial->type->throttle(tty);
- } else {
- generic_throttle(tty);
+ serial->type->throttle(port);
}
return;
@@ -528,30 +581,30 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_unthrottle port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
+ dbg("serial_unthrottle");
+
+ if (port_paranoia_check (port, "serial_unthrottle")) {
return;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_unthrottle")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_unthrottle port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function */
if (serial->type->unthrottle) {
- serial->type->unthrottle(tty);
- } else {
- generic_unthrottle(tty);
+ serial->type->unthrottle(port);
}
return;
@@ -560,70 +613,62 @@ static void serial_unthrottle (struct tty_struct * tty)
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
-
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
dbg("serial_ioctl");
-
- if (!serial) {
- dbg("serial == NULL!");
+
+ if (port_paranoia_check (port, "serial_ioctl")) {
return -ENODEV;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_ioctl port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_ioctl")) {
return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_ioctl port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return -ENODEV;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->ioctl) {
- return (serial->type->ioctl(tty, file, cmd, arg));
+ return (serial->type->ioctl(port, file, cmd, arg));
} else {
- return (generic_ioctl (tty, file, cmd, arg));
+ return -ENOIOCTLCMD;
}
}
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
-
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
dbg("serial_set_termios");
-
- if (!serial) {
- dbg("serial == NULL!");
+
+ if (port_paranoia_check (port, "serial_set_termios")) {
return;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_set_termios port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_set_termios")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_set_termios port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->set_termios) {
- serial->type->set_termios(tty, old);
- } else {
- generic_set_termios (tty, old);
+ serial->type->set_termios(port, old);
}
return;
@@ -632,32 +677,31 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
static void serial_break (struct tty_struct *tty, int break_state)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
-
- if (!serial) {
- dbg("serial == NULL!");
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_break");
+
+ if (port_paranoia_check (port, "serial_break")) {
return;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_break port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_break")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_break port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function if it is
available */
if (serial->type->break_ctl) {
- serial->type->break_ctl(tty, break_state);
+ serial->type->break_ctl(port, break_state);
}
}
@@ -666,13 +710,9 @@ static void serial_break (struct tty_struct *tty, int break_state)
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
*****************************************************************************/
-static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
-
- dbg("whiteheat_serial_open port %d", portNumber);
+ dbg("whiteheat_open port %d", port->number);
if (port->active) {
dbg ("device already open");
@@ -681,7 +721,7 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
port->active = 1;
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
/* Need to do device specific setup here (control lines, baud rate, etc.) */
@@ -691,36 +731,30 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
}
-static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp)
+static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
-
- dbg("whiteheat_serial_close port %d", portNumber);
+ dbg("whiteheat_close port %d", port->number);
/* Need to change the control lines here */
/* FIXME */
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
-static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_termios)
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = port->tty->termios->c_cflag;
- dbg("whiteheat_set_termios port %d", port);
+ dbg("whiteheat_set_termios port %d", port->number);
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("nothing to change...");
return;
}
@@ -732,12 +766,9 @@ static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_t
return;
}
-static void whiteheat_throttle (struct tty_struct * tty)
+static void whiteheat_throttle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("whiteheat_throttle port %d", port);
+ dbg("whiteheat_throttle port %d", port->number);
/* Change the control signals */
/* FIXME!!! */
@@ -746,12 +777,9 @@ static void whiteheat_throttle (struct tty_struct * tty)
}
-static void whiteheat_unthrottle (struct tty_struct * tty)
+static void whiteheat_unthrottle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("whiteheat_unthrottle port %d", port);
+ dbg("whiteheat_unthrottle port %d", port->number);
/* Change the control signals */
/* FIXME!!! */
@@ -837,13 +865,9 @@ static int whiteheat_startup (struct usb_serial *serial)
/******************************************************************************
* Handspring Visor specific driver functions
******************************************************************************/
-static int visor_serial_open (struct tty_struct *tty, struct file *filp)
+static int visor_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
-
- dbg("visor_serial_open port %d", portNumber);
+ dbg("visor_open port %d", port->number);
if (port->active) {
dbg ("device already open");
@@ -853,23 +877,22 @@ static int visor_serial_open (struct tty_struct *tty, struct file *filp)
port->active = 1;
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
return (0);
}
-static void visor_serial_close(struct tty_struct *tty, struct file * filp)
+
+static void visor_close (struct usb_serial_port *port, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
- dbg("visor_serial_close port %d", portNumber);
+ dbg("visor_close port %d", port->number);
if (!transfer_buffer) {
- err("visor_serial_close: kmalloc(%d) failed.", 0x12);
+ err("visor_close: kmalloc(%d) failed.", 0x12);
} else {
/* send a shutdown message to the device */
usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
@@ -877,33 +900,27 @@ static void visor_serial_close(struct tty_struct *tty, struct file * filp)
}
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
-static void visor_throttle (struct tty_struct * tty)
+static void visor_throttle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("visor_throttle port %d", port);
+ dbg("visor_throttle port %d", port->number);
- usb_unlink_urb (&serial->port[port].read_urb);
+ usb_unlink_urb (port->read_urb);
return;
}
-static void visor_unthrottle (struct tty_struct * tty)
+static void visor_unthrottle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ dbg("visor_unthrottle port %d", port->number);
- dbg("visor_unthrottle port %d", port);
-
- if (usb_unlink_urb (&serial->port[port].read_urb))
+ if (usb_unlink_urb (port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
return;
@@ -988,17 +1005,15 @@ static int visor_startup (struct usb_serial *serial)
#include "ftdi_sio.h"
-static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
+static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
char buf[1]; /* Needed for the usb_control_msg I think */
- dbg("ftdi_sio_serial_open port %d", portNumber);
+ dbg("ftdi_sio_open port %d", port->number);
if (port->active) {
- dbg ("device already open");
+ dbg ("port already open");
return -EINVAL;
}
port->active = 1;
@@ -1069,21 +1084,19 @@ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
}
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
return (0);
}
-static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
char buf[1];
- dbg("ftdi_sio_serial_close port %d", portNumber);
+ dbg("ftdi_sio_close port %d", port->number);
/* FIXME - might be able to do both simultaneously */
if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -1104,8 +1117,8 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
/* FIXME Should I flush the device here? - not doing it for now */
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
@@ -1116,15 +1129,13 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
B1 0
B2..7 length of message excluding byte 0
*/
-static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
const int data_offset = 1;
- dbg("ftdi_sio_serial_write port %d, %d bytes", portNumber, count);
+ dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
if (count == 0) {
dbg("write request of 0 bytes");
@@ -1133,9 +1144,9 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- unsigned char *first_byte = port->write_urb.transfer_buffer;
+ unsigned char *first_byte = port->write_urb->transfer_buffer;
- if (port->write_urb.status == -EINPROGRESS) {
+ if (port->write_urb->status == -EINPROGRESS) {
dbg ("already writing");
return 0;
}
@@ -1148,16 +1159,16 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
/* Copy in the data to send */
if (from_user) {
- copy_from_user(port->write_urb.transfer_buffer + data_offset ,
+ copy_from_user(port->write_urb->transfer_buffer + data_offset ,
buf, count - data_offset );
}
else {
- memcpy(port->write_urb.transfer_buffer + data_offset,
+ memcpy(port->write_urb->transfer_buffer + data_offset,
buf, count - data_offset );
}
/* Write the control byte at the front of the packet*/
- first_byte = port->write_urb.transfer_buffer;
+ first_byte = port->write_urb->transfer_buffer;
*first_byte = 1 | ((count-data_offset) << 2) ;
#ifdef DEBUG
@@ -1181,9 +1192,9 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
#endif
/* send the data out the bulk port */
- port->write_urb.transfer_buffer_length = count;
+ port->write_urb->transfer_buffer_length = count;
- if (usb_submit_urb(&port->write_urb))
+ if (usb_submit_urb(port->write_urb))
dbg("usb_submit_urb(write bulk) failed");
dbg("write returning: %d", count - data_offset);
@@ -1197,14 +1208,24 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
static void ftdi_sio_read_bulk_callback (struct urb *urb)
{ /* ftdi_sio_serial_buld_callback */
- struct usb_serial *serial = (struct usb_serial *)urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
const int data_offset = 2;
int i;
dbg("ftdi_sio_read_bulk_callback");
+ if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
+ return;
+ }
+
if (urb->status) {
dbg("nonzero read bulk status received: %d", urb->status);
return;
@@ -1227,6 +1248,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
if (urb->actual_length > data_offset) {
+ tty = port->tty;
for (i = data_offset ; i < urb->actual_length ; ++i) {
tty_insert_flip_char(tty, data[i], 0);
}
@@ -1241,14 +1263,14 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
} /* ftdi_sio_serial_read_bulk_callback */
-static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios)
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
- unsigned int cflag = tty->termios->c_cflag;
+ struct usb_serial *serial = port->serial;
+ unsigned int cflag = port->tty->termios->c_cflag;
__u16 urb_value; /* Will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
- dbg("ftdi_sio_set_termios port %d", port);
+
+ dbg("ftdi_sio_set_termios port %d", port->number);
/* FIXME - we should keep the old termios really */
/* FIXME -For this cut I don't care if the line is really changing or
@@ -1312,14 +1334,14 @@ static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_te
/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
-static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ struct usb_serial *serial = port->serial;
__u16 urb_value=0; /* Will hold the new flags */
char buf[1];
int ret, mask;
- dbg("ftdi_sio_ioctl port %d", port);
+
+ dbg("ftdi_sio_ioctl port %d", port->number);
/* Based on code from acm.c */
switch (cmd) {
@@ -1408,8 +1430,9 @@ static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned
static void keyspan_pda_rx_interrupt (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *) urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
@@ -1417,11 +1440,21 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
if (urb->status)
return;
- /* see if the message is data or a status interrupt */
+ if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ /* see if the message is data or a status interrupt */
switch (data[0]) {
case 0:
/* rest of message is rx data */
if (urb->actual_length) {
+ tty = serial->port[0].tty;
for (i = 1; i < urb->actual_length ; ++i) {
tty_insert_flip_char(tty, data[i], 0);
}
@@ -1435,6 +1468,7 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
case 1: /* modemline change */
break;
case 2: /* tx unthrottle interrupt */
+ tty = serial->port[0].tty;
serial->tx_throttled = 0;
wake_up(&serial->write_wait); /* wake up writer */
wake_up(&tty->write_wait); /* them too */
@@ -1451,11 +1485,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
}
-static void keyspan_pda_rx_throttle (struct tty_struct *tty)
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
/* stop receiving characters. We just turn off the URB request, and
let chars pile up in the device. If we're doing hardware
flowcontrol, the device will signal the other end when its buffer
@@ -1463,19 +1494,16 @@ static void keyspan_pda_rx_throttle (struct tty_struct *tty)
send an XOFF, although it might make sense to foist that off
upon the device too. */
- dbg("keyspan_pda_rx_throttle port %d", port);
- usb_unlink_urb(&serial->port[port].read_urb);
+ dbg("keyspan_pda_rx_throttle port %d", port->number);
+ usb_unlink_urb(port->read_urb);
}
-static void keyspan_pda_rx_unthrottle (struct tty_struct *tty)
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
/* just restart the receive interrupt URB */
- dbg("keyspan_pda_rx_unthrottle port %d", port);
- if (usb_submit_urb(&serial->port[port].read_urb))
+ dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+ if (usb_submit_urb(port->read_urb))
dbg(" usb_submit_urb(read urb) failed");
return;
}
@@ -1516,9 +1544,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
}
-static void keyspan_pda_break_ctl (struct tty_struct *tty, int break_state)
+static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ struct usb_serial *serial = port->serial;
int value;
if (break_state == -1)
value = 1; /* start break */
@@ -1535,11 +1563,11 @@ static void keyspan_pda_break_ctl (struct tty_struct *tty, int break_state)
}
-static void keyspan_pda_set_termios (struct tty_struct *tty,
+static void keyspan_pda_set_termios (struct usb_serial_port *port,
struct termios *old_termios)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
+ struct usb_serial *serial = port->serial;
+ unsigned int cflag = port->tty->termios->c_cflag;
/* cflag specifies lots of stuff: number of stop bits, parity, number
of data bits, baud. What can the device actually handle?:
@@ -1611,10 +1639,10 @@ static int keyspan_pda_set_modem_info(struct usb_serial *serial,
}
-static int keyspan_pda_ioctl(struct tty_struct *tty, struct file *file,
+static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ struct usb_serial *serial = port->serial;
int rc;
unsigned int value;
unsigned char status, mask;
@@ -1677,11 +1705,10 @@ static int keyspan_pda_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
-static int keyspan_pda_write(struct tty_struct * tty, int from_user,
+static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ struct usb_serial *serial = port->serial;
int request_unthrottle = 0;
int rc = 0;
DECLARE_WAITQUEUE(wait, current);
@@ -1704,7 +1731,7 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- while (serial->port[port].write_urb.status == -EINPROGRESS) {
+ while (port->write_urb->status == -EINPROGRESS) {
if (0 /* file->f_flags & O_NONBLOCK */) {
rc = -EAGAIN;
goto err;
@@ -1746,8 +1773,7 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
remove_wait_queue(&serial->write_wait, &wait);
set_current_state(TASK_RUNNING);
- count = (count > serial->port[port].bulk_out_size) ?
- serial->port[port].bulk_out_size : count;
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
if (count > serial->tx_room) {
unsigned char room;
/* Looks like we might overrun the Tx buffer. Ask the device
@@ -1784,17 +1810,15 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
if (count) {
/* now transfer data */
if (from_user) {
- copy_from_user(serial->port[port].write_urb.transfer_buffer,
- buf, count);
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
}
else {
- memcpy (serial->port[port].write_urb.transfer_buffer,
- buf, count);
+ memcpy (port->write_urb->transfer_buffer, buf, count);
}
/* send the data out the bulk port */
- serial->port[port].write_urb.transfer_buffer_length = count;
+ port->write_urb->transfer_buffer_length = count;
- if (usb_submit_urb(&serial->port[port].write_urb))
+ if (usb_submit_urb(port->write_urb))
dbg(" usb_submit_urb(write bulk) failed");
}
else {
@@ -1828,11 +1852,22 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
static void keyspan_pda_write_bulk_callback (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *) urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+ if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
wake_up_interruptible(&serial->write_wait);
+ tty = port->tty;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -1841,9 +1876,9 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
}
-static int keyspan_pda_write_room (struct tty_struct *tty)
+static int keyspan_pda_write_room (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ struct usb_serial *serial = port->serial;
/* used by n_tty.c for processing of tabs and such. Giving it our
conservative guess is probably good enough, but needs testing by
@@ -1853,9 +1888,9 @@ static int keyspan_pda_write_room (struct tty_struct *tty)
}
-static int keyspan_pda_chars_in_buffer (struct tty_struct *tty)
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ struct usb_serial *serial = port->serial;
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
@@ -1865,11 +1900,9 @@ static int keyspan_pda_chars_in_buffer (struct tty_struct *tty)
}
-static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp)
+static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
unsigned char room;
int rc;
@@ -1901,33 +1934,30 @@ static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp)
/* the normal serial device seems to always turn on DTR and RTS here,
so do the same */
- if (tty->termios->c_cflag & CBAUD)
+ if (port->tty->termios->c_cflag & CBAUD)
keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
else
keyspan_pda_set_modem_info(serial, 0);
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg(" usb_submit_urb(read int) failed");
return (0);
}
-static void keyspan_pda_serial_close(struct tty_struct *tty,
- struct file *filp)
+static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
/* the normal serial device seems to always shut off DTR and RTS now */
- if (tty->termios->c_cflag & HUPCL)
+ if (port->tty->termios->c_cflag & HUPCL)
keyspan_pda_set_modem_info(serial, 0);
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
@@ -1971,7 +2001,7 @@ static int keyspan_pda_startup (struct usb_serial *serial)
intin = serial->port[0].interrupt_in_endpoint;
/* set up the receive interrupt urb */
- FILL_INT_URB(&serial->port[0].read_urb, serial->dev,
+ FILL_INT_URB(serial->port[0].read_urb, serial->dev,
usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
serial->port[0].interrupt_in_buffer,
intin->wMaxPacketSize,
@@ -1990,13 +2020,11 @@ static int keyspan_pda_startup (struct usb_serial *serial)
/*****************************************************************************
* generic devices specific driver functions
*****************************************************************************/
-static int generic_serial_open (struct tty_struct *tty, struct file *filp)
+static int generic_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_serial_open port %d", portNumber);
+ dbg("generic_open port %d", port->number);
if (port->active) {
dbg ("device already open");
@@ -2007,7 +2035,7 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp)
/* if we have a bulk interrupt, start reading from it */
if (serial->num_bulk_in) {
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
}
@@ -2015,33 +2043,29 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp)
}
-static void generic_serial_close(struct tty_struct *tty, struct file * filp)
+static void generic_close (struct usb_serial_port *port, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_serial_close port %d", portNumber);
+ dbg("generic_close port %d", port->number);
/* shutdown any bulk reads that might be going on */
if (serial->num_bulk_out) {
- usb_unlink_urb (&port->write_urb);
+ usb_unlink_urb (port->write_urb);
}
if (serial->num_bulk_in) {
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->read_urb);
}
port->active = 0;
}
-static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_serial_write port %d", portNumber);
+ dbg("generic_serial_write port %d", port->number);
if (count == 0) {
dbg("write request of 0 bytes");
@@ -2050,7 +2074,7 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- if (port->write_urb.status == -EINPROGRESS) {
+ if (port->write_urb->status == -EINPROGRESS) {
dbg ("already writing");
return (0);
}
@@ -2058,16 +2082,16 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
if (from_user) {
- copy_from_user(port->write_urb.transfer_buffer, buf, count);
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
}
else {
- memcpy (port->write_urb.transfer_buffer, buf, count);
+ memcpy (port->write_urb->transfer_buffer, buf, count);
}
/* send the data out the bulk port */
- port->write_urb.transfer_buffer_length = count;
+ port->write_urb->transfer_buffer_length = count;
- if (usb_submit_urb(&port->write_urb))
+ if (usb_submit_urb(port->write_urb))
dbg("usb_submit_urb(write bulk) failed");
return (count);
@@ -2078,17 +2102,15 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
}
-static int generic_write_room (struct tty_struct *tty)
+static int generic_write_room (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
int room;
- dbg("generic_write_room port %d", portNumber);
+ dbg("generic_write_room port %d", port->number);
if (serial->num_bulk_out) {
- if (port->write_urb.status == -EINPROGRESS)
+ if (port->write_urb->status == -EINPROGRESS)
room = 0;
else
room = port->bulk_out_size;
@@ -2100,16 +2122,14 @@ static int generic_write_room (struct tty_struct *tty)
}
-static int generic_chars_in_buffer (struct tty_struct *tty)
+static int generic_chars_in_buffer (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_chars_in_buffer port %d", portNumber);
+ dbg("generic_chars_in_buffer port %d", port->number);
if (serial->num_bulk_out) {
- if (port->write_urb.status == -EINPROGRESS) {
+ if (port->write_urb->status == -EINPROGRESS) {
return (port->bulk_out_size);
}
}
@@ -2118,43 +2138,25 @@ static int generic_chars_in_buffer (struct tty_struct *tty)
}
-static void generic_throttle (struct tty_struct *tty)
-{
- /* do nothing for the generic device */
- return;
-}
-
-
-static void generic_unthrottle (struct tty_struct *tty)
-{
- /* do nothing for the generic device */
- return;
-}
-
-
-static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
- /* generic driver doesn't support any ioctls yet */
- return -ENOIOCTLCMD;
-}
-
-
-static void generic_set_termios (struct tty_struct *tty, struct termios * old)
-{
- /* generic driver doesn't really care about setting any line settings */
- return;
-}
-
-
static void generic_read_bulk_callback (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *)urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
dbg("generic_read_bulk_callback");
+ if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
+ return;
+ }
+
if (urb->status) {
dbg("nonzero read bulk status received: %d", urb->status);
return;
@@ -2169,7 +2171,8 @@ static void generic_read_bulk_callback (struct urb *urb)
printk ("\n");
}
#endif
-
+
+ tty = port->tty;
if (urb->actual_length) {
for (i = 0; i < urb->actual_length ; ++i) {
tty_insert_flip_char(tty, data[i], 0);
@@ -2187,16 +2190,27 @@ static void generic_read_bulk_callback (struct urb *urb)
static void generic_write_bulk_callback (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *) urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
dbg("generic_write_bulk_callback");
+ if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
+ return;
+ }
+
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
}
+ tty = port->tty;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -2206,7 +2220,6 @@ static void generic_write_bulk_callback (struct urb *urb)
}
-
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial *serial = NULL;
@@ -2331,6 +2344,11 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {
port = &serial->port[i];
+ port->read_urb = usb_alloc_urb (0);
+ if (!port->read_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->bulk_in_buffer) {
@@ -2338,16 +2356,21 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
goto probe_error;
}
if (serial->type->read_bulk_callback) {
- FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, serial);
+ FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
} else {
- FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, serial);
+ FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
}
}
for (i = 0; i < num_bulk_out; ++i) {
port = &serial->port[i];
+ port->write_urb = usb_alloc_urb(0);
+ if (!port->write_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
if (!port->bulk_out_buffer) {
@@ -2355,25 +2378,31 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
goto probe_error;
}
if (serial->type->write_bulk_callback) {
- FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, serial);
+ FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
} else {
- FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, serial);
+ FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
}
}
#if 0 /* use this code when WhiteHEAT is up and running */
for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ port->control_urb = usb_alloc_urb(0);
+ if (!port->control_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- serial->interrupt_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL);
- if (!serial->interrupt_in_buffer[i]) {
+ port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->interrupt_in_buffer) {
err("Couldn't allocate interrupt_in_buffer");
goto probe_error;
}
- FILL_INT_URB(&serial->control_urb[i], dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
- serial->interrupt_in_buffer[i], buffer_size, serial_control_irq,
- serial, interrupt_in_endpoint[i]->bInterval);
+ FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
+ port->interrupt_in_buffer, buffer_size, serial_control_irq,
+ port, interrupt_in_endpoint[i]->bInterval);
}
#endif
@@ -2395,15 +2424,27 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
probe_error:
if (serial) {
- for (i = 0; i < num_bulk_in; ++i)
+ for (i = 0; i < num_bulk_in; ++i) {
+ port = &serial->port[i];
+ if (port->read_urb)
+ usb_free_urb (port->read_urb);
if (serial->port[i].bulk_in_buffer[i])
kfree (serial->port[i].bulk_in_buffer);
- for (i = 0; i < num_bulk_out; ++i)
+ }
+ for (i = 0; i < num_bulk_out; ++i) {
+ port = &serial->port[i];
+ if (port->write_urb)
+ usb_free_urb (port->write_urb);
if (serial->port[i].bulk_out_buffer)
kfree (serial->port[i].bulk_out_buffer);
- for (i = 0; i < num_interrupt_in; ++i)
+ }
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ if (port->control_urb)
+ usb_free_urb (port->control_urb);
if (serial->port[i].interrupt_in_buffer)
kfree (serial->port[i].interrupt_in_buffer);
+ }
/* return the minor range that this device had */
return_serial (serial);
@@ -2422,27 +2463,33 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
int i;
if (serial) {
- /* need to stop any transfers...*/
- for (i = 0; i < serial->num_ports; ++i) {
- port = &serial->port[i];
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
- port->active = 0;
- }
+ for (i = 0; i < serial->num_ports; ++i)
+ serial->port[i].active = 0;
- /* free up any memory that we allocated */
for (i = 0; i < serial->num_bulk_in; ++i) {
port = &serial->port[i];
+ if (port->read_urb) {
+ usb_unlink_urb (port->read_urb);
+ usb_free_urb (port->read_urb);
+ }
if (port->bulk_in_buffer)
kfree (port->bulk_in_buffer);
}
for (i = 0; i < serial->num_bulk_out; ++i) {
port = &serial->port[i];
+ if (port->write_urb) {
+ usb_unlink_urb (port->write_urb);
+ usb_free_urb (port->write_urb);
+ }
if (port->bulk_out_buffer)
kfree (port->bulk_out_buffer);
}
for (i = 0; i < serial->num_interrupt_in; ++i) {
port = &serial->port[i];
+ if (port->control_urb) {
+ usb_unlink_urb (port->control_urb);
+ usb_free_urb (port->control_urb);
+ }
if (port->interrupt_in_buffer)
kfree (port->interrupt_in_buffer);
}
@@ -2468,7 +2515,7 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
static struct tty_driver serial_tty_driver = {
magic: TTY_DRIVER_MAGIC,
driver_name: "usb",
- name: "ttyUSB",
+ name: "ttyUSB%d",
major: SERIAL_TTY_MAJOR,
minor_start: 0,
num: SERIAL_TTY_MINORS,
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 71fecb0ec..48082101a 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -52,8 +52,12 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
+#define USB_SERIAL_MAGIC 0x6702 /* magic number for usb_serial struct */
+#define USB_SERIAL_PORT_MAGIC 0x7301 /* magic number for usb_serial_port struct */
+
struct usb_serial_port {
+ int magic;
struct usb_serial *serial; /* pointer back to the owner of this port */
struct tty_struct * tty; /* the coresponding tty for this device */
unsigned char minor;
@@ -63,21 +67,21 @@ struct usb_serial_port {
struct usb_endpoint_descriptor * interrupt_in_endpoint;
__u8 interrupt_in_interval;
unsigned char * interrupt_in_buffer;
- struct urb control_urb;
+ struct urb * control_urb;
unsigned char * bulk_in_buffer;
- struct urb read_urb;
+ struct urb * read_urb;
unsigned char * bulk_out_buffer;
int bulk_out_size;
- struct urb write_urb;
+ struct urb * write_urb;
void * private; /* data private to the specific driver */
};
struct usb_serial {
+ int magic;
struct usb_device * dev;
struct usb_serial_device_type * type;
- struct tty_struct * tty; /* the coresponding tty for this device */
unsigned char minor;
unsigned char num_ports; /* the number of ports this device has */
char num_interrupt_in; /* number of interrupt in endpoints we have */
@@ -121,16 +125,16 @@ struct usb_serial_device_type {
int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */
/* serial function calls */
- int (*open)(struct tty_struct * tty, struct file * filp);
- void (*close)(struct tty_struct * tty, struct file * filp);
- int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count);
- int (*write_room)(struct tty_struct *tty);
- int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
- void (*break_ctl)(struct tty_struct *tty, int break_state);
- int (*chars_in_buffer)(struct tty_struct *tty);
- void (*throttle)(struct tty_struct * tty);
- void (*unthrottle)(struct tty_struct * tty);
+ int (*open) (struct usb_serial_port *port, struct file * filp);
+ void (*close) (struct usb_serial_port *port, struct file * filp);
+ int (*write) (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+ int (*write_room) (struct usb_serial_port *port);
+ int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+ void (*set_termios) (struct usb_serial_port *port, struct termios * old);
+ void (*break_ctl) (struct usb_serial_port *port, int break_state);
+ int (*chars_in_buffer) (struct usb_serial_port *port);
+ void (*throttle) (struct usb_serial_port *port);
+ void (*unthrottle) (struct usb_serial_port *port);
void (*read_bulk_callback)(struct urb *urb);
void (*write_bulk_callback)(struct urb *urb);
@@ -140,15 +144,11 @@ struct usb_serial_device_type {
/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
/* need to always compile these in, as some of the other devices use these functions as their own. */
/* if a driver does not provide a function pointer, the generic function will be called. */
-static int generic_serial_open (struct tty_struct *tty, struct file *filp);
-static void generic_serial_close (struct tty_struct *tty, struct file *filp);
-static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
-static int generic_write_room (struct tty_struct *tty);
-static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
-static void generic_set_termios (struct tty_struct *tty, struct termios * old);
-static int generic_chars_in_buffer (struct tty_struct *tty);
-static void generic_throttle (struct tty_struct *tty);
-static void generic_unthrottle (struct tty_struct *tty);
+static int generic_open (struct usb_serial_port *port, struct file *filp);
+static void generic_close (struct usb_serial_port *port, struct file *filp);
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int generic_write_room (struct usb_serial_port *port);
+static int generic_chars_in_buffer (struct usb_serial_port *port);
static void generic_read_bulk_callback (struct urb *urb);
static void generic_write_bulk_callback (struct urb *urb);
@@ -172,11 +172,11 @@ static struct usb_serial_device_type generic_device = {
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
/* function prototypes for the Connect Tech WhiteHEAT serial converter */
-static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp);
-static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp);
-static void whiteheat_set_termios (struct tty_struct *tty, struct termios * old);
-static void whiteheat_throttle (struct tty_struct *tty);
-static void whiteheat_unthrottle (struct tty_struct *tty);
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp);
+static void whiteheat_close (struct usb_serial_port *port, struct file *filp);
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
+static void whiteheat_throttle (struct usb_serial_port *port);
+static void whiteheat_unthrottle (struct usb_serial_port *port);
static int whiteheat_startup (struct usb_serial *serial);
/* All of the device info needed for the Connect Tech WhiteHEAT */
@@ -193,6 +193,7 @@ static struct usb_serial_device_type whiteheat_fake_device = {
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
startup: whiteheat_startup
};
static struct usb_serial_device_type whiteheat_device = {
@@ -206,8 +207,8 @@ static struct usb_serial_device_type whiteheat_device = {
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
num_ports: 4,
- open: whiteheat_serial_open,
- close: whiteheat_serial_close,
+ open: whiteheat_open,
+ close: whiteheat_close,
throttle: whiteheat_throttle,
unthrottle: whiteheat_unthrottle,
set_termios: whiteheat_set_termios,
@@ -269,11 +270,11 @@ struct visor_connection_info {
/* function prototypes for a handspring visor */
-static int visor_serial_open (struct tty_struct *tty, struct file *filp);
-static void visor_serial_close (struct tty_struct *tty, struct file *filp);
-static void visor_throttle (struct tty_struct *tty);
-static void visor_unthrottle (struct tty_struct *tty);
-static int visor_startup (struct usb_serial *serial);
+static int visor_open (struct usb_serial_port *port, struct file *filp);
+static void visor_close (struct usb_serial_port *port, struct file *filp);
+static void visor_throttle (struct usb_serial_port *port);
+static void visor_unthrottle (struct usb_serial_port *port);
+static int visor_startup (struct usb_serial *serial);
/* All of the device info needed for the Handspring Visor */
static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID;
@@ -289,8 +290,8 @@ static struct usb_serial_device_type handspring_device = {
num_bulk_in: 2,
num_bulk_out: 2,
num_ports: 2,
- open: visor_serial_open,
- close: visor_serial_close,
+ open: visor_open,
+ close: visor_close,
throttle: visor_throttle,
unthrottle: visor_unthrottle,
startup: visor_startup,
@@ -300,12 +301,12 @@ static struct usb_serial_device_type handspring_device = {
#ifdef CONFIG_USB_SERIAL_FTDI_SIO
/* function prototypes for a FTDI serial converter */
-static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp);
-static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp);
-static int ftdi_sio_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
+static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp);
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp);
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static void ftdi_sio_read_bulk_callback (struct urb *urb);
-static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios * old);
-static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old);
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
/* All of the device info needed for the FTDI SIO serial converter */
static __u16 ftdi_vendor_id = FTDI_VENDOR_ID;
@@ -321,9 +322,10 @@ static struct usb_serial_device_type ftdi_sio_device = {
num_bulk_in: 1,
num_bulk_out: 1,
num_ports: 1,
- open: ftdi_sio_serial_open,
- close: ftdi_sio_serial_close,
- write: ftdi_sio_serial_write,
+ open: ftdi_sio_open,
+ close: ftdi_sio_close,
+ write: ftdi_sio_write,
+ ioctl: ftdi_sio_ioctl,
read_bulk_callback: ftdi_sio_read_bulk_callback,
set_termios: ftdi_sio_set_termios
};
@@ -332,28 +334,28 @@ static struct usb_serial_device_type ftdi_sio_device = {
#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
/* function prototypes for a Keyspan PDA serial converter */
-static int keyspan_pda_serial_open (struct tty_struct *tty,
+static int keyspan_pda_open (struct usb_serial_port *port,
struct file *filp);
-static void keyspan_pda_serial_close (struct tty_struct *tty,
+static void keyspan_pda_close (struct usb_serial_port *port,
struct file *filp);
static int keyspan_pda_startup (struct usb_serial *serial);
-static void keyspan_pda_rx_throttle (struct tty_struct *tty);
-static void keyspan_pda_rx_unthrottle (struct tty_struct *tty);
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port);
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port);
static int keyspan_pda_setbaud (struct usb_serial *serial, int baud);
-static int keyspan_pda_write_room (struct tty_struct *tty);
-static int keyspan_pda_write (struct tty_struct *tty,
+static int keyspan_pda_write_room (struct usb_serial_port *port);
+static int keyspan_pda_write (struct usb_serial_port *port,
int from_user,
const unsigned char *buf,
int count);
static void keyspan_pda_write_bulk_callback (struct urb *urb);
-static int keyspan_pda_chars_in_buffer (struct tty_struct *tty);
-static int keyspan_pda_ioctl (struct tty_struct *tty,
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
+static int keyspan_pda_ioctl (struct usb_serial_port *port,
struct file *file,
unsigned int cmd,
unsigned long arg);
-static void keyspan_pda_set_termios (struct tty_struct *tty,
+static void keyspan_pda_set_termios (struct usb_serial_port *port,
struct termios *old);
-static void keyspan_pda_break_ctl (struct tty_struct *tty,
+static void keyspan_pda_break_ctl (struct usb_serial_port *port,
int break_state);
static int keyspan_pda_fake_startup (struct usb_serial *serial);
@@ -385,8 +387,8 @@ static struct usb_serial_device_type keyspan_pda_device = {
num_bulk_in: 0,
num_bulk_out: 1,
num_ports: 1,
- open: keyspan_pda_serial_open,
- close: keyspan_pda_serial_close,
+ open: keyspan_pda_open,
+ close: keyspan_pda_close,
write: keyspan_pda_write,
write_room: keyspan_pda_write_room,
write_bulk_callback: keyspan_pda_write_bulk_callback,
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index f5e67acec..9927b5382 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -1315,8 +1315,8 @@ static __u8 root_hub_dev_des[] =
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
- 0x00, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
@@ -1617,7 +1617,13 @@ static int rh_submit_urb(urb_t *urb)
memcpy (data, root_hub_config_des, len);
OK(len);
case 0x03: /* string descriptors */
- stat = -EPIPE;
+ len = usb_root_hub_string (wValue & 0xff,
+ uhci->io_addr, "UHCI",
+ data, wLength);
+ if (len > 0) {
+ OK (min (leni, len));
+ } else
+ stat = -EPIPE;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
@@ -1985,6 +1991,15 @@ static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsign
{
int retval;
struct uhci *uhci;
+ char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+ sprintf(buf, "%d", irq);
+#else
+ bufp = __irq_itoa(irq);
+#endif
+ printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+ io_addr, bufp);
uhci = alloc_uhci(io_addr, io_size);
if (!uhci)
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 78ae0a0ea..b134107da 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -262,8 +262,14 @@ static int sohci_submit_urb (urb_t * urb)
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
+ /* a request to the virtual root hub */
if (usb_pipedevice (pipe) == ohci->rh.devnum)
- return rh_submit_urb (urb); /* a request to the virtual root hub */
+ return rh_submit_urb (urb);
+
+ /* when controller's hung, permit only hub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled)
+ return -ESHUTDOWN;
/* every endpoint has a ed, locate and fill it */
if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
@@ -333,10 +339,11 @@ static int sohci_submit_urb (urb_t * urb)
(le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
}
- td_submit_urb (urb); /* fill the TDs and link it to the ed */
-
if (ed->state != ED_OPER) /* link the ed into a chain if is not already */
ep_link (ohci, ed);
+
+ td_submit_urb (urb); /* fill the TDs and link it to the ed */
+
spin_unlock_irqrestore (&usb_ed_lock, flags);
urb->status = USB_ST_URB_PENDING;
@@ -1122,8 +1129,8 @@ static __u8 root_hub_dev_des[] =
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
- 0x00, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
@@ -1222,13 +1229,16 @@ static void rh_int_timer_do (unsigned long ptr)
urb_t * urb = (urb_t *) ptr;
ohci_t * ohci = urb->dev->bus->hcpriv;
+
+ if (ohci->disabled)
+ return;
if(ohci->rh.send) {
len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
if (len > 0) {
urb->actual_length = len;
#ifdef DEBUG
- urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+ urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
#endif
if (urb->complete) urb->complete (urb);
}
@@ -1379,27 +1389,49 @@ static int rh_submit_urb (urb_t * urb)
len = min (leni, min (sizeof (root_hub_config_des), wLength));
data_buf = root_hub_config_des; OK(len);
case (0x03): /* string descriptors */
+ len = usb_root_hub_string (wValue & 0xff,
+ (int) ohci->regs, "OHCI",
+ data, wLength);
+ if (len > 0) {
+ data_buf = data;
+ OK (min (leni, len));
+ }
+ // else fallthrough
default:
status = TD_CC_STALL;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
- *(__u8 *) (data_buf+1) = 0x29;
- put_unaligned(cpu_to_le32 (readl (&ohci->regs->roothub.a)),
- (__u32 *) (data_buf + 2));
- *(__u8 *) data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */
-
- len = min (leni, min(*(__u8 *) data_buf, wLength));
- *(__u8 *) (data_buf+6) = 0; /* Root Hub needs no current from bus */
- if (*(__u8 *) (data_buf+2) < 8) { /* less than 8 Ports */
- *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff;
- *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16;
- } else {
- put_unaligned(cpu_to_le32 (readl(&ohci->regs->roothub.b)),
- (__u32 *) (data_buf + 7));
+ {
+ __u32 temp = readl (&ohci->regs->roothub.a);
+
+ data_buf [0] = 9; // min length;
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = readl (&ohci->regs->roothub.b);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min (leni, min (data_buf [0], wLength));
+ OK (len);
}
- OK (len);
case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
@@ -1413,7 +1445,8 @@ static int rh_submit_urb (urb_t * urb)
dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
len = min(len, leni);
- memcpy (data, data_buf, len);
+ if (data != data_buf)
+ memcpy (data, data_buf, len);
urb->actual_length = len;
urb->status = cc_to_error [status];
@@ -1472,6 +1505,7 @@ static void hc_reset (ohci_t * ohci)
}
udelay (1);
}
+ ohci->disabled = 0;
}
/*-------------------------------------------------------------------------*/
@@ -1502,7 +1536,7 @@ static int hc_start (ohci_t * ohci)
writel (0x628, &ohci->regs->lsthresh);
/* Choose the interrupts we care about now, others later on demand */
- mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
writel (mask, &ohci->regs->intrenable);
@@ -1550,6 +1584,11 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, controller disabled");
+ }
+
if (ints & OHCI_INTR_WDH) {
writel (OHCI_INTR_WDH, &regs->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci));
@@ -1650,16 +1689,24 @@ static void hc_release_ohci (ohci_t * ohci)
static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
{
ohci_t * ohci;
- dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base);
+ char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+ sprintf(buf, "%d", irq);
+#else
+ bufp = __irq_itoa(irq);
+#endif
+ printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
+ (unsigned long) mem_base, bufp);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
return -ENOMEM;
}
-
+
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
-
+
hc_reset (ohci);
writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
index 6098f0b39..e854e0c1d 100644
--- a/drivers/usb/usb-ohci.h
+++ b/drivers/usb/usb-ohci.h
@@ -212,31 +212,53 @@ struct ohci_regs {
} roothub;
} __attribute((aligned(32)));
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
/*
- * cmdstatus register */
-#define OHCI_CLF 0x02
-#define OHCI_BLF 0x04
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
/*
- * Interrupt register masks
+ * HcCommandStatus (cmdstatus) register masks
*/
-#define OHCI_INTR_SO (1)
-#define OHCI_INTR_WDH (1 << 1)
-#define OHCI_INTR_SF (1 << 2)
-#define OHCI_INTR_RD (1 << 3)
-#define OHCI_INTR_UE (1 << 4)
-#define OHCI_INTR_FNO (1 << 5)
-#define OHCI_INTR_RHSC (1 << 6)
-#define OHCI_INTR_OC (1 << 30)
-#define OHCI_INTR_MIE (1 << 31)
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
/*
- * Control register masks
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
*/
-#define OHCI_USB_RESET 0
-#define OHCI_USB_RESUME (1 << 6)
-#define OHCI_USB_OPER (2 << 6)
-#define OHCI_USB_SUSPEND (3 << 6)
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
/* Virtual Root HUB */
@@ -248,6 +270,9 @@ struct virt_root_hub {
int interval;
struct timer_list rh_int_timer;
};
+
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
/* destination of request */
#define RH_INTERFACE 0x01
@@ -261,8 +286,8 @@ struct virt_root_hub {
#define RH_GET_STATUS 0x0080
#define RH_CLEAR_FEATURE 0x0100
#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
#define RH_SET_DESCRIPTOR 0x0700
#define RH_GET_CONFIGURATION 0x0880
#define RH_SET_CONFIGURATION 0x0900
@@ -282,6 +307,7 @@ struct virt_root_hub {
#define RH_PORT_RESET 0x04
#define RH_PORT_POWER 0x08
#define RH_PORT_LOW_SPEED 0x09
+
#define RH_C_PORT_CONNECTION 0x10
#define RH_C_PORT_ENABLE 0x11
#define RH_C_PORT_SUSPEND 0x12
@@ -298,29 +324,44 @@ struct virt_root_hub {
#define RH_ACK 0x01
#define RH_REQ_ERR -1
#define RH_NACK 0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
-/* Root-Hub Register info */
-
-#define RH_PS_CCS 0x00000001
-#define RH_PS_PES 0x00000002
-#define RH_PS_PSS 0x00000004
-#define RH_PS_POCI 0x00000008
-#define RH_PS_PRS 0x00000010
-#define RH_PS_PPS 0x00000100
-#define RH_PS_LSDA 0x00000200
-#define RH_PS_CSC 0x00010000
-#define RH_PS_PESC 0x00020000
-#define RH_PS_PSSC 0x00040000
-#define RH_PS_OCIC 0x00080000
-#define RH_PS_PRSC 0x00100000
-
-/* Root hub status bits */
-#define RH_HS_LPS 0x00000001
-#define RH_HS_OCI 0x00000002
-#define RH_HS_DRWE 0x00008000
-#define RH_HS_LPSC 0x00010000
-#define RH_HS_OCIC 0x00020000
-#define RH_HS_CRWE 0x80000000
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
#define min(a,b) (((a)<(b))?(a):(b))
@@ -347,23 +388,25 @@ typedef struct
typedef struct ohci {
- struct ohci_hcca hcca; /* hcca */
+ struct ohci_hcca hcca; /* hcca */
int irq;
- struct ohci_regs * regs; /* OHCI controller's memory */
- struct list_head ohci_hcd_list; /* list of all ohci_hcd */
+ int disabled; /* e.g. got a UE, we're hung */
+
+ struct ohci_regs * regs; /* OHCI controller's memory */
+ struct list_head ohci_hcd_list; /* list of all ohci_hcd */
struct ohci * next; // chain of uhci device contexts
struct list_head urb_list; // list of all pending urbs
spinlock_t urb_list_lock; // lock to keep consistency
- int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load ballancing)*/
+ int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/
ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */
ed_t * ed_bulktail; /* last endpoint of bulk list */
ed_t * ed_controltail; /* last endpoint of control list */
ed_t * ed_isotail; /* last endpoint of iso list */
int intrstatus;
- __u32 hc_control; /* copy of the hc control reg */
+ __u32 hc_control; /* copy of the hc control reg */
struct usb_bus * bus;
struct usb_device * dev[128];
struct virt_root_hub rh;
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index 0cac2ef13..d1b77c8f5 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -3,20 +3,19 @@
* (c) 1999 Michael Gee (michael@linuxspecific.com)
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
- * Further reference:
- * This driver is based on the 'USB Mass Storage Class' document. This
- * describes in detail the protocol used to communicate with such
- * devices. Clearly, the designers had SCSI and ATAPI commands in mind
- * when they created this document. The commands are all very similar
- * to commands in the SCSI-II and ATAPI specifications.
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
*
- * It is important to note that in a number of cases this class exhibits
- * class-specific exemptions from the USB specification. Notably the
- * usage of NAK, STALL and ACK differs from the norm, in that they are
- * used to communicate wait, failed and OK on commands.
- * Also, for certain devices, the interrupt endpoint is used to convey
- * status of a command.
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
*
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
*/
#include <linux/module.h>
@@ -40,7 +39,6 @@
#include "usb-storage.h"
#include "usb-storage-debug.h"
-
/*
* This is the size of the structure Scsi_Host_Template. We create
* an instance of this structure in this file and this is a check
@@ -75,34 +73,47 @@ typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
typedef int (*trans_reset)(struct us_data*);
typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
+/* we allocate one of these for every device that we remember */
struct us_data {
struct us_data *next; /* next device */
struct usb_device *pusb_dev; /* this usb_device */
unsigned int flags; /* from filter initially */
+
+ /* information about the device -- only good if device is attached */
__u8 ifnum; /* interface number */
__u8 ep_in; /* in endpoint */
__u8 ep_out; /* out ....... */
__u8 ep_int; /* interrupt . */
- __u8 subclass; /* as in overview */
- __u8 protocol; /* .............. */
- trans_cmnd transport; /* protocol specific do cmd */
- trans_reset transport_reset; /* .......... device reset */
+ __u8 subclass;
+ __u8 protocol;
+
+ /* function pointers for this device */
+ trans_cmnd transport; /* transport function */
+ trans_reset transport_reset; /* transport device reset */
proto_cmnd proto_handler; /* protocol handler */
+
+ /* SCSI interfaces */
GUID(guid); /* unique dev id */
struct Scsi_Host *host; /* our dummy host data */
Scsi_Host_Template htmplt; /* own host template */
int host_number; /* to find us */
int host_no; /* allocated by scsi */
Scsi_Cmnd *srb; /* current srb */
+
+ /* thread information */
Scsi_Cmnd *queue_srb; /* the single queue slot */
int action; /* what to do */
+ int pid; /* control thread */
+
+ /* interrupt info for CBI devices */
struct semaphore ip_waitq; /* for CBI interrupts */
__u16 ip_data; /* interrupt data */
int ip_wanted; /* needed */
- int pid; /* control thread */
- struct semaphore *notify; /* wait for thread to begin */
void *irq_handle; /* for USB int requests */
unsigned int irqpipe; /* pipe for release_irq */
+
+ /* mutual exclusion structures */
+ struct semaphore notify; /* wait for thread to begin */
struct semaphore sleeper; /* to sleep on */
struct semaphore queue_exclusion; /* to protect data structs */
};
@@ -116,6 +127,7 @@ struct us_data {
#define US_ACT_DEVICE_RESET 3
#define US_ACT_BUS_RESET 4
#define US_ACT_HOST_RESET 5
+#define US_ACT_EXIT 6
/* The list of structures and the protective lock for them */
static struct us_data *us_list;
@@ -254,11 +266,6 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
case MODE_SENSE:
return srb->cmnd[4];
- /* FIXME: this needs to come out when the other
- * fix is in place */
- case READ_CAPACITY:
- return 8;
-
/* FIXME: these should be removed and tested */
case LOG_SENSE:
case MODE_SENSE_10:
@@ -791,9 +798,8 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
/* check the return code for the command */
+ US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
if (result < 0) {
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
-
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
@@ -820,15 +826,10 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* STATUS STAGE */
- /* go to sleep until we get this interrup */
- /* FIXME: this should be changed to use a timeout -- or let the
- * device reset routine up() this for us to unjam us
- */
+ /* go to sleep until we get this interrupt */
down(&(us->ip_waitq));
- /* FIXME: currently this code is unreachable, but the idea is
- * necessary. See above comment.
- */
+ /* if we were woken up by a reset instead of the actual interrupt */
if (us->ip_wanted) {
US_DEBUGP("Did not get interrupt on CBI\n");
us->ip_wanted = 0;
@@ -837,8 +838,9 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
- /* UFI gives us ASC and ASCQ, like a request sense */
- /* REQUEST_SENSE and INQUIRY don't affect the sense data, so we
+ /* UFI gives us ASC and ASCQ, like a request sense
+ *
+ * REQUEST_SENSE and INQUIRY don't affect the sense data, so we
* ignore the information for those commands
*/
if (us->subclass == US_SC_UFI) {
@@ -1114,29 +1116,27 @@ static int us_detect(struct SHT *sht)
static int us_release(struct Scsi_Host *psh)
{
struct us_data *us = (struct us_data *)psh->hostdata[0];
- struct us_data *prev;
unsigned long flags;
+ int result;
+ /* lock the data structures */
+ spin_lock_irqsave(&us_list_spinlock, flags);
+
+ US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
+
+ /* release the interrupt handler, if necessary */
if (us->irq_handle) {
- usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
+ US_DEBUGP("-- releasing irq\n");
+ result = usb_release_irq(us->pusb_dev, us->irq_handle,
+ us->irqpipe);
+ US_DEBUGP("-- usb_release_irq() returned %d\n", result);
us->irq_handle = NULL;
}
- /* FIXME: release the interface claim here? */
-
- /* FIXME: we need to move this elsewhere --
- * the remove function only gets called to remove the module
- */
- spin_lock_irqsave(&us_list_spinlock, flags);
- if (us_list == us)
- us_list = us->next;
- else {
- prev = us_list;
- while (prev->next != us)
- prev = prev->next;
- prev->next = us->next;
- }
+ /* lock the data structures */
spin_unlock_irqrestore(&us_list_spinlock, flags);
+
+ /* we always have a successful release */
return 0;
}
@@ -1153,7 +1153,7 @@ static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
{
struct us_data *us = (struct us_data *)srb->host->hostdata[0];
- US_DEBUGP("Command wakeup\n");
+ US_DEBUGP("us_queuecommand() called\n");
srb->host_scribble = (unsigned char *)us;
/* get exclusive access to the structures we want */
@@ -1180,9 +1180,11 @@ static int us_abort( Scsi_Cmnd *srb )
/* FIXME: this doesn't do anything right now */
static int us_bus_reset( Scsi_Cmnd *srb )
{
- // struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
US_DEBUGP("Bus reset requested\n");
+ if (us->ip_wanted)
+ up(&(us->ip_waitq));
// us->transport_reset(us);
return SUCCESS;
}
@@ -1364,12 +1366,9 @@ static int usb_stor_control_thread(void * __us)
unlock_kernel();
- up(us->notify);
+ up(&(us->notify));
for(;;) {
- siginfo_t info;
- int unsigned long signr;
-
US_DEBUGP("*** thread sleeping.\n");
down(&(us->sleeper));
down(&(us->queue_exclusion));
@@ -1378,7 +1377,7 @@ static int usb_stor_control_thread(void * __us)
/* take the command off the queue */
action = us->action;
us->action = 0;
- us->srb = us-> queue_srb;
+ us->srb = us->queue_srb;
/* release the queue lock as fast as possible */
up(&(us->queue_exclusion));
@@ -1433,7 +1432,8 @@ static int usb_stor_control_thread(void * __us)
us->proto_handler(us->srb, us);
}
- US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result);
+ US_DEBUGP("scsi cmd done, result=0x%x\n",
+ us->srb->result);
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1452,19 +1452,12 @@ static int usb_stor_control_thread(void * __us)
} /* end switch on action */
- /* FIXME: we ignore TERM and KILL... is this right? */
- if (signal_pending(current)) {
- /* sending SIGUSR1 makes us print out some info */
- spin_lock_irq(&current->sigmask_lock);
- signr = dequeue_signal(&current->blocked, &info);
- spin_unlock_irq(&current->sigmask_lock);
- } /* if (singal_pending(current)) */
+ /* exit if we get a signal to exit */
+ if (action == US_ACT_EXIT)
+ break;
} /* for (;;) */
- // MOD_DEC_USE_COUNT;
-
printk("usb_stor_control_thread exiting\n");
-
return 0;
}
@@ -1495,14 +1488,12 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* FIXME: this isn't quite right... */
/* We make an exception for the shuttle E-USB */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- protocol = US_PR_CB;
- subclass = US_SC_8070; /* an assumption */
- } else if (dev->descriptor.bDeviceClass != 0 ||
- altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
- altsetting->bInterfaceSubClass < US_SC_MIN ||
- altsetting->bInterfaceSubClass > US_SC_MAX) {
+ if (!(dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) &&
+ !(dev->descriptor.bDeviceClass == 0 &&
+ altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+ altsetting->bInterfaceSubClass >= US_SC_MIN &&
+ altsetting->bInterfaceSubClass <= US_SC_MAX)) {
/* if it's not a mass storage, we go no further */
return NULL;
}
@@ -1510,7 +1501,43 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n");
+ /* Determine subclass and protocol, or copy from the interface */
+ /* FIXME: this isn't quite right */
+ if (dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) {
+ protocol = US_PR_CB;
+ subclass = US_SC_8070; /* an assumption */
+ } else {
+ subclass = altsetting->bInterfaceSubClass;
+ protocol = altsetting->bInterfaceProtocol;
+ }
+
+ /* shuttle E-USB */
+ /* FIXME: all we should need to do here is determine the protocol */
+ if (dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) {
+ __u8 qstat[2];
+
+ result = usb_control_msg(ss->pusb_dev,
+ usb_rcvctrlpipe(dev,0),
+ 1, 0xC0,
+ 0, ss->ifnum,
+ qstat, 2, HZ*5);
+ US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
+ CBI_irq, 255, (void *)ss,
+ &ss->irq_handle);
+ if (result < 0)
+ return NULL;
+
+ /* FIXME: what is this?? */
+ down(&(ss->ip_waitq));
+ }
+
/*
+ * Find the endpoints we need
* 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.
@@ -1519,6 +1546,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* is it an BULK endpoint? */
if ((altsetting->endpoint[i].bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ /* BULK in or out? */
if (altsetting->endpoint[i].bEndpointAddress &
USB_DIR_IN)
ep_in = altsetting->endpoint[i].bEndpointAddress &
@@ -1542,36 +1570,14 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
US_DEBUGP("Result from usb_set_interface is %d\n", result);
if (result == -EPIPE) {
+ US_DEBUGP("-- clearing stall on control interface\n");
usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
} else if (result != 0) {
/* it's not a stall, but another error -- time to bail */
+ US_DEBUGP("-- unknown error. rejecting device\n");
return NULL;
}
- /* shuttle E-USB */
- /* FIXME: all we should need to do here is determine the protocol */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- __u8 qstat[2];
-
- result = usb_control_msg(ss->pusb_dev,
- usb_rcvctrlpipe(dev,0),
- 1, 0xC0,
- 0, ss->ifnum,
- qstat, 2, HZ*5);
- US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
- init_MUTEX_LOCKED(&(ss->ip_waitq));
- ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255, (void *)ss,
- &ss->irq_handle);
- if (result < 0)
- return NULL;
-
- /* FIXME: what is this?? */
- down(&(ss->ip_waitq));
- }
-
/* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
US_DEBUGP("Problems with device\n");
@@ -1638,8 +1644,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("Allocating IRQ for CBI transport\n");
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255,
- (void *)ss, &ss->irq_handle);
+ CBI_irq, 255, (void *)ss,
+ &(ss->irq_handle));
US_DEBUGP("usb_request_irq returned %d\n", result);
}
} else {
@@ -1656,23 +1662,12 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* Initialize the mutexes only when the struct is new */
init_MUTEX_LOCKED(&(ss->sleeper));
+ init_MUTEX_LOCKED(&(ss->notify));
init_MUTEX(&(ss->queue_exclusion));
- /*
- * If we've allready determined the subclass and protocol,
- * use that. Otherwise, use the interface ones. This
- * allows us to support devices which are compliant but
- * don't announce it. Note that this information is
- * maintained in the us_data struct so we only have to do
- * this for new devices.
- */
- if (subclass) {
- ss->subclass = subclass;
- ss->protocol = protocol;
- } else {
- ss->subclass = altsetting->bInterfaceSubClass;
- ss->protocol = altsetting->bInterfaceProtocol;
- }
+ /* copy over the subclass and protocol data */
+ ss->subclass = subclass;
+ ss->protocol = protocol;
/* copy over the endpoint data */
ss->ep_in = ep_in;
@@ -1762,9 +1757,9 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("Allocating IRQ for CBI transport\n");
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255,
- (void *)ss, &ss->irq_handle);
- US_DEBUGP("usb_request_irq returned %d", result);
+ CBI_irq, 255, (void *)ss,
+ &(ss->irq_handle));
+ US_DEBUGP("usb_request_irq returned %d\n", result);
}
/*
@@ -1786,23 +1781,18 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
(struct us_data *)ss->htmplt.proc_dir = ss;
/* start up our thread */
- {
- DECLARE_MUTEX_LOCKED(sem);
-
- ss->notify = &sem;
- ss->pid = kernel_thread(usb_stor_control_thread, ss,
- CLONE_FS | CLONE_FILES |
- CLONE_SIGHAND);
- if (ss->pid < 0) {
- printk(KERN_WARNING USB_STORAGE
- "Unable to start control thread\n");
- kfree(ss);
- return NULL;
- }
-
- /* wait for it to start */
- down(&sem);
+ ss->pid = kernel_thread(usb_stor_control_thread, ss,
+ CLONE_FS | CLONE_FILES |
+ CLONE_SIGHAND);
+ if (ss->pid < 0) {
+ printk(KERN_WARNING USB_STORAGE
+ "Unable to start control thread\n");
+ kfree(ss);
+ return NULL;
}
+
+ /* wait for it to start */
+ down(&(ss->notify));
/* now register - our detect function will be called */
ss->htmplt.module = &__this_module;
@@ -1829,18 +1819,26 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
static void storage_disconnect(struct usb_device *dev, void *ptr)
{
struct us_data *ss = ptr;
+ int result;
- if (!ss)
+ US_DEBUGP("storage_disconnect() called\n");
+
+ /* this is the odd case -- we disconnected but weren't using it */
+ if (!ss) {
+ US_DEBUGP("-- device was not in use\n");
return;
-
- /* FIXME: we need mututal exclusion and resource freeing here */
+ }
/* release the IRQ, if we have one */
if (ss->irq_handle) {
- usb_release_irq(ss->pusb_dev, ss->irq_handle, ss->irqpipe);
+ US_DEBUGP("-- releasing irq handle\n");
+ result = usb_release_irq(ss->pusb_dev, ss->irq_handle,
+ ss->irqpipe);
+ US_DEBUGP("-- usb_release_irq() returned %d\n", result);
ss->irq_handle = NULL;
}
+ /* mark the device as gone */
ss->pusb_dev = NULL;
}
@@ -1851,11 +1849,16 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
int __init usb_stor_init(void)
{
+ /*
+ * Check to see if the host template is a different size from
+ * what we're expected -- people have updated this in the past
+ * and forgotten about this driver.
+ */
if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
- printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ;
- printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n",
+ printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE bad\n");
+ printk(KERN_ERR
+ "usb-storage: expected %d bytes, got %d bytes\n",
SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
-
return -1 ;
}
@@ -1863,6 +1866,7 @@ int __init usb_stor_init(void)
if (usb_register(&storage_driver) < 0)
return -1;
+ /* we're all set */
printk(KERN_INFO "USB Mass Storage support registered.\n");
return 0;
}
@@ -1870,17 +1874,35 @@ int __init usb_stor_init(void)
void __exit usb_stor_exit(void)
{
static struct us_data *ptr;
-
+ static struct us_data *next;
+ unsigned long flags;
+
+ /*
+ * deregister the driver -- this eliminates races with probes and
+ * disconnects
+ */
+ usb_deregister(&storage_driver) ;
+
+ /* lock access to the data structures */
+ spin_lock_irqsave(&us_list_spinlock, flags);
+
/* unregister all the virtual hosts */
for (ptr = us_list; ptr != NULL; ptr = ptr->next)
- scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
-
- /* free up the data structures */
-
+ scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
+
/* kill the threads */
+ /* FIXME: we can do this by sending them a signal to die */
- /* deregister the driver */
- usb_deregister(&storage_driver) ;
+ /* free up the data structures */
+ /* FIXME: we need to eliminate the host structure also */
+ while (ptr) {
+ next = ptr->next;
+ kfree(ptr);
+ ptr = next;
+ }
+
+ /* unlock the data structures */
+ spin_unlock_irqrestore(&us_list_spinlock, flags);
}
module_init(usb_stor_init) ;
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 5dbde2959..f77296d7f 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -1002,8 +1002,11 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
urb_priv = urb->hcpriv;
switch (usb_pipetype (urb->pipe)) {
- case PIPE_ISOCHRONOUS:
+
case PIPE_INTERRUPT:
+ usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+ case PIPE_ISOCHRONOUS:
uhci_clean_iso_step1(s, urb_priv);
uhci_wait_ms(1);
uhci_clean_iso_step2(s, urb_priv);
@@ -1131,8 +1134,10 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
urb_priv = (urb_priv_t*)urb->hcpriv;
switch (usb_pipetype (urb->pipe)) {
- case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
+ usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+ case PIPE_ISOCHRONOUS:
uhci_clean_iso_step1 (s, urb_priv);
break;
@@ -1617,8 +1622,8 @@ _static __u8 root_hub_dev_des[] =
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
- 0x00, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
@@ -1915,8 +1920,14 @@ _static int rh_submit_urb (urb_t *urb)
len = min (leni, min (sizeof (root_hub_config_des), wLength));
memcpy (data, root_hub_config_des, len);
OK (len);
- case (0x03): /*string descriptors */
- stat = -EPIPE;
+ case (0x03): /* string descriptors */
+ len = usb_root_hub_string (wValue & 0xff,
+ uhci->io_addr, "UHCI",
+ data, wLength);
+ if (len > 0) {
+ OK (min (leni, len));
+ } else
+ stat = -EPIPE;
}
break;
@@ -2597,6 +2608,15 @@ _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_add
uhci_t *s;
struct usb_bus *bus;
struct pm_dev *pmdev;
+ char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+ sprintf(buf, "%d", irq);
+#else
+ bufp = __irq_itoa(irq);
+#endif
+ printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+ io_addr, bufp);
s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
if (!s)
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index df8fe9b38..9b2d38b6f 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -1184,6 +1184,54 @@ void usb_init_root_hub(struct usb_device *dev)
dev->actconfig = NULL;
}
+/* for returning string descriptors in UTF-16LE */
+static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+{
+ int retval;
+
+ for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+ *utf++ = *ascii++ & 0x7f;
+ *utf++ = 0;
+ }
+ return retval;
+}
+
+/*
+ * root_hub_string is used by each host controller's root hub code,
+ * so that they're identified consistently throughout the system.
+ */
+int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+ char buf [20];
+
+ // assert (len > (2 * (sizeof (buf) + 1)));
+ // assert (strlen (type) ~== 4);
+
+ // language ids
+ if (id == 0) {
+ *data++ = 4; *data++ = 3; /* 4 bytes data */
+ *data++ = 0; *data++ = 0; /* some language id */
+ return 4;
+
+ // serial number
+ } else if (id == 1) {
+ sprintf (buf, "%x", serial);
+
+ // product description
+ } else if (id == 2) {
+ sprintf (buf, "USB %s Root Hub", type);
+
+ // id 3 == vendor description
+
+ // unsupported IDs --> "stall"
+ } else
+ return 0;
+
+ data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+ data [1] = 3;
+ return data [0];
+}
+
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the
* extra field of the interface and endpoint descriptor structs.
@@ -1824,6 +1872,7 @@ EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_init_root_hub);
+EXPORT_SYMBOL(usb_root_hub_string);
EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
diff --git a/drivers/usb/wacom.c b/drivers/usb/wacom.c
index 6dc9ab480..cb77f0717 100644
--- a/drivers/usb/wacom.c
+++ b/drivers/usb/wacom.c
@@ -1,5 +1,5 @@
/*
- * wacom.c Version 0.4
+ * wacom.c Version 0.5
*
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
@@ -14,8 +14,10 @@
* v0.1 (vp) - Initial release
* v0.2 (aba) - Support for all buttons / combinations
* v0.3 (vp) - Support for Intuos added
- * v0.4 (sm) - Support for more Intuos models, menustrip,
- * relative mode, proximity.
+ * v0.4 (sm) - Support for more Intuos models, menustrip
+ * relative mode, proximity.
+ * v0.5 (vp) - Big cleanup, nifty features removed,
+ * they belong in userspace
*/
/*
@@ -50,16 +52,14 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
/*
* Wacom Graphire packet:
*
- * The input report:
- *
* byte 0: report ID (2)
- * byte 1: bit7 mouse/pen/rubber near
- * bit5-6 0 - pen, 1 - rubber, 2 - mouse
- * bit4 1 ?
- * bit3 0 ?
- * bit2 mouse middle button / pen button2
- * bit1 mouse right button / pen button1
- * bit0 mouse left button / pen tip / rubber
+ * byte 1: bit7 pointer in range
+ * bit5-6 pointer type 0 - pen, 1 - rubber, 2 - mouse
+ * bit4 1 ?
+ * bit3 0 ?
+ * bit2 mouse middle button / pen button2
+ * bit1 mouse right button / pen button1
+ * bit0 mouse left button / touch
* byte 2: X low bits
* byte 3: X high bits
* byte 4: Y low bits
@@ -69,115 +69,58 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
*
* There are also two single-byte feature reports (2 and 3).
*
- * Resolution:
- * X: 0 - 10206
- * Y: 0 - 7422
- *
- * (0,0) is upper left corner
- *
- * Wacom Intuos Status packet:
+ * Wacom Intuos status packet:
*
- * byte 0: report ID (2)
- * byte 1: bit7 1 (Sync Byte)
- * bit6 Pointer Near
- * bit5 0 - first proximity report
- * bit4 0 ?
- * bit3 0 ?
- * bit2 pen button2
- * bit1 pen button1
- * bit0 0 ?
- * byte 2: X high bits
- * byte 3: X low bits
- * byte 4: Y high bits
- * byte 5: Y low bits
- * byte 6: bits 0-7: pressure (bits 2-9)
- * byte 7: bits 6-7: pressure (bits 0-1)
- * byte 7: bits 0-5: X tilt (bits 1-6)
- * byte 8: bit 7: X tilt (bit 0)
- * byte 8: bits 0-6: Y tilt (bits 0-6)
- * byte 9: bits 4-7: Proximity
+ * byte 0: report ID (2)
+ * byte 1: bit7 1 - sync bit
+ * bit6 pointer in range
+ * bit5 pointer type report
+ * bit4 0 ?
+ * bit3 0 ?
+ * bit2 pen button2
+ * bit1 pen button1
+ * bit0 0 ?
+ * byte 2: X high bits
+ * byte 3: X low bits
+ * byte 4: Y high bits
+ * byte 5: Y low bits
+ * byte 6: bits 0-7: pressure (bits 2-9)
+ * byte 7: bits 6-7: pressure (bits 0-1)
+ * byte 7: bits 0-5: X tilt (bits 1-6)
+ * byte 8: bit 7: X tilt (bit 0)
+ * byte 8: bits 0-6: Y tilt (bits 0-6)
+ * byte 9: bits 4-7: distance
*/
-#define USB_VENDOR_ID_WACOM 0x056a
-#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS45 0x0020 /* Guess */
-#define USB_DEVICE_ID_WACOM_INTUOS68 0x0021
-#define USB_DEVICE_ID_WACOM_INTUOS912 0x0022 /* Guess */
-#define USB_DEVICE_ID_WACOM_INTUOS1212 0x0023
-#define USB_DEVICE_ID_WACOM_INTUOS1218 0x0024 /* Guess */
-
-#define USB_TOOL_ID_WACOM_PEN 0x0022
-#define USB_TOOL_ID_WACOM_ERASER 0x00fa
-#define USB_TOOL_ID_WACOM_STROKE_PEN 0x0032
-#define USB_TOOL_ID_WACOM_INKING_PEN 0x0012
-#define USB_TOOL_ID_WACOM_AIRBRUSH 0x0112
-#define USB_TOOL_ID_WACOM_MOUSE4D 0x0094
-#define USB_TOOL_ID_WACOM_LENS_CURSOR 0x0096
-
-#define INTUOS_PEN_MODE_ABS 0x00
-#define INTUOS_PEN_MODE_REL 0x01
-#define INTUOS_PEN_MODE_QUICKPOINT 0x02
-
-#define INTUOS_PRESSURE_MODE_SOFT 0x00
-#define INTUOS_PRESSURE_MODE_MED 0x01
-#define INTUOS_PRESSURE_MODE_FIRM 0x02
-
-#define INTUOS_MENUSTRIP_Y_ZONE 1400
-#define INTUOS_MENUSTRIP_BTN_YMIN 270
-#define INTUOS_MENUSTRIP_BTN_YMAX 1070
-#define INTUOS_MENUSTRIP_F1_XMIN 40
-#define INTUOS_MENUSTRIP_F7_XMIN 8340
-#define INTUOS_MENUSTRIP_F12_XMIN 15300
-
-#define INTUOS_MENUSTRIP_BTN_WIDTH 1300
-
-#define INTUOS_MENUSTRIP_F7_IX_OFFSET 6 /* offset into wacom_fkeys */
-#define INTUOS_MENUSTRIP_F12_IX_OFFSET 11
+#define USB_VENDOR_ID_WACOM 0x056a
+
+struct wacom_features {
+ char *name;
+ int idProduct;
+ int pktlen;
+ int x_max;
+ int y_max;
+ int pressure_max;
+ int distance_max;
+ void (*irq)(struct urb *urb);
+ unsigned long evbit;
+ unsigned long relbit;
+ unsigned long absbit;
+ unsigned long btnbit;
+ unsigned long digibit;
+};
struct wacom {
- signed char data[10];
+ signed char data[10];
struct input_dev dev;
struct urb irq;
-
- int last_x, last_y;
- unsigned int tool, device;
- unsigned int ymax, menustrip_touch;
- unsigned int pen_mode;
- unsigned int pressure_mode;
+ struct wacom_features *features;
+ int tool;
};
-static int wacom_fkeys[16] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4,
- KEY_F5, KEY_F6, KEY_F7, KEY_F8,
- KEY_F9, KEY_F10, KEY_F11, KEY_F12,
- KEY_F13, KEY_F14, KEY_F15, KEY_F16};
-
-#define INTUOS_EXTENTS_MAX_X 0x00
-#define INTUOS_EXTENTS_MAX_Y 0x01
-#define INTUOS_EXTENTS_HAS_F7 0x02
-#define INTUOS_EXTENTS_HAS_F12 0x03
-#define INTUOS_EXTENTS_PEN_MODE 0x04
-#define INTUOS_EXTENTS_HAS_QUICKPOINT 0x05
-#define INTUOS_EXTENTS_HAS_PRESSURE_MODE 0x06
-#define INTUOS_EXTENTS_PRESSURE_MODE 0x07
-
-#define WACOM_TRUE 1
-#define WACOM_FALSE 0
-
-static int intuos_extents[5][8] = {
- { 12700, 10360, WACOM_FALSE, WACOM_FALSE, 8340, WACOM_FALSE, WACOM_FALSE, 0}, /* Intuos 4x5 */
- { 20320, 15040, WACOM_TRUE, WACOM_FALSE, 15300, WACOM_FALSE, WACOM_TRUE, 18360}, /* Intuos 6x8 */
- { 30480, 23060, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 9x12 */
- { 30480, 30480, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 12x12 */
- { 47720, 30480, WACOM_TRUE, WACOM_TRUE, 29260, WACOM_TRUE, WACOM_TRUE, 33620}}; /* Intuos 12x18 */
-
-static char intuos_names[5][12] = {
- {"Intuos 4x5 "}, {"Intuos 6x8 "},
- {"Intuos 9x12 "}, {"Intuos 12x12"},
- {"Intuos 12x18"}};
-
static void wacom_graphire_irq(struct urb *urb)
{
- struct wacom *wacom = urb->context;
+ struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
@@ -186,285 +129,135 @@ static void wacom_graphire_irq(struct urb *urb)
if (data[0] != 2)
dbg("received unknown report #%d", data[0]);
- if ( data[1] & 0x80 ) {
- input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
- input_report_abs(dev, ABS_Y, 7422 - (data[4] | ((__u32)data[5] << 8)));
+ if ( data[1] & 0x80 ) {
+ input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
+ input_report_abs(dev, ABS_Y, data[4] | ((__u32)data[5] << 8));
}
switch ((data[1] >> 5) & 3) {
- case 0: /* Pen */
- input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80);
- input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
- break;
-
- case 1: /* Rubber */
- input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
- input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
- break;
-
- case 2: /* Mouse */
- input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24);
- input_report_btn(dev, BTN_LEFT, data[1] & 0x01);
- input_report_btn(dev, BTN_RIGHT, data[1] & 0x02);
- input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04);
- input_report_abs(dev, ABS_DISTANCE, data[7]);
- input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
- break;
- }
-}
+ case 0: /* Pen */
+ input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80);
+ break;
-static void intuos_menustrip( unsigned int x, unsigned int y, struct wacom *wacom )
-{
- struct input_dev *dev = &wacom->dev;
- unsigned int local_x = x;
- unsigned int local_y = y - ( wacom->ymax - INTUOS_MENUSTRIP_Y_ZONE );
- unsigned int fkey_index ;
-
- /* Ensure we are in the vertical strip for the buttons */
- if ( (local_y > INTUOS_MENUSTRIP_BTN_YMIN) && (local_y < INTUOS_MENUSTRIP_BTN_YMAX) ) {
-
- /* Handle Pressure Mode */
- if ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_PRESSURE_MODE] ) {
- int pressure_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PRESSURE_MODE])
- / INTUOS_MENUSTRIP_BTN_WIDTH );
- if ( ( pressure_mode >= INTUOS_PRESSURE_MODE_SOFT ) &&
- ( pressure_mode <= INTUOS_PRESSURE_MODE_FIRM ) ) {
- wacom->pressure_mode = pressure_mode;
- return;
- }
- }
-
- /* Handle Pen Mode */
- {
- int pen_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PEN_MODE])
- / INTUOS_MENUSTRIP_BTN_WIDTH );
- if ( ( pen_mode == INTUOS_PEN_MODE_ABS ) ||
- ( pen_mode == INTUOS_PEN_MODE_REL ) ||
- ( ( pen_mode == INTUOS_PEN_MODE_QUICKPOINT ) &&
- ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_QUICKPOINT] ) ) ) {
- wacom->pen_mode = pen_mode;
- return;
- }
- }
-
- /* Handle Function Keys */
- if ( local_x > INTUOS_MENUSTRIP_F12_XMIN ) {
- fkey_index = INTUOS_MENUSTRIP_F12_IX_OFFSET
- + ( (local_x - INTUOS_MENUSTRIP_F12_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
- fkey_index = ( fkey_index > 16 ) ? 16 : fkey_index; /* Ensure in range */
- }
- else if ( local_x > INTUOS_MENUSTRIP_F7_XMIN ) {
- fkey_index = INTUOS_MENUSTRIP_F7_IX_OFFSET
- + ( (local_x - INTUOS_MENUSTRIP_F7_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
- fkey_index = ( fkey_index > 11 ) ? 11 : fkey_index;
- }
- else {
- fkey_index = ( (local_x - INTUOS_MENUSTRIP_F1_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
- fkey_index = ( fkey_index > 6 ) ? 6 : fkey_index;
- }
- input_report_key(dev, wacom_fkeys[fkey_index], 1);
- input_report_key(dev, wacom_fkeys[fkey_index], 0);
+ case 1: /* Rubber */
+ input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
+ break;
- return;
+ case 2: /* Mouse */
+ input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24);
+ input_report_btn(dev, BTN_LEFT, data[1] & 0x01);
+ input_report_btn(dev, BTN_RIGHT, data[1] & 0x02);
+ input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04);
+ input_report_abs(dev, ABS_DISTANCE, data[7]);
+ input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+ return;
}
+
+ input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+
+ input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
+ input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
+ input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
}
-
+
static void wacom_intuos_irq(struct urb *urb)
{
- struct wacom *wacom = urb->context;
+ struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
unsigned int t;
- int x, y;
if (urb->status) return;
if (data[0] != 2)
dbg("received unknown report #%d", data[0]);
- if ( ((data[1] >> 5) & 0x3) == 0x2 ) /* First record, feature report */
- {
- wacom->tool = (((char)data[2] << 4) | (char)data[3] >> 4) & 0xff ;
- /* Report tool type */
- switch ( wacom->tool ) {
- case USB_TOOL_ID_WACOM_PEN:
- input_report_btn(dev, BTN_TOOL_PEN, 1);
- break;
- case USB_TOOL_ID_WACOM_ERASER:
- input_report_btn(dev, BTN_TOOL_RUBBER, 1);
- break;
- case USB_TOOL_ID_WACOM_STROKE_PEN:
- input_report_btn(dev, BTN_TOOL_BRUSH, 1);
- break;
- case USB_TOOL_ID_WACOM_INKING_PEN:
- input_report_btn(dev, BTN_TOOL_PENCIL, 1);
- break;
- case USB_TOOL_ID_WACOM_AIRBRUSH:
- input_report_btn(dev, BTN_TOOL_AIRBRUSH, 1);
- break;
- case USB_TOOL_ID_WACOM_MOUSE4D:
- case USB_TOOL_ID_WACOM_LENS_CURSOR:
- input_report_btn(dev, BTN_TOOL_MOUSE, 1);
- break;
- default:
- break;
- }
- return;
- }
-
- if ( ( data[1] | data[2] | data[3] | data[4] | data[5] | data[6]
- | data[7] | data[8] | data[9] ) == 0x80 ) { /* exit report */
- switch ( wacom->tool ) {
- case USB_TOOL_ID_WACOM_PEN:
- input_report_btn(dev, BTN_TOOL_PEN, 0);
- break;
- case USB_TOOL_ID_WACOM_ERASER:
- input_report_btn(dev, BTN_TOOL_RUBBER, 0);
- break;
- case USB_TOOL_ID_WACOM_STROKE_PEN:
- input_report_btn(dev, BTN_TOOL_BRUSH, 0);
- break;
- case USB_TOOL_ID_WACOM_INKING_PEN:
- input_report_btn(dev, BTN_TOOL_PENCIL, 0);
- break;
- case USB_TOOL_ID_WACOM_AIRBRUSH:
- input_report_btn(dev, BTN_TOOL_AIRBRUSH, 0);
- break;
- case USB_TOOL_ID_WACOM_MOUSE4D:
- case USB_TOOL_ID_WACOM_LENS_CURSOR:
- input_report_btn(dev, BTN_TOOL_MOUSE, 0);
- break;
- default:
- break;
+ if (((data[1] >> 5) & 0x3) == 0x2) { /* Enter report */
+
+ switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
+ case 0x012: wacom->tool = BTN_TOOL_PENCIL; break; /* Inking pen */
+ case 0x022: wacom->tool = BTN_TOOL_PEN; break; /* Pen */
+ case 0x032: wacom->tool = BTN_TOOL_BRUSH; break; /* Stroke pen */
+ case 0x094: wacom->tool = BTN_TOOL_MOUSE; break; /* Mouse 4D */
+ case 0x096: wacom->tool = BTN_TOOL_LENS; break; /* Lens cursor */
+ case 0x0fa: wacom->tool = BTN_TOOL_RUBBER; break; /* Eraser */
+ case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH; break; /* Airbrush */
+ default: wacom->tool = BTN_TOOL_PEN; break; /* Unknown tool */
}
+ input_report_btn(dev, wacom->tool, 1);
return;
}
- x = (((unsigned int) data[2]) << 8) | data[3] ;
- y = wacom->dev.absmax[ABS_Y] - ((((unsigned int) data[4]) << 8) | data[5]);
-
- t = (((unsigned int) data[6]) << 2) | ((data[7] & 0xC0) >> 6);
-
- /* Handle touch near menustrip */
- if ( y > ( wacom->dev.absmax[ABS_Y] - INTUOS_MENUSTRIP_Y_ZONE ) ) {
- if ( t > 10 ) /* Touch */
- wacom->menustrip_touch = 1;
- if ( (wacom->menustrip_touch) && (t <= 10) ) { /* Pen Up */
- intuos_menustrip( x, y, wacom );
- wacom->menustrip_touch = 0;
- }
+ if ((data[1] | data[2] | data[3] | data[4] | data[5] |
+ data[6] | data[7] | data[8] | data[9]) == 0x80) { /* Exit report */
+ input_report_btn(dev, wacom->tool, 0);
return;
}
- else
- wacom->menustrip_touch = 0;
-
- switch ( wacom->pen_mode ) {
- case INTUOS_PEN_MODE_ABS:
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
- break;
- case INTUOS_PEN_MODE_REL:
- input_report_rel(dev, REL_X, ( x - wacom->last_x) / 8 );
- input_report_rel(dev, REL_Y, - ( y - wacom->last_y) / 8 );
- break;
- default: break;
- }
-
- wacom->last_x = x;
- wacom->last_y = y;
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
-
- input_report_btn(dev, BTN_TOUCH, t > 10);
- input_report_abs(dev, ABS_PRESSURE, t);
-
- input_report_abs(dev, ABS_DISTANCE, ( data[9] & 0xf0 ) >> 4 );
-
- input_report_abs(dev, ABS_TILT_X, ((((unsigned int) data[7]) & 0x3f) << 1) | ((data[8] & 0x80) >> 7));
+ input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
+ input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
+ input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+ input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
+ input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+ input_report_btn(dev, BTN_STYLUS, data[1] & 2);
+ input_report_btn(dev, BTN_STYLUS2, data[1] & 4);
+ input_report_btn(dev, BTN_TOUCH, t > 10);
}
+#define WACOM_INTUOS_TOOLS (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
+
+struct wacom_features wacom_features[] = {
+ { "Graphire", 0x10, 8, 10206, 7422, 511, 32, wacom_graphire_irq,
+ BIT(EV_REL), 0, BIT(REL_WHEEL), BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE), 0 },
+ { "Intuos 4x5", 0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 6x8", 0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 9x12", 0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { NULL , 0 }
+};
+
static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_endpoint_descriptor *endpoint;
struct wacom *wacom;
- char *name;
+ int i;
- if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM ||
- (dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_GRAPHIRE &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS45 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS68 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS912 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1212 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1218))
- return NULL;
+ if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM) return NULL;
+ for (i = 0; wacom_features[i].idProduct && wacom_features[i].idProduct != dev->descriptor.idProduct; i++);
+ if (!wacom_features[i].idProduct) return NULL;
endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
memset(wacom, 0, sizeof(struct wacom));
- if ( dev->descriptor.idProduct == USB_DEVICE_ID_WACOM_GRAPHIRE ) {
- wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
- wacom->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
- wacom->dev.relbit[0] |= BIT(REL_WHEEL);
- wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
-
- wacom->dev.absmax[ABS_X] = 10206;
- wacom->dev.absmax[ABS_Y] = 7422;
- wacom->dev.absmax[ABS_PRESSURE] = 511;
- wacom->dev.absmax[ABS_DISTANCE] = 32;
-
- FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, 8, wacom_graphire_irq, wacom, endpoint->bInterval);
-
- name = "Graphire";
- }
- else { /* Intuos */
-
- wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
- wacom->dev.keybit[LONG(KEY_F1)] |= BIT(KEY_F1) | BIT(KEY_F2) | BIT(KEY_F3) | BIT(KEY_F4) | BIT(KEY_F5);
- wacom->dev.keybit[LONG(KEY_F6)] |= BIT(KEY_F6) | BIT(KEY_F7) | BIT(KEY_F8);
- wacom->dev.keybit[LONG(KEY_F9)] |= BIT(KEY_F9) | BIT(KEY_F10) | BIT(KEY_F11) | BIT(KEY_F12);
- wacom->dev.keybit[LONG(KEY_F13)] |= BIT(KEY_F13) | BIT(KEY_F14) | BIT(KEY_F15) | BIT(KEY_F16);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_BRUSH);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_MOUSE);
- wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
- wacom->dev.absbit[0] |= BIT(ABS_TILT_X) | BIT(ABS_TILT_Y);
- wacom->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
-
- wacom->dev.absmax[ABS_PRESSURE] = 1023;
- wacom->dev.absmax[ABS_DISTANCE] = 15;
- wacom->dev.absmax[ABS_TILT_X] = 127;
- wacom->dev.absmax[ABS_TILT_Y] = 127;
-
- wacom->device = dev->descriptor.idProduct - USB_DEVICE_ID_WACOM_INTUOS45;
+ wacom->features = wacom_features + i;
- wacom->dev.absmax[ABS_X] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_X];
- wacom->dev.absmax[ABS_Y] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y];
+ wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | wacom->features->evbit;
+ wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | wacom->features->absbit;
+ wacom->dev.relbit[0] |= wacom->features->relbit;
+ wacom->dev.keybit[LONG(BTN_LEFT)] |= wacom->features->btnbit;
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) |
+ BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | wacom->features->digibit;
- wacom->ymax = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y];
- wacom->pen_mode = INTUOS_PEN_MODE_ABS;
- wacom->pressure_mode = INTUOS_PRESSURE_MODE_SOFT;
+ wacom->dev.absmax[ABS_X] = wacom->features->x_max;
+ wacom->dev.absmax[ABS_Y] = wacom->features->y_max;
+ wacom->dev.absmax[ABS_PRESSURE] = wacom->features->pressure_max;
+ wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max;
+ wacom->dev.absmax[ABS_TILT_X] = 127;
+ wacom->dev.absmax[ABS_TILT_Y] = 127;
- name = intuos_names[wacom->device];
-
- FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, 10, wacom_intuos_irq, wacom, endpoint->bInterval);
-
- }
+ FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
if (usb_submit_urb(&wacom->irq)) {
kfree(wacom);
@@ -473,7 +266,7 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
input_register_device(&wacom->dev);
- printk(KERN_INFO "input%d: Wacom %s\n", wacom->dev.number, name);
+ printk(KERN_INFO "input%d: Wacom %s on usb%d\n", wacom->dev.number, wacom->features->name, dev->devnum);
return wacom;
}
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 12918c1b5..49125330f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -16,7 +16,8 @@ M_OBJS :=
# All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
-export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o fbcon-afb.o fbcon-ilbm.o \
+export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \
+ fbcon-afb.o fbcon-ilbm.o \
fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
@@ -46,6 +47,7 @@ obj-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
obj-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o fbmon.o
+obj-$(CONFIG_FB_COMPAT_XPMAC) += macmodes.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_AMIGA) += amifb.o
@@ -64,9 +66,9 @@ obj-$(CONFIG_FB_CYBER) += cyberfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_SGIVW) += sgivwfb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
-obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o
+obj-$(CONFIG_FB_MAC) += macfb.o
obj-$(CONFIG_FB_HP300) += hpfb.o
-obj-$(CONFIG_FB_OF) += offb.o macmodes.o
+obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
obj-$(CONFIG_FB_CLGEN) += clgenfb.o fbgen.o
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 97df72fd2..a0518c009 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1765,37 +1765,11 @@ default_chipset:
fb_info.flags = FBINFO_FLAG_DEFAULT;
memset(&var, 0, sizeof(var));
-#ifdef MODULE
- var.xres = ami_modedb[defmode].xres;
- var.yres = ami_modedb[defmode].yres;
- var.xres_virtual = ami_modedb[defmode].xres;
- var.yres_virtual = ami_modedb[defmode].yres;
- var.xoffset = 0;
- var.yoffset = 0;
- var.bits_per_pixel = 4;
- var.activate |= FB_ACTIVATE_TEST;
- var.pixclock = ami_modedb[defmode].pixclock;
- var.left_margin = ami_modedb[defmode].left_margin;
- var.right_margin = ami_modedb[defmode].right_margin;
- var.upper_margin = ami_modedb[defmode].upper_margin;
- var.lower_margin = ami_modedb[defmode].lower_margin;
- var.hsync_len = ami_modedb[defmode].hsync_len;
- var.vsync_len = ami_modedb[defmode].vsync_len;
- var.sync = ami_modedb[defmode].sync;
- var.vmode = ami_modedb[defmode].vmode;
- err = fb_info.fbops->fb_set_var(&var, -1, &fb_info);
- var.activate &= ~FB_ACTIVATE_TEST;
- if (err) {
- err = -EINVAL;
- goto amifb_error;
- }
-#else
if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
err = -EINVAL;
goto amifb_error;
}
-#endif
round_down_bpp = 0;
chipptr = chipalloc(videomemorysize+
diff --git a/drivers/video/cgthreefb.c b/drivers/video/cgthreefb.c
index 5e4d45a9e..9cec20abf 100644
--- a/drivers/video/cgthreefb.c
+++ b/drivers/video/cgthreefb.c
@@ -1,4 +1,4 @@
-/* $Id: cgthreefb.c,v 1.8 1999/11/19 09:57:08 davem Exp $
+/* $Id: cgthreefb.c,v 1.9 2000/03/19 04:20:44 anton Exp $
* cgthreefb.c: CGthree frame buffer driver
*
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -114,9 +114,9 @@ static void cg3_blank (struct fb_info_sbusfb *fb)
u8 tmp;
spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.cg3.regs->control);
+ tmp = sbus_readb(&fb->s.cg3.regs->control);
tmp &= ~CG3_CR_ENABLE_VIDEO;
- sbus_writel(tmp, &fb->s.cg3.regs->control);
+ sbus_writeb(tmp, &fb->s.cg3.regs->control);
spin_unlock_irqrestore(&fb->lock, flags);
}
@@ -126,9 +126,9 @@ static void cg3_unblank (struct fb_info_sbusfb *fb)
u8 tmp;
spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.cg3.regs->control);
+ tmp = sbus_readb(&fb->s.cg3.regs->control);
tmp |= CG3_CR_ENABLE_VIDEO;
- sbus_writel(tmp, &fb->s.cg3.regs->control);
+ sbus_writeb(tmp, &fb->s.cg3.regs->control);
spin_unlock_irqrestore(&fb->lock, flags);
}
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index e71f36e50..98bcf32d8 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -3,15 +3,22 @@
*
* Copyright (C) 1998 Geert Uytterhoeven
*
+ * 2000 - Removal of OpenFirmware dependencies by:
+ * - Ani Joshi
+ * - Brad Douglas <brad@neruo.com>
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
-#include <linux/tty.h>
+#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/string.h>
+#include <asm/vc_ioctl.h>
+
+#include <video/fbcon.h>
#include <video/macmodes.h>
@@ -181,6 +188,107 @@ static const struct monitor_map {
{ -1, VMODE_640_480_60 }, /* catch-all, must be last */
};
+struct fb_info *console_fb_info = NULL;
+struct vc_mode display_info;
+static u16 palette_red[16];
+static u16 palette_green[16];
+static u16 palette_blue[16];
+static struct fb_cmap palette_cmap = {
+ 0, 16, palette_red, palette_green, palette_blue, NULL
+};
+
+
+int console_getmode(struct vc_mode *);
+int console_setmode(struct vc_mode *, int);
+int console_setcmap(int, unsigned char *, unsigned char *, unsigned char *);
+int console_powermode(int);
+int mac_var_to_vmode(const struct fb_var_screeninfo *, int *, int *);
+
+
+int console_getmode(struct vc_mode *mode)
+{
+ *mode = display_info;
+ return 0;
+}
+
+
+int console_setmode(struct vc_mode *mode, int doit)
+{
+ struct fb_var_screeninfo var;
+ int cmode, err;
+
+ if (!console_fb_info)
+ return -EOPNOTSUPP;
+
+ switch(mode->depth) {
+ case 0:
+ case 8:
+ cmode = CMODE_8;
+ break;
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ cmode = CMODE_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((err = mac_vmode_to_var(mode->mode, cmode, &var)))
+ return err;
+
+ var.activate = FB_ACTIVATE_TEST;
+ err = console_fb_info->fbops->fb_set_var(&var, fg_console,
+ console_fb_info);
+ if (err || !doit)
+ return err;
+ else {
+ int unit;
+
+ var.activate = FB_ACTIVATE_NOW;
+ for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
+ if (fb_display[unit].conp &&
+ (GET_FB_IDX(console_fb_info->node) == con2fb_map[unit]))
+ console_fb_info->fbops->fb_set_var(&var, unit,
+ console_fb_info);
+ }
+
+ return 0;
+}
+
+
+int console_setcmap(int n_entries, unsigned char *red, unsigned char *green,
+ unsigned char *blue)
+{
+ int i, j, n = 0, err;
+
+ if (!console_fb_info)
+ return -EOPNOTSUPP;
+
+ for (i = 0; i < n_entries; i += n) {
+ n = n_entries - i;
+ if (n > 16)
+ n = 16;
+ palette_cmap.start = 1;
+ palette_cmap.len = n;
+
+ for (j = 0; j < n; j++) {
+ palette_cmap.red[j] = (red[i+j] << 8) | red[i+j];
+ palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
+ palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j];
+ }
+ err = console_fb_info->fbops->fb_set_cmap(&palette_cmap, 1,
+ fg_console,
+ console_fb_info);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
/*
* Convert a MacOS vmode/cmode pair to a frame buffer video mode structure
@@ -255,6 +363,17 @@ int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var)
}
+int console_powermode(int mode)
+{
+ if (mode == VC_POWERMODE_INQUIRY)
+ return 0;
+ if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
+ return -EINVAL;
+ /* Not Supported */
+ return -ENXIO;
+}
+
+
/*
* Convert a frame buffer video mode structure to a MacOS vmode/cmode pair
*/
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 404c646f5..e33b8fdd7 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -8,6 +8,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/console_struct.h>
@@ -253,7 +254,7 @@ static int __init my_atoi(const char *name)
}
}
-static int __init PROC_CONSOLE(const struct fb_info *info)
+static int PROC_CONSOLE(const struct fb_info *info)
{
int fgc;
@@ -275,8 +276,8 @@ static int __init PROC_CONSOLE(const struct fb_info *info)
return MINOR(current->tty->device) - 1;
}
-static int __init try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
- const struct fb_videomode *mode, unsigned int bpp)
+int __fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+ const struct fb_videomode *mode, unsigned int bpp)
{
int err;
@@ -391,20 +392,22 @@ done:
if ((name_matches(db[j], name, namelen) ||
(res_specified && res_matches(db[j], xres, yres))) &&
(!i || db[j].refresh == refresh) &&
- try_mode(var, info, &db[j], bpp))
+ __fb_try_mode(var, info, &db[j], bpp))
return 2-i;
}
}
DPRINTK("Trying default video mode\n");
- if (try_mode(var, info, default_mode, default_bpp))
+ if (__fb_try_mode(var, info, default_mode, default_bpp))
return 3;
DPRINTK("Trying all modes\n");
for (i = 0; i < dbsize; i++)
- if (try_mode(var, info, &db[i], default_bpp))
+ if (__fb_try_mode(var, info, &db[i], default_bpp))
return 4;
DPRINTK("No valid mode found\n");
return 0;
}
+
+EXPORT_SYMBOL(__fb_try_mode);
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index f734c4f9f..d3a609d35 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -94,15 +94,6 @@ static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, int con, struct fb_info *info);
-#ifdef CONFIG_FB_COMPAT_XPMAC
-int console_getmode(struct vc_mode *);
-int console_setmode(struct vc_mode *, int);
-int console_setcmap(int, unsigned char *, unsigned char *, unsigned char *);
-int console_powermode(int);
-struct fb_info *console_fb_info = NULL;
-struct vc_mode display_info;
-#endif /* CONFIG_FB_COMPAT_XPMAC */
-
extern boot_infos_t *boot_infos;
static int offb_init_driver(struct device_node *);
@@ -898,103 +889,3 @@ static void do_install_cmap(int con, struct fb_info *info)
fb_set_cmap(fb_default_cmap(size), 1, offb_setcolreg, info);
}
}
-
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-
- /*
- * Backward compatibility mode for Xpmac
- */
-
-int console_getmode(struct vc_mode *mode)
-{
- *mode = display_info;
- return 0;
-}
-
-int console_setmode(struct vc_mode *mode, int doit)
-{
- struct fb_var_screeninfo var;
- int cmode, err;
-
- if (!console_fb_info)
- return -EOPNOTSUPP;
- switch (mode->depth) {
- case 8:
- case 0: /* default */
- cmode = CMODE_8;
- break;
- case 16:
- cmode = CMODE_16;
- break;
- case 24:
- case 32:
- cmode = CMODE_32;
- break;
- default:
- return -EINVAL;
- }
- if ((err = mac_vmode_to_var(mode->mode, cmode, &var)))
- return err;
- var.activate = FB_ACTIVATE_TEST;
- err = console_fb_info->fbops->fb_set_var(&var, fg_console,
- console_fb_info);
- if (err || !doit)
- return err;
- else {
- int unit;
- var.activate = FB_ACTIVATE_NOW;
- for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
- if (fb_display[unit].conp &&
- (GET_FB_IDX(console_fb_info->node) == con2fb_map[unit]))
- console_fb_info->fbops->fb_set_var(&var, unit,
- console_fb_info);
- }
- return 0;
-}
-
-static u16 palette_red[16];
-static u16 palette_green[16];
-static u16 palette_blue[16];
-
-static struct fb_cmap palette_cmap = {
- 0, 16, palette_red, palette_green, palette_blue, NULL
-};
-
-int console_setcmap(int n_entries, unsigned char *red, unsigned char *green,
- unsigned char *blue)
-{
- int i, j, n, err;
-
- if (!console_fb_info)
- return -EOPNOTSUPP;
- for (i = 0; i < n_entries; i += n) {
- n = n_entries-i;
- if (n > 16)
- n = 16;
- palette_cmap.start = i;
- palette_cmap.len = n;
- for (j = 0; j < n; j++) {
- palette_cmap.red[j] = (red[i+j] << 8) | red[i+j];
- palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
- palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j];
- }
- err = console_fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console,
- console_fb_info);
- if (err)
- return err;
- }
- return 0;
-}
-
-int console_powermode(int mode)
-{
- if (mode == VC_POWERMODE_INQUIRY)
- return 0;
- if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
- return -EINVAL;
- /* Not supported */
- return -ENXIO;
-}
-
-#endif /* CONFIG_FB_COMPAT_XPMAC */
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 82c916d8a..eef60b04e 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -521,7 +521,7 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
rinfo->base1_region_size = pci_resource_len (pd, 1);
assert (rinfo->base0_region_size >= 0x00800000); /* from GGI */
- assert (rinfo->base0_region_size >= 0x01000000); /* from GGI */
+ assert (rinfo->base1_region_size >= 0x01000000); /* from GGI */
rinfo->ctrl_base_phys = rinfo->pd->resource[0].start;
rinfo->fb_base_phys = rinfo->pd->resource[1].start;
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 6eb08c857..c9aecc730 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -59,7 +59,7 @@ static int adfs_readpage(struct dentry *dentry, struct page *page)
return block_read_full_page(page, adfs_get_block);
}
-static int adfs_prepare_write(struct page *page, unsigned int from, unsigned int to)
+static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to)
{
return cont_prepare_write(page, from, to, adfs_get_block,
&((struct inode *)page->mapping->host)->u.adfs_i.mmu_private);
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 069964acb..bc0db190f 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -299,7 +299,7 @@ static int affs_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,affs_get_block);
}
-static int affs_prepare_write(struct page *page, unsigned from, unsigned to)
+static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,affs_get_block,
&((struct inode*)page->mapping->host)->u.affs_i.mmu_private);
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index f5ef5e652..c5ca51cda 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -137,7 +137,7 @@ static int bfs_readpage(struct dentry *dentry, struct page *page)
return block_read_full_page(page, bfs_get_block);
}
-static int bfs_prepare_write(struct page *page, unsigned from, unsigned to)
+static int bfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return block_prepare_write(page, from, to, bfs_get_block);
}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 9339775ce..f48a2492d 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -252,7 +252,6 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct exec ex;
- struct file * file;
int fd;
unsigned long error;
unsigned long fd_offset;
@@ -263,7 +262,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
@@ -304,26 +303,32 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->flags &= ~PF_FORKNOEXEC;
#ifdef __sparc__
if (N_MAGIC(ex) == NMAGIC) {
+ loff_t pos = fd_offset;
/* Fuck me plenty... */
+ /* <AOL></AOL> */
error = do_brk(N_TXTADDR(ex), ex.a_text);
- read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
- ex.a_text, 0);
+ bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
+ ex.a_text, &pos);
error = do_brk(N_DATADDR(ex), ex.a_data);
- read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
- ex.a_data, 0);
+ bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
+ ex.a_data, &pos);
goto beyond_if;
}
#endif
if (N_MAGIC(ex) == OMAGIC) {
+ loff_t pos;
#if defined(__alpha__) || defined(__sparc__)
+ pos = fd_offset;
do_brk(N_TXTADDR(ex) & PAGE_MASK,
ex.a_text+ex.a_data + PAGE_SIZE - 1);
- read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
- ex.a_text+ex.a_data, 0);
+ bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
+ ex.a_text+ex.a_data, &pos);
#else
+ pos = 32;
do_brk(0, ex.a_text+ex.a_data);
- read_exec(bprm->dentry, 32, (char *) 0, ex.a_text+ex.a_data, 0);
+ bprm->file->f_op->read(bprm->file, (char *) 0,
+ ex.a_text+ex.a_data, &pos);
#endif
flush_icache_range((unsigned long) 0,
(unsigned long) ex.a_text+ex.a_data);
@@ -336,49 +341,48 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
error_time2 = jiffies;
}
- fd = open_dentry(bprm->dentry, O_RDONLY);
+ fd = get_unused_fd();
if (fd < 0)
return fd;
- file = fget(fd);
+ get_file(bprm->file);
+ fd_install(fd, bprm->file);
if ((fd_offset & ~PAGE_MASK) != 0 &&
(jiffies-error_time) > 5*HZ)
{
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert program: %s\n",
- file->f_dentry->d_name.name);
+ bprm->file->f_dentry->d_name.name);
error_time = jiffies;
}
- if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
- fput(file);
+ if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
+ loff_t pos = fd_offset;
sys_close(fd);
do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
- read_exec(bprm->dentry, fd_offset,
- (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
+ bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
+ ex.a_text+ex.a_data, &pos);
flush_icache_range((unsigned long) N_TXTADDR(ex),
(unsigned long) N_TXTADDR(ex) +
ex.a_text+ex.a_data);
goto beyond_if;
}
- error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
+ error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset);
if (error != N_TXTADDR(ex)) {
- fput(file);
sys_close(fd);
send_sig(SIGKILL, current, 0);
return error;
}
- error = do_mmap(file, N_DATADDR(ex), ex.a_data,
+ error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset + ex.a_text);
- fput(file);
sys_close(fd);
if (error != N_DATADDR(ex)) {
send_sig(SIGKILL, current, 0);
@@ -420,16 +424,12 @@ static int load_aout_library(struct file *file)
unsigned long bss, start_addr, len;
unsigned long error;
int retval;
- loff_t offset = 0;
struct exec ex;
inode = file->f_dentry->d_inode;
retval = -ENOEXEC;
- /* N.B. Save current fs? */
- set_fs(KERNEL_DS);
- error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset);
- set_fs(USER_DS);
+ error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
if (error != sizeof(ex))
goto out;
@@ -450,6 +450,7 @@ static int load_aout_library(struct file *file)
if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
static unsigned long error_time;
+ loff_t pos = N_TXTOFF(ex);
if ((jiffies-error_time) > 5*HZ)
{
@@ -461,8 +462,8 @@ static int load_aout_library(struct file *file)
do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
- read_exec(file->f_dentry, N_TXTOFF(ex),
- (char *)start_addr, ex.a_text + ex.a_data, 0);
+ file->f_op->read(file, (char *)start_addr,
+ ex.a_text + ex.a_data, &pos);
flush_icache_range((unsigned long) start_addr,
(unsigned long) start_addr + ex.a_text + ex.a_data);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 28f82594f..a12183834 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -205,17 +205,15 @@ create_elf_tables(char *p, int argc, int envc,
an ELF header */
static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
- struct dentry * interpreter_dentry,
+ struct file * interpreter,
unsigned long *interp_load_addr)
{
- struct file * file;
struct elf_phdr *elf_phdata;
struct elf_phdr *eppnt;
unsigned long load_addr = 0;
int load_addr_set = 0;
unsigned long last_bss = 0, elf_bss = 0;
unsigned long error = ~0UL;
- int elf_exec_fileno;
int retval, i, size;
/* First of all, some simple consistency checks */
@@ -224,8 +222,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
goto out;
if (!elf_check_arch(interp_elf_ex->e_machine))
goto out;
- if (!interpreter_dentry->d_inode->i_fop ||
- !interpreter_dentry->d_inode->i_fop->mmap)
+ if (!interpreter->f_op->mmap)
goto out;
/*
@@ -244,17 +241,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
if (!elf_phdata)
goto out;
- retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
- (char *) elf_phdata, size, 1);
+ retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size);
error = retval;
if (retval < 0)
- goto out_free;
-
- error = ~0UL;
- elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
- if (elf_exec_fileno < 0)
- goto out_free;
- file = fget(elf_exec_fileno);
+ goto out_close;
eppnt = elf_phdata;
for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
@@ -271,7 +261,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
elf_type |= MAP_FIXED;
- map_addr = do_mmap(file,
+ map_addr = do_mmap(interpreter,
load_addr + ELF_PAGESTART(vaddr),
eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
elf_prot,
@@ -322,19 +312,17 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
out_close:
- fput(file);
- sys_close(elf_exec_fileno);
-out_free:
kfree(elf_phdata);
out:
return error;
}
static unsigned long load_aout_interp(struct exec * interp_ex,
- struct dentry * interpreter_dentry)
+ struct file * interpreter)
{
- unsigned long text_data, offset, elf_entry = ~0UL;
+ unsigned long text_data, elf_entry = ~0UL;
char * addr;
+ loff_t offset;
int retval;
current->mm->end_code = interp_ex->a_text;
@@ -357,7 +345,10 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
}
do_brk(0, text_data);
- retval = read_exec(interpreter_dentry, offset, addr, text_data, 0);
+ retval = -ENOEXEC;
+ if (!interpreter->f_op->read)
+ goto out;
+ retval = interpreter->f_op->read(interpreter, addr, text_data, &offset);
if (retval < 0)
goto out;
flush_icache_range((unsigned long)addr,
@@ -383,8 +374,7 @@ out:
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
- struct file * file;
- struct dentry *interpreter_dentry = NULL; /* to shut gcc up */
+ struct file *interpreter = NULL; /* to shut gcc up */
unsigned long load_addr = 0, load_bias;
int load_addr_set = 0;
char * elf_interpreter = NULL;
@@ -430,7 +420,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out;
}
#endif
- if (!bprm->dentry->d_inode->i_fop||!bprm->dentry->d_inode->i_fop->mmap)
+ if (!bprm->file->f_op||!bprm->file->f_op->mmap)
goto out;
/* Now read in all of the header information */
@@ -443,16 +433,15 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (!elf_phdata)
goto out;
- retval = read_exec(bprm->dentry, elf_ex.e_phoff,
- (char *) elf_phdata, size, 1);
+ retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size);
if (retval < 0)
goto out_free_ph;
- retval = open_dentry(bprm->dentry, O_RDONLY);
+ retval = get_unused_fd();
if (retval < 0)
goto out_free_ph;
- elf_exec_fileno = retval;
- file = fget(elf_exec_fileno);
+ get_file(bprm->file);
+ fd_install(elf_exec_fileno = retval, bprm->file);
elf_ppnt = elf_phdata;
elf_bss = 0;
@@ -480,9 +469,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (!elf_interpreter)
goto out_free_file;
- retval = read_exec(bprm->dentry, elf_ppnt->p_offset,
+ retval = kernel_read(bprm->file, elf_ppnt->p_offset,
elf_interpreter,
- elf_ppnt->p_filesz, 1);
+ elf_ppnt->p_filesz);
if (retval < 0)
goto out_free_interp;
/* If the program interpreter is one of these two,
@@ -495,32 +484,22 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
#if 0
printk("Using ELF interpreter %s\n", elf_interpreter);
#endif
- old_fs = get_fs(); /* This could probably be optimized */
- set_fs(get_ds());
#ifdef __sparc__
if (ibcs2_interpreter) {
unsigned long old_pers = current->personality;
current->personality = PER_SVR4;
- lock_kernel();
- interpreter_dentry = open_namei(elf_interpreter);
- unlock_kernel();
+ interpreter = open_exec(elf_interpreter);
current->personality = old_pers;
} else
#endif
{
- lock_kernel();
- interpreter_dentry = open_namei(elf_interpreter);
- unlock_kernel();
+ interpreter = open_exec(elf_interpreter);
}
- set_fs(old_fs);
- retval = PTR_ERR(interpreter_dentry);
- if (IS_ERR(interpreter_dentry))
+ retval = PTR_ERR(interpreter);
+ if (IS_ERR(interpreter))
goto out_free_interp;
- retval = permission(interpreter_dentry->d_inode, MAY_EXEC);
- if (retval < 0)
- goto out_free_dentry;
- retval = read_exec(interpreter_dentry, 0, bprm->buf, 128, 1);
+ retval = kernel_read(interpreter, 0, bprm->buf, 128);
if (retval < 0)
goto out_free_dentry;
@@ -629,7 +608,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_flags |= MAP_FIXED;
}
- error = do_mmap(file, ELF_PAGESTART(load_bias + vaddr),
+ error = do_mmap(bprm->file, ELF_PAGESTART(load_bias + vaddr),
(elf_ppnt->p_filesz +
ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
elf_prot, elf_flags, (elf_ppnt->p_offset -
@@ -661,7 +640,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_brk = k;
}
set_fs(old_fs);
- fput(file); /* all done with the file */
elf_entry += load_bias;
elf_bss += load_bias;
@@ -674,14 +652,14 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_interpreter) {
if (interpreter_type == INTERPRETER_AOUT)
elf_entry = load_aout_interp(&interp_ex,
- interpreter_dentry);
+ interpreter);
else
elf_entry = load_elf_interp(&interp_elf_ex,
- interpreter_dentry,
+ interpreter,
&interp_load_addr);
lock_kernel();
- dput(interpreter_dentry);
+ fput(interpreter);
unlock_kernel();
kfree(elf_interpreter);
@@ -708,7 +686,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
#ifndef VM_STACK_FLAGS
lock_kernel();
- current->executable = dget(bprm->dentry);
+ current->executable = dget(bprm->file->f_dentry);
unlock_kernel();
#endif
compute_creds(bprm);
@@ -779,13 +757,12 @@ out:
/* error cleanup */
out_free_dentry:
lock_kernel();
- dput(interpreter_dentry);
+ fput(interpreter);
unlock_kernel();
out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);
out_free_file:
- fput(file);
sys_close(elf_exec_fileno);
out_free_ph:
kfree(elf_phdata);
@@ -797,25 +774,13 @@ out_free_ph:
static int load_elf_library(struct file *file)
{
- struct dentry * dentry;
- struct inode * inode;
struct elf_phdr *elf_phdata;
unsigned long elf_bss = 0, bss, len, k;
int retval, error, i, j;
struct elfhdr elf_ex;
- loff_t offset = 0;
-
- error = -EACCES;
- dentry = file->f_dentry;
- inode = dentry->d_inode;
- /* seek to the beginning of the file */
error = -ENOEXEC;
-
- /* N.B. save current DS?? */
- set_fs(KERNEL_DS);
- retval = file->f_op->read(file, (char *) &elf_ex, sizeof(elf_ex), &offset);
- set_fs(USER_DS);
+ retval = kernel_read(file, 0, (char *) &elf_ex, sizeof(elf_ex));
if (retval != sizeof(elf_ex))
goto out;
@@ -824,8 +789,7 @@ static int load_elf_library(struct file *file)
/* First of all, some simple consistency checks */
if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- !elf_check_arch(elf_ex.e_machine) ||
- (!inode->i_fop || !inode->i_fop->mmap))
+ !elf_check_arch(elf_ex.e_machine) || !file->f_op->mmap)
goto out;
/* Now read in all of the header information */
@@ -840,8 +804,8 @@ static int load_elf_library(struct file *file)
goto out;
/* N.B. check for error return?? */
- retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
+ retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata,
+ sizeof(struct elf_phdr) * elf_ex.e_phnum);
error = -ENOEXEC;
for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 1a1533a10..1b18094eb 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -25,7 +25,7 @@
static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
{
char *interp, *i_name, *i_arg;
- struct dentry * dentry;
+ struct file * file;
int retval;
struct elfhdr elf_ex;
@@ -38,16 +38,13 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
(!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
- (!bprm->dentry->d_inode->i_fop ||
- !bprm->dentry->d_inode->i_fop->mmap)) {
+ (!bprm->file->f_op || !bprm->file->f_op->mmap)) {
return -ENOEXEC;
}
bprm->sh_bang++; /* Well, the bang-shell is implicit... */
- lock_kernel();
- dput(bprm->dentry);
- unlock_kernel();
- bprm->dentry = NULL;
+ fput(bprm->file);
+ bprm->file = NULL;
/* Unlike in the script case, we don't have to do any hairy
* parsing to find our interpreter... it's hardcoded!
@@ -79,16 +76,14 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
/*
* OK, now restart the process with the interpreter's inode.
- * Note that we use open_namei() as the name is now in kernel
+ * Note that we use open_exec() as the name is now in kernel
* space, and we don't need to copy it.
*/
- lock_kernel();
- dentry = open_namei(interp);
- unlock_kernel();
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ file = open_exec(interp);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
- bprm->dentry = dentry;
+ bprm->file = file;
retval = prepare_binprm(bprm);
if (retval < 0)
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 9d98d7d70..a03c4723f 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -27,6 +27,7 @@
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <linux/file.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
@@ -180,7 +181,7 @@ static struct binfmt_entry *check_file(struct linux_binprm *bprm)
static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
{
struct binfmt_entry *fmt;
- struct dentry * dentry;
+ struct file * file;
char iname[128];
char *iname_addr = iname;
int retval;
@@ -200,8 +201,8 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (!fmt)
goto _ret;
- dput(bprm->dentry);
- bprm->dentry = NULL;
+ fput(bprm->file);
+ bprm->file = NULL;
/* Build args for interpreter */
remove_arg_zero(bprm);
@@ -213,11 +214,11 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
bprm->argc++;
bprm->filename = iname; /* for binfmt_script */
- dentry = open_namei(iname);
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ file = open_exec(iname);
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
goto _ret;
- bprm->dentry = dentry;
+ bprm->file = file;
retval = prepare_binprm(bprm);
if (retval >= 0)
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 450f918a4..dc78f8389 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -11,12 +11,13 @@
#include <linux/malloc.h>
#include <linux/binfmts.h>
#include <linux/init.h>
+#include <linux/file.h>
#include <linux/smp_lock.h>
static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
{
char *cp, *i_name, *i_arg;
- struct dentry * dentry;
+ struct file *file;
char interp[128];
int retval;
@@ -28,10 +29,8 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
*/
bprm->sh_bang++;
- lock_kernel();
- dput(bprm->dentry);
- unlock_kernel();
- bprm->dentry = NULL;
+ fput(bprm->file);
+ bprm->file = NULL;
bprm->buf[127] = '\0';
if ((cp = strchr(bprm->buf, '\n')) == NULL)
@@ -81,13 +80,11 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
/*
* OK, now restart the process with the interpreter's dentry.
*/
- lock_kernel();
- dentry = open_namei(interp);
- unlock_kernel();
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ file = open_exec(interp);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
- bprm->dentry = dentry;
+ bprm->file = file;
retval = prepare_binprm(bprm);
if (retval < 0)
return retval;
diff --git a/fs/buffer.c b/fs/buffer.c
index 617188db0..26580ee0d 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2029,7 +2029,7 @@ int block_symlink(struct inode *inode, const char *symname, int len)
if (!page)
goto fail;
- err = mapping->a_ops->prepare_write(page, 0, len-1);
+ err = mapping->a_ops->prepare_write(NULL, page, 0, len-1);
if (err)
goto fail_map;
kaddr = (char*)page_address(page);
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 1e39811e6..bb51b0c05 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -685,7 +685,7 @@ static int coda_venus_readdir(struct file *filp, void *getdent,
}
/* we use this routine to read the file into our buffer */
- bufsize = read_exec(filp->f_dentry, filp->f_pos, buff, DIR_BUFSIZE, 1);
+ bufsize = kernel_read(filp, filp->f_pos, buff, DIR_BUFSIZE);
if ( bufsize < 0) {
printk("coda_venus_readdir: cannot read directory %d.\n",
bufsize);
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 237c7d9aa..c5ca590d2 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -200,12 +200,6 @@ out:
return retval;
}
-/* Nothing to do.. */
-static void cramfs_put_super(struct super_block *sb)
-{
- return;
-}
-
static int cramfs_statfs(struct super_block *sb, struct statfs *buf)
{
buf->f_type = CRAMFS_MAGIC;
@@ -361,7 +355,6 @@ static struct inode_operations cramfs_dir_inode_operations = {
};
static struct super_operations cramfs_ops = {
- put_super: cramfs_put_super,
statfs: cramfs_statfs,
};
diff --git a/fs/dcache.c b/fs/dcache.c
index dc424305f..d4aef49e7 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -27,6 +27,9 @@
#define DCACHE_PARANOIA 1
/* #define DCACHE_DEBUG 1 */
+/* Right now the dcache depends on the kernel lock */
+#define check_lock() if (!kernel_locked()) BUG()
+
/* For managing the dcache */
extern unsigned long num_physpages, page_cache_size;
extern int inodes_stat[];
@@ -104,6 +107,8 @@ void dput(struct dentry *dentry)
{
int count;
+ check_lock();
+
if (!dentry)
return;
@@ -158,7 +163,7 @@ out:
count,
dentry->d_parent->d_name.name,
dentry->d_name.name);
- *(int *)0 = 0;
+ BUG();
}
/*
@@ -168,6 +173,8 @@ out:
*/
int d_invalidate(struct dentry * dentry)
{
+ check_lock();
+
/*
* If it's already been dropped, return OK.
*/
@@ -226,6 +233,7 @@ static inline void prune_one_dentry(struct dentry * dentry)
*/
void prune_dcache(int count)
{
+ check_lock();
for (;;) {
struct dentry *dentry;
struct list_head *tmp = dentry_unused.prev;
@@ -261,6 +269,8 @@ void shrink_dcache_sb(struct super_block * sb)
struct list_head *tmp, *next;
struct dentry *dentry;
+ check_lock();
+
/*
* Pass one ... move the dentries for the specified
* superblock to the most recent end of the unused list.
@@ -308,6 +318,8 @@ int is_root_busy(struct dentry *root)
struct list_head *next;
int count = root->d_count;
+ check_lock();
+
repeat:
next = this_parent->d_subdirs.next;
resume:
@@ -337,6 +349,44 @@ resume:
}
/*
+ * Search for at least 1 mount point in the dentry's subdirs.
+ * We descend to the next level whenever the d_subdirs
+ * list is non-empty and continue searching.
+ */
+int have_submounts(struct dentry *parent)
+{
+ struct dentry *this_parent = parent;
+ struct list_head *next;
+
+ if (parent->d_mounts != parent)
+ return 1;
+repeat:
+ next = this_parent->d_subdirs.next;
+resume:
+ while (next != &this_parent->d_subdirs) {
+ struct list_head *tmp = next;
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+ next = tmp->next;
+ /* Have we found a mount point ? */
+ if (dentry->d_mounts != dentry)
+ return 1;
+ if (!list_empty(&dentry->d_subdirs)) {
+ this_parent = dentry;
+ goto repeat;
+ }
+ }
+ /*
+ * All done at this level ... ascend and resume the search.
+ */
+ if (this_parent != parent) {
+ next = this_parent->d_child.next;
+ this_parent = this_parent->d_parent;
+ goto resume;
+ }
+ return 0; /* No mount points found in tree */
+}
+
+/*
* Search the dentry child list for the specified parent,
* and move any unused dentries to the end of the unused
* list for prune_dcache(). We descend to the next level
@@ -349,6 +399,8 @@ static int select_parent(struct dentry * parent)
struct list_head *next;
int found = 0;
+ check_lock();
+
repeat:
next = this_parent->d_subdirs.next;
resume:
@@ -525,6 +577,8 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
struct list_head *head = d_hash(parent,hash);
struct list_head *tmp = head->next;
+ check_lock();
+
for (;;) {
struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
if (tmp == head)
@@ -564,6 +618,8 @@ int d_validate(struct dentry *dentry, struct dentry *dparent,
struct list_head *base, *lhp;
int valid = 1;
+ check_lock();
+
if (dentry != dparent) {
base = d_hash(dparent, hash);
lhp = base;
@@ -605,6 +661,10 @@ out:
*/
void d_delete(struct dentry * dentry)
{
+ check_lock();
+
+ check_lock();
+
/*
* Are we the only user?
*/
@@ -646,6 +706,7 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target)
{
const unsigned char *old_name, *new_name;
+ check_lock();
memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
old_name = target->d_name.name;
new_name = dentry->d_name.name;
@@ -674,6 +735,8 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target)
*/
void d_move(struct dentry * dentry, struct dentry * target)
{
+ check_lock();
+
if (!dentry->d_inode)
printk(KERN_WARNING "VFS: moving negative dcache entry\n");
@@ -773,7 +836,11 @@ asmlinkage long sys_getcwd(char *buf, unsigned long size)
error = -ENOMEM;
if (page) {
unsigned long len;
- char * cwd = d_path(pwd, page, PAGE_SIZE);
+ char * cwd;
+
+ lock_kernel();
+ cwd = d_path(pwd, page, PAGE_SIZE);
+ unlock_kernel();
error = -ERANGE;
len = PAGE_SIZE + page - cwd;
diff --git a/fs/devfs/Makefile b/fs/devfs/Makefile
index 2b301b37a..23f190410 100644
--- a/fs/devfs/Makefile
+++ b/fs/devfs/Makefile
@@ -36,4 +36,4 @@ doc: base.c util.c
test:
gcc -o /tmp/base.o -D__KERNEL__ -I../../include -Wall \
-Wstrict-prototypes -O2 -fomit-frame-pointer -pipe \
- -fno-strength-reduce -DCPU=686 -DEXPORT_SYMTAB -c base.c
+ -fno-strength-reduce -DEXPORT_SYMTAB -c base.c
diff --git a/fs/exec.c b/fs/exec.c
index d7d5240be..8a8a10631 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -93,56 +93,6 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
__MOD_DEC_USE_COUNT(fmt->module);
}
-/* N.B. Error returns must be < 0 */
-int open_dentry(struct dentry * dentry, int mode)
-{
- struct inode * inode = dentry->d_inode;
- struct file * f;
- struct list_head * l = NULL;
- int fd, error;
-
- lock_kernel();
- if (inode->i_sb)
- l = &inode->i_sb->s_files;
-
- error = -EINVAL;
- if (!inode->i_fop)
- goto out;
- fd = get_unused_fd();
- if (fd >= 0) {
- error = -ENFILE;
- f = get_empty_filp();
- if (!f)
- goto out_fd;
- f->f_flags = mode;
- f->f_mode = (mode+1) & O_ACCMODE;
- f->f_dentry = dentry;
- f->f_pos = 0;
- f->f_reada = 0;
- f->f_op = inode->i_fop;
- if (f->f_op->open) {
- error = f->f_op->open(inode,f);
- if (error)
- goto out_filp;
- }
- file_move(f, l);
- fd_install(fd, f);
- dget(dentry);
- }
- unlock_kernel();
- return fd;
-
-out_filp:
- if (error > 0)
- error = -EIO;
- put_filp(f);
-out_fd:
- put_unused_fd(fd);
-out:
- unlock_kernel();
- return error;
-}
-
/*
* Note that a shared library must be both readable and executable due to
* security reasons.
@@ -365,44 +315,45 @@ int setup_arg_pages(struct linux_binprm *bprm)
return 0;
}
-/*
- * Read in the complete executable. This is used for "-N" files
- * that aren't on a block boundary, and for files on filesystems
- * without get_block support.
- */
-int read_exec(struct dentry *dentry, unsigned long offset,
- char * addr, unsigned long count, int to_kmem)
+struct file *open_exec(const char *name)
{
- struct file file;
- struct inode * inode = dentry->d_inode;
- int result = -ENOEXEC;
+ struct dentry *dentry;
+ struct file *file;
- if (!inode->i_fop)
- goto end_readexec;
- if (init_private_file(&file, dentry, 1))
- goto end_readexec;
- if (!file.f_op->read)
- goto close_readexec;
- if (file.f_op->llseek) {
- if (file.f_op->llseek(&file,offset,0) != offset)
- goto close_readexec;
- } else
- file.f_pos = offset;
- if (to_kmem) {
- mm_segment_t old_fs = get_fs();
- set_fs(get_ds());
- result = file.f_op->read(&file, addr, count, &file.f_pos);
- set_fs(old_fs);
- } else {
- result = verify_area(VERIFY_WRITE, addr, count);
- if (result)
- goto close_readexec;
- result = file.f_op->read(&file, addr, count, &file.f_pos);
+ lock_kernel();
+ dentry = lookup_dentry(name, NULL, LOOKUP_FOLLOW);
+ file = (struct file*) dentry;
+ if (!IS_ERR(dentry)) {
+ file = ERR_PTR(-EACCES);
+ if (dentry->d_inode && S_ISREG(dentry->d_inode->i_mode)) {
+ int err = permission(dentry->d_inode, MAY_EXEC);
+ file = ERR_PTR(err);
+ if (!err) {
+ file = dentry_open(dentry, O_RDONLY);
+out:
+ unlock_kernel();
+ return file;
+ }
+ }
+ dput(dentry);
}
-close_readexec:
- if (file.f_op->release)
- file.f_op->release(inode,&file);
-end_readexec:
+ goto out;
+}
+
+int kernel_read(struct file *file, unsigned long offset,
+ char * addr, unsigned long count)
+{
+ mm_segment_t old_fs;
+ loff_t pos = offset;
+ int result = -ENOSYS;
+
+ if (!file->f_op->read)
+ goto fail;
+ old_fs = get_fs();
+ set_fs(get_ds());
+ result = file->f_op->read(file, addr, count, &pos);
+ set_fs(old_fs);
+fail:
return result;
}
@@ -540,7 +491,7 @@ int flush_old_exec(struct linux_binprm * bprm)
flush_thread();
if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
- permission(bprm->dentry->d_inode,MAY_READ))
+ permission(bprm->file->f_dentry->d_inode,MAY_READ))
current->dumpable = 0;
/* An exec changes our domain. We are no longer part of the thread
@@ -580,7 +531,7 @@ int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
int retval,id_change,cap_raised;
- struct inode * inode = bprm->dentry->d_inode;
+ struct inode * inode = bprm->file->f_dentry->d_inode;
mode = inode->i_mode;
if (!S_ISREG(mode)) /* must be regular file */
@@ -677,7 +628,7 @@ int prepare_binprm(struct linux_binprm *bprm)
}
memset(bprm->buf,0,sizeof(bprm->buf));
- return read_exec(bprm->dentry,0,bprm->buf,128,1);
+ return kernel_read(bprm->file,0,bprm->buf,128);
}
/*
@@ -763,24 +714,20 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
{
int i;
char * dynloader[] = { "/sbin/loader" };
- struct dentry * dentry;
+ struct file * file;
- lock_kernel();
- dput(bprm->dentry);
- unlock_kernel();
- bprm->dentry = NULL;
+ fput(bprm->file);
+ bprm->file = NULL;
bprm_loader.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
for (i = 0 ; i < MAX_ARG_PAGES ; i++) /* clear page-table */
bprm_loader.page[i] = NULL;
- lock_kernel();
- dentry = open_namei(dynloader[0]);
- unlock_kernel();
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ file = open_exec(dynloader[0]);
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
return retval;
- bprm->dentry = dentry;
+ bprm->file = file;
bprm->loader = bprm_loader.p;
retval = prepare_binprm(bprm);
if (retval<0)
@@ -802,12 +749,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
retval = fn(bprm, regs);
if (retval >= 0) {
put_binfmt(fmt);
- if (bprm->dentry) {
- lock_kernel();
- dput(bprm->dentry);
- unlock_kernel();
- }
- bprm->dentry = NULL;
+ if (bprm->file)
+ fput(bprm->file);
+ bprm->file = NULL;
current->did_exec = 1;
return retval;
}
@@ -815,7 +759,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
put_binfmt(fmt);
if (retval != -ENOEXEC)
break;
- if (!bprm->dentry) {
+ if (!bprm->file) {
spin_unlock(&binfmt_lock);
return retval;
}
@@ -847,37 +791,31 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
{
struct linux_binprm bprm;
- struct dentry * dentry;
+ struct file *file;
int retval;
int i;
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
- lock_kernel();
- dentry = open_namei(filename);
- unlock_kernel();
+ file = open_exec(filename);
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
return retval;
- bprm.dentry = dentry;
+ bprm.file = file;
bprm.filename = filename;
bprm.sh_bang = 0;
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
- lock_kernel();
- dput(dentry);
- unlock_kernel();
+ fput(file);
return bprm.argc;
}
if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
- lock_kernel();
- dput(dentry);
- unlock_kernel();
+ fput(file);
return bprm.envc;
}
@@ -905,11 +843,8 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
out:
/* Something went wrong, return the inode and free the argument pages*/
- if (bprm.dentry) {
- lock_kernel();
- dput(bprm.dentry);
- unlock_kernel();
- }
+ if (bprm.file)
+ fput(bprm.file);
/* Assumes that free_page() can take a NULL argument. */
/* I hope this is ok for all architectures */
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 904f5cb8f..90ce121ce 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -11,6 +11,7 @@
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/config.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
@@ -300,21 +301,20 @@ do_more:
if (!gdp)
goto error_return;
- if (test_opt (sb, CHECK_STRICT) &&
- (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
- in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
- in_range (block, le32_to_cpu(gdp->bg_inode_table),
- sb->u.ext2_sb.s_itb_per_group) ||
- in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
- sb->u.ext2_sb.s_itb_per_group)))
- ext2_panic (sb, "ext2_free_blocks",
+ if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
+ in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
+ in_range (block, le32_to_cpu(gdp->bg_inode_table),
+ sb->u.ext2_sb.s_itb_per_group) ||
+ in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
+ sb->u.ext2_sb.s_itb_per_group))
+ ext2_error (sb, "ext2_free_blocks",
"Freeing blocks in system zones - "
"Block = %lu, count = %lu",
block, count);
for (i = 0; i < count; i++) {
if (!ext2_clear_bit (bit + i, bh->b_data))
- ext2_warning (sb, "ext2_free_blocks",
+ ext2_error (sb, "ext2_free_blocks",
"bit already cleared for block %lu",
block);
else {
@@ -527,11 +527,11 @@ got_block:
tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block);
- if (test_opt (sb, CHECK_STRICT) &&
- (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
- tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
- in_range (tmp, le32_to_cpu(gdp->bg_inode_table), sb->u.ext2_sb.s_itb_per_group)))
- ext2_panic (sb, "ext2_new_block",
+ if (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
+ tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
+ in_range (tmp, le32_to_cpu(gdp->bg_inode_table),
+ sb->u.ext2_sb.s_itb_per_group))
+ ext2_error (sb, "ext2_new_block",
"Allocating block in system zone - "
"block = %u", tmp);
@@ -679,6 +679,7 @@ int ext2_group_sparse(int group)
test_root(group, 7));
}
+#ifdef CONFIG_EXT2_CHECK
/* Called at mount-time, super-block is locked */
void ext2_check_blocks_bitmap (struct super_block * sb)
{
@@ -753,3 +754,4 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
"stored = %lu, counted = %lu",
(unsigned long) le32_to_cpu(es->s_free_blocks_count), bitmap_count);
}
+#endif
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 3a3e4a69c..277562ec7 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -12,6 +12,7 @@
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/config.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
@@ -236,7 +237,7 @@ void ext2_free_inode (struct inode * inode)
/* Ok, now we can actually update the inode bitmaps.. */
if (!ext2_clear_bit (bit, bh->b_data))
- ext2_warning (sb, "ext2_free_inode",
+ ext2_error (sb, "ext2_free_inode",
"bit already cleared for inode %lu", ino);
else {
gdp = ext2_get_group_desc (sb, block_group, &bh2);
@@ -401,7 +402,7 @@ repeat:
EXT2_INODES_PER_GROUP(sb))) <
EXT2_INODES_PER_GROUP(sb)) {
if (ext2_set_bit (j, bh->b_data)) {
- ext2_warning (sb, "ext2_new_inode",
+ ext2_error (sb, "ext2_new_inode",
"bit already set for inode %d", j);
goto repeat;
}
@@ -527,6 +528,7 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
#endif
}
+#ifdef CONFIG_EXT2_CHECK
/* Called at mount-time, super-block is locked */
void ext2_check_inodes_bitmap (struct super_block * sb)
{
@@ -565,3 +567,4 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
(unsigned long) le32_to_cpu(es->s_free_inodes_count),
bitmap_count);
}
+#endif
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index cfaf5d4d3..dd09b95aa 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -628,7 +628,7 @@ static int ext2_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,ext2_get_block);
}
-static int ext2_prepare_write(struct page *page, unsigned from, unsigned to)
+static int ext2_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return block_prepare_write(page,from,to,ext2_get_block);
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 73be71e61..a68289d71 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -16,6 +16,7 @@
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
@@ -153,23 +154,14 @@ static int parse_options (char * options, unsigned long * sb_block,
set_opt (*mount_options, NO_UID32);
}
else if (!strcmp (this_char, "check")) {
- if (!value || !*value)
- set_opt (*mount_options, CHECK_NORMAL);
- else if (!strcmp (value, "none")) {
- clear_opt (*mount_options, CHECK_NORMAL);
- clear_opt (*mount_options, CHECK_STRICT);
- }
- else if (!strcmp (value, "normal"))
- set_opt (*mount_options, CHECK_NORMAL);
- else if (!strcmp (value, "strict")) {
- set_opt (*mount_options, CHECK_NORMAL);
- set_opt (*mount_options, CHECK_STRICT);
- }
- else {
- printk ("EXT2-fs: Invalid check option: %s\n",
- value);
- return 0;
- }
+ if (!value || !*value || !strcmp (value, "none"))
+ clear_opt (*mount_options, CHECK);
+ else
+#ifdef CONFIG_EXT2_CHECK
+ set_opt (*mount_options, CHECK);
+#else
+ printk("EXT2 Check option not supported\n");
+#endif
}
else if (!strcmp (this_char, "debug"))
set_opt (*mount_options, DEBUG);
@@ -205,10 +197,6 @@ static int parse_options (char * options, unsigned long * sb_block,
set_opt (*mount_options, GRPID);
else if (!strcmp (this_char, "minixdf"))
set_opt (*mount_options, MINIX_DF);
- else if (!strcmp (this_char, "nocheck")) {
- clear_opt (*mount_options, CHECK_NORMAL);
- clear_opt (*mount_options, CHECK_STRICT);
- }
else if (!strcmp (this_char, "nogrpid") ||
!strcmp (this_char, "sysvgroups"))
clear_opt (*mount_options, GRPID);
@@ -305,10 +293,12 @@ static void ext2_setup_super (struct super_block * sb,
EXT2_BLOCKS_PER_GROUP(sb),
EXT2_INODES_PER_GROUP(sb),
sb->u.ext2_sb.s_mount_opt);
+#ifdef CONFIG_EXT2_CHECK
if (test_opt (sb, CHECK)) {
ext2_check_blocks_bitmap (sb);
ext2_check_inodes_bitmap (sb);
}
+#endif
}
#if 0 /* ibasket's still have unresolved bugs... -DaveM */
@@ -398,7 +388,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
}
sb->u.ext2_sb.s_mount_opt = 0;
- set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL);
if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
&sb->u.ext2_sb.s_mount_opt)) {
return NULL;
@@ -674,7 +663,6 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
/*
* Allow the "check" option to be passed as a remount option.
*/
- new_mount_opt = EXT2_MOUNT_CHECK_NORMAL;
if (!parse_options (data, &tmp, &resuid, &resgid,
&new_mount_opt))
return -EINVAL;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index cedd3ba2b..a0202c66f 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -737,7 +737,7 @@ static int fat_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,fat_get_block);
}
-static int fat_prepare_write(struct page *page, unsigned from, unsigned to)
+static int fat_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,fat_get_block,
&MSDOS_I((struct inode*)page->mapping->host)->mmu_private);
diff --git a/fs/fifo.c b/fs/fifo.c
index fcaf45f9f..25a08e757 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -12,6 +12,21 @@
#include <linux/mm.h>
#include <linux/malloc.h>
+static void wait_for_partner(struct inode* inode, unsigned int* cnt)
+{
+ int cur = *cnt;
+ while(cur == *cnt) {
+ pipe_wait(inode);
+ if(signal_pending(current))
+ break;
+ }
+}
+
+static void wake_up_partner(struct inode* inode)
+{
+ wake_up_interruptible(PIPE_WAIT(*inode));
+}
+
static int fifo_open(struct inode *inode, struct file *filp)
{
int ret;
@@ -20,29 +35,12 @@ static int fifo_open(struct inode *inode, struct file *filp)
if (down_interruptible(PIPE_SEM(*inode)))
goto err_nolock_nocleanup;
- if (! inode->i_pipe) {
- unsigned long page;
- struct pipe_inode_info *info;
-
- info = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL);
-
+ if (!inode->i_pipe) {
ret = -ENOMEM;
- if (!info)
- goto err_nocleanup;
- page = __get_free_page(GFP_KERNEL);
- if (!page) {
- kfree(info);
+ if(!pipe_new(inode))
goto err_nocleanup;
- }
-
- inode->i_pipe = info;
-
- init_waitqueue_head(PIPE_WAIT(*inode));
- PIPE_BASE(*inode) = (char *) page;
- PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
- PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
- PIPE_WAITING_WRITERS(*inode) = PIPE_WAITING_READERS(*inode) = 0;
}
+ filp->f_version = 0;
switch (filp->f_mode) {
case 1:
@@ -51,27 +49,23 @@ static int fifo_open(struct inode *inode, struct file *filp)
* POSIX.1 says that O_NONBLOCK means return with the FIFO
* opened, even when there is no process writing the FIFO.
*/
- filp->f_op = &connecting_fifo_fops;
+ filp->f_op = &read_fifo_fops;
+ PIPE_RCOUNTER(*inode)++;
if (PIPE_READERS(*inode)++ == 0)
- wake_up_interruptible(PIPE_WAIT(*inode));
-
- if (!(filp->f_flags & O_NONBLOCK)) {
- while (!PIPE_WRITERS(*inode)) {
- if (signal_pending(current))
+ wake_up_partner(inode);
+
+ if (!PIPE_WRITERS(*inode)) {
+ if ((filp->f_flags & O_NONBLOCK)) {
+ /* suppress POLLHUP until we have
+ * seen a writer */
+ filp->f_version = PIPE_WCOUNTER(*inode);
+ } else
+ {
+ wait_for_partner(inode, &PIPE_WCOUNTER(*inode));
+ if(signal_pending(current))
goto err_rd;
- up(PIPE_SEM(*inode));
- interruptible_sleep_on(PIPE_WAIT(*inode));
-
- /* Note that using down_interruptible here
- and similar places below is pointless,
- since we have to acquire the lock to clean
- up properly. */
- down(PIPE_SEM(*inode));
}
}
-
- if (PIPE_WRITERS(*inode))
- filp->f_op = &read_fifo_fops;
break;
case 2:
@@ -85,15 +79,14 @@ static int fifo_open(struct inode *inode, struct file *filp)
goto err;
filp->f_op = &write_fifo_fops;
+ PIPE_WCOUNTER(*inode)++;
if (!PIPE_WRITERS(*inode)++)
- wake_up_interruptible(PIPE_WAIT(*inode));
+ wake_up_partner(inode);
- while (!PIPE_READERS(*inode)) {
+ if (!PIPE_READERS(*inode)) {
+ wait_for_partner(inode, &PIPE_RCOUNTER(*inode));
if (signal_pending(current))
goto err_wr;
- up(PIPE_SEM(*inode));
- interruptible_sleep_on(PIPE_WAIT(*inode));
- down(PIPE_SEM(*inode));
}
break;
@@ -108,8 +101,10 @@ static int fifo_open(struct inode *inode, struct file *filp)
PIPE_READERS(*inode)++;
PIPE_WRITERS(*inode)++;
+ PIPE_RCOUNTER(*inode)++;
+ PIPE_WCOUNTER(*inode)++;
if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1)
- wake_up_interruptible(PIPE_WAIT(*inode));
+ wake_up_partner(inode);
break;
default:
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 34e365663..8c0afe0c8 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -225,7 +225,7 @@ static int hfs_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,hfs_get_block);
}
-static int hfs_prepare_write(struct page *page, unsigned from, unsigned to)
+static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,hfs_get_block,
&((struct inode*)page->mapping->host)->u.hfs_i.mmu_private);
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 710b9120b..d8063e296 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -94,7 +94,7 @@ static int hpfs_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,hpfs_get_block);
}
-static int hpfs_prepare_write(struct page *page, unsigned from, unsigned to)
+static int hpfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,hpfs_get_block,
&((struct inode*)page->mapping->host)->u.hpfs_i.mmu_private);
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 517456326..20b9bb490 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -296,6 +296,7 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
struct rpc_clnt *clnt;
struct nlm_args *argp = &req->a_args;
struct nlm_res *resp = &req->a_res;
+ struct rpc_message msg;
int status;
dprintk("lockd: call procedure %s on %s (async)\n",
@@ -306,8 +307,11 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
return -ENOLCK;
/* bootstrap and kick off the async RPC call */
- status = rpc_do_call(clnt, proc, argp, resp, RPC_TASK_ASYNC,
- callback, req);
+ msg.rpc_proc = proc;
+ msg.rpc_argp = argp;
+ msg.rpc_resp =resp;
+ msg.rpc_cred = NULL;
+ status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
/* If the async call is proceeding, increment host refcount */
if (status >= 0 && (req->a_flags & RPC_TASK_ASYNC))
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index a2f280bdc..55dee3886 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -163,7 +163,7 @@ xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
*p++ = htonl(argp->proc);
/* This is the private part. Needed only for SM_MON call */
- if (rqstp->rq_task->tk_proc == SM_MON) {
+ if (rqstp->rq_task->tk_msg.rpc_proc == SM_MON) {
*p++ = argp->addr;
*p++ = 0;
*p++ = 0;
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 4c9fa16a3..a581e328a 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -1014,7 +1014,7 @@ static int minix_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,minix_get_block);
}
-static int minix_prepare_write(struct page *page, unsigned from, unsigned to)
+static int minix_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return block_prepare_write(page,from,to,minix_get_block);
}
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 3171e8adc..3c8aac510 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -9,7 +9,7 @@
O_TARGET := nfs.o
O_OBJS := inode.o file.o read.o write.o dir.o symlink.o proc.o \
- nfs2xdr.o
+ nfs2xdr.o flushd.o
ifdef CONFIG_ROOT_NFS
O_OBJS += nfsroot.o mount_clnt.o
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 37b2b682b..3ca240129 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -596,9 +596,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
out_valid:
return 1;
out_bad:
- d_drop(dentry);
if (!list_empty(&dentry->d_subdirs))
shrink_dcache_parent(dentry);
+ /* If we have submounts, don't unhash ! */
+ if (have_submounts(dentry))
+ goto out_valid;
+ d_drop(dentry);
/* Purge readdir caches. */
if (dentry->d_parent->d_inode) {
nfs_zap_caches(dentry->d_parent->d_inode);
@@ -862,61 +865,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
return error;
}
-
-/* Note: we copy the code from lookup_dentry() here, only: we have to
- * omit the directory lock. We are already the owner of the lock when
- * we reach here. And "down(&dir->i_sem)" would make us sleep forever
- * ('cause WE have the lock)
- *
- * VERY IMPORTANT: calculate the hash for this dentry!!!!!!!!
- * Otherwise the cached lookup DEFINITELY WILL fail. And a new dentry
- * is created. Without the DCACHE_NFSFS_RENAMED flag. And with d_count
- * == 1. And trouble.
- *
- * Concerning my choice of the temp name: it is just nice to have
- * i_ino part of the temp name, as this offers another check whether
- * somebody attempts to remove the "silly renamed" dentry itself.
- * Which is something that I consider evil. Your opinion may vary.
- * BUT:
- * Now that I compute the hash value right, it should be possible to simply
- * check for the DCACHE_NFSFS_RENAMED flag in dentry->d_flag instead of
- * doing the string compare.
- * WHICH MEANS:
- * This offers the opportunity to shorten the temp name. Currently, I use
- * the hex representation of i_ino + an event counter. This sums up to
- * as much as 36 characters for a 64 bit machine, and needs 20 chars on
- * a 32 bit machine.
- * QUINTESSENCE
- * The use of i_ino is simply cosmetic. All we need is a unique temp
- * file name for the .nfs files. The event counter seemed to be adequate.
- * And as we retry in case such a file already exists, we are guaranteed
- * to succeed.
- */
-
-static
-struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
-{
- struct qstr sqstr;
- struct dentry *sdentry;
- struct dentry *res;
-
- sqstr.name = silly;
- sqstr.len = slen;
- sqstr.hash = full_name_hash(silly, slen);
- sdentry = d_lookup(parent, &sqstr);
- if (!sdentry) {
- sdentry = d_alloc(parent, &sqstr);
- if (sdentry == NULL)
- return ERR_PTR(-ENOMEM);
- res = nfs_lookup(parent->d_inode, sdentry);
- if (res) {
- dput(sdentry);
- return res;
- }
- }
- return sdentry;
-}
-
static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
static unsigned int sillycounter = 0;
@@ -966,7 +914,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
dfprintk(VFS, "trying to rename %s to %s\n",
dentry->d_name.name, silly);
- sdentry = nfs_silly_lookup(dentry->d_parent, silly, slen);
+ sdentry = lookup_one(silly, dget(dentry->d_parent));
/*
* N.B. Better to return EBUSY here ... it could be
* dangerous to delete the file while it's in use.
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 9a91bb1ab..32d290c73 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -144,10 +144,10 @@ nfs_fsync(struct file *file, struct dentry *dentry)
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-static int nfs_prepare_write(struct page *page, unsigned offset, unsigned to)
+static int nfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
kmap(page);
- return 0;
+ return nfs_flush_incompatible(file, page);
}
static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
diff --git a/fs/nfs/flushd.c b/fs/nfs/flushd.c
new file mode 100644
index 000000000..d36c3a9ae
--- /dev/null
+++ b/fs/nfs/flushd.c
@@ -0,0 +1,304 @@
+/*
+ * linux/fs/nfs/flushd.c
+ *
+ * For each NFS mount, there is a separate cache object that contains
+ * a hash table of all clusters. With this cache, an async RPC task
+ * (`flushd') is associated, which wakes up occasionally to inspect
+ * its list of dirty buffers.
+ * (Note that RPC tasks aren't kernel threads. Take a look at the
+ * rpciod code to understand what they are).
+ *
+ * Inside the cache object, we also maintain a count of the current number
+ * of dirty pages, which may not exceed a certain threshold.
+ * (FIXME: This threshold should be configurable).
+ *
+ * The code is streamlined for what I think is the prevalent case for
+ * NFS traffic, which is sequential write access without concurrent
+ * access by different processes.
+ *
+ * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
+ *
+ * Rewritten 6/3/2000 by Trond Myklebust
+ * Copyright (C) 1999, 2000, Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/pagemap.h>
+#include <linux/file.h>
+
+#include <linux/sched.h>
+
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sched.h>
+
+#include <linux/spinlock.h>
+
+#include <linux/nfs.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/nfs_flushd.h>
+#include <linux/nfs_mount.h>
+
+/*
+ * Various constants
+ */
+#define NFSDBG_FACILITY NFSDBG_PAGECACHE
+
+/*
+ * This is the wait queue all cluster daemons sleep on
+ */
+static struct rpc_wait_queue flushd_queue = RPC_INIT_WAITQ("nfs_flushd");
+
+/*
+ * Spinlock
+ */
+spinlock_t nfs_flushd_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Local function declarations.
+ */
+static void nfs_flushd(struct rpc_task *);
+static void nfs_flushd_exit(struct rpc_task *);
+
+
+int nfs_reqlist_init(struct nfs_server *server)
+{
+ struct nfs_reqlist *cache;
+ struct rpc_task *task;
+ int status = 0;
+
+ dprintk("NFS: writecache_init\n");
+ spin_lock(&nfs_flushd_lock);
+ cache = server->rw_requests;
+
+ if (cache->task)
+ goto out_unlock;
+
+ /* Create the RPC task */
+ status = -ENOMEM;
+ task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC);
+ if (!task)
+ goto out_unlock;
+
+ task->tk_calldata = server;
+
+ cache->task = task;
+
+ /* Run the task */
+ cache->runat = jiffies;
+
+ cache->auth = server->client->cl_auth;
+ task->tk_action = nfs_flushd;
+ task->tk_exit = nfs_flushd_exit;
+
+ spin_unlock(&nfs_flushd_lock);
+ rpc_execute(task);
+ return 0;
+ out_unlock:
+ spin_unlock(&nfs_flushd_lock);
+ return status;
+}
+
+void nfs_reqlist_exit(struct nfs_server *server)
+{
+ struct nfs_reqlist *cache;
+
+ cache = server->rw_requests;
+ if (!cache)
+ return;
+
+ dprintk("NFS: reqlist_exit (ptr %p rpc %p)\n", cache, cache->task);
+ while (cache->task || cache->inodes) {
+ spin_lock(&nfs_flushd_lock);
+ if (!cache->task) {
+ spin_unlock(&nfs_flushd_lock);
+ nfs_reqlist_init(server);
+ } else {
+ cache->task->tk_status = -ENOMEM;
+ rpc_wake_up_task(cache->task);
+ spin_unlock(&nfs_flushd_lock);
+ }
+ interruptible_sleep_on_timeout(&cache->request_wait, 1 * HZ);
+ }
+}
+
+int nfs_reqlist_alloc(struct nfs_server *server)
+{
+ struct nfs_reqlist *cache;
+ if (server->rw_requests)
+ return 0;
+
+ cache = (struct nfs_reqlist *)kmalloc(sizeof(*cache), GFP_KERNEL);
+ if (!cache)
+ return -ENOMEM;
+
+ memset(cache, 0, sizeof(*cache));
+ init_waitqueue_head(&cache->request_wait);
+ server->rw_requests = cache;
+
+ return 0;
+}
+
+void nfs_reqlist_free(struct nfs_server *server)
+{
+ if (server->rw_requests) {
+ kfree(server->rw_requests);
+ server->rw_requests = NULL;
+ }
+}
+
+void nfs_wake_flushd()
+{
+ rpc_wake_up_status(&flushd_queue, -ENOMEM);
+}
+
+static void inode_append_flushd(struct inode *inode)
+{
+ struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
+ struct inode **q;
+
+ spin_lock(&nfs_flushd_lock);
+ if (NFS_FLAGS(inode) & NFS_INO_FLUSH)
+ goto out;
+ inode->u.nfs_i.hash_next = NULL;
+
+ q = &cache->inodes;
+ while (*q)
+ q = &(*q)->u.nfs_i.hash_next;
+ *q = inode;
+
+ /* Note: we increase the inode i_count in order to prevent
+ * it from disappearing when on the flush list
+ */
+ NFS_FLAGS(inode) |= NFS_INO_FLUSH;
+ inode->i_count++;
+ out:
+ spin_unlock(&nfs_flushd_lock);
+}
+
+void inode_remove_flushd(struct inode *inode)
+{
+ struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
+ struct inode **q;
+
+ spin_lock(&nfs_flushd_lock);
+ if (!(NFS_FLAGS(inode) & NFS_INO_FLUSH))
+ goto out;
+
+ q = &cache->inodes;
+ while (*q && *q != inode)
+ q = &(*q)->u.nfs_i.hash_next;
+ if (*q) {
+ *q = inode->u.nfs_i.hash_next;
+ NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
+ iput(inode);
+ }
+ out:
+ spin_unlock(&nfs_flushd_lock);
+}
+
+void inode_schedule_scan(struct inode *inode, unsigned long time)
+{
+ struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
+ struct rpc_task *task;
+ unsigned long mintimeout;
+
+ if (time_after(NFS_NEXTSCAN(inode), time))
+ NFS_NEXTSCAN(inode) = time;
+ mintimeout = jiffies + 1 * HZ;
+ if (time_before(mintimeout, NFS_NEXTSCAN(inode)))
+ mintimeout = NFS_NEXTSCAN(inode);
+ inode_append_flushd(inode);
+
+ spin_lock(&nfs_flushd_lock);
+ task = cache->task;
+ if (!task) {
+ spin_unlock(&nfs_flushd_lock);
+ nfs_reqlist_init(NFS_SERVER(inode));
+ } else {
+ if (time_after(cache->runat, mintimeout))
+ rpc_wake_up_task(task);
+ spin_unlock(&nfs_flushd_lock);
+ }
+}
+
+
+static void
+nfs_flushd(struct rpc_task *task)
+{
+ struct nfs_server *server;
+ struct nfs_reqlist *cache;
+ struct inode *inode, *next;
+ unsigned long delay = jiffies + NFS_WRITEBACK_LOCKDELAY;
+ int flush = (task->tk_status == -ENOMEM);
+
+ dprintk("NFS: %4d flushd starting\n", task->tk_pid);
+ server = (struct nfs_server *) task->tk_calldata;
+ cache = server->rw_requests;
+
+ spin_lock(&nfs_flushd_lock);
+ next = cache->inodes;
+ cache->inodes = NULL;
+ spin_unlock(&nfs_flushd_lock);
+
+ while ((inode = next) != NULL) {
+ next = next->u.nfs_i.hash_next;
+ inode->u.nfs_i.hash_next = NULL;
+ NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
+
+ if (flush) {
+ nfs_sync_file(inode, NULL, 0, 0, FLUSH_AGING);
+ } else if (time_after(jiffies, NFS_NEXTSCAN(inode))) {
+ NFS_NEXTSCAN(inode) = jiffies + NFS_WRITEBACK_LOCKDELAY;
+ nfs_flush_timeout(inode, FLUSH_AGING);
+#ifdef CONFIG_NFS_V3
+ nfs_commit_timeout(inode, FLUSH_AGING);
+#endif
+ }
+
+ if (nfs_have_writebacks(inode)) {
+ inode_append_flushd(inode);
+ if (time_after(delay, NFS_NEXTSCAN(inode)))
+ delay = NFS_NEXTSCAN(inode);
+ }
+ iput(inode);
+ }
+
+ dprintk("NFS: %4d flushd back to sleep\n", task->tk_pid);
+ if (time_after(jiffies + 1 * HZ, delay))
+ delay = 1 * HZ;
+ else
+ delay = delay - jiffies;
+ task->tk_status = 0;
+ task->tk_action = nfs_flushd;
+ task->tk_timeout = delay;
+ cache->runat = jiffies + task->tk_timeout;
+
+ spin_lock(&nfs_flushd_lock);
+ if (!cache->nr_requests && !cache->inodes) {
+ cache->task = NULL;
+ task->tk_action = NULL;
+ } else
+ rpc_sleep_on(&flushd_queue, task, NULL, NULL);
+ spin_unlock(&nfs_flushd_lock);
+}
+
+static void
+nfs_flushd_exit(struct rpc_task *task)
+{
+ struct nfs_server *server;
+ struct nfs_reqlist *cache;
+ server = (struct nfs_server *) task->tk_calldata;
+ cache = server->rw_requests;
+
+ spin_lock(&nfs_flushd_lock);
+ if (cache->task == task)
+ cache->task = NULL;
+ spin_unlock(&nfs_flushd_lock);
+ wake_up(&cache->request_wait);
+ rpc_release_task(task);
+}
+
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 441d62edc..ca7e1b944 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -27,6 +27,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_flushd.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
@@ -74,6 +75,12 @@ nfs_read_inode(struct inode * inode)
inode->i_rdev = 0;
NFS_FILEID(inode) = 0;
NFS_FSID(inode) = 0;
+ INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
+ INIT_LIST_HEAD(&inode->u.nfs_i.commit);
+ INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
+ inode->u.nfs_i.ndirty = 0;
+ inode->u.nfs_i.ncommit = 0;
+ inode->u.nfs_i.npages = 0;
NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
}
@@ -92,8 +99,6 @@ nfs_put_inode(struct inode * inode)
static void
nfs_delete_inode(struct inode * inode)
{
- int failed;
-
dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
lock_kernel();
@@ -101,29 +106,12 @@ nfs_delete_inode(struct inode * inode)
nfs_free_dircache(inode);
} else {
/*
- * Flush out any pending write requests ...
+ * The following can never actually happen...
*/
- if (NFS_WRITEBACK(inode) != NULL) {
- unsigned long timeout = jiffies + 5*HZ;
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
-#endif
- nfs_inval(inode);
- while (NFS_WRITEBACK(inode) != NULL &&
- time_before(jiffies, timeout)) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/10);
- }
- current->state = TASK_RUNNING;
- if (NFS_WRITEBACK(inode) != NULL)
- printk("NFS: Arghhh, stuck RPC requests!\n");
+ if (nfs_have_writebacks(inode)) {
+ printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
}
}
-
- failed = nfs_check_failed_request(inode);
- if (failed)
- printk("NFS: inode %ld had %d failed requests\n",
- inode->i_ino, failed);
unlock_kernel();
clear_inode(inode);
@@ -135,9 +123,18 @@ nfs_put_super(struct super_block *sb)
struct nfs_server *server = &sb->u.nfs_sb.s_server;
struct rpc_clnt *rpc;
+ /*
+ * First get rid of the request flushing daemon.
+ * Relies on rpc_shutdown_client() waiting on all
+ * client tasks to finish.
+ */
+ nfs_reqlist_exit(server);
+
if ((rpc = server->client) != NULL)
rpc_shutdown_client(rpc);
+ nfs_reqlist_free(server);
+
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_down(); /* release rpc.lockd */
rpciod_down(); /* release rpciod */
@@ -306,6 +303,12 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
sb->s_root->d_op = &nfs_dentry_operations;
sb->s_root->d_fsdata = root_fh;
+ /* Fire up the writeback cache */
+ if (nfs_reqlist_alloc(server) < 0) {
+ printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
+ goto failure_kill_reqlist;
+ }
+
/* We're airborne */
/* Check whether to start the lockd process */
@@ -314,6 +317,8 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
return sb;
/* Yargs. It didn't work out. */
+ failure_kill_reqlist:
+ nfs_reqlist_exit(server);
out_no_root:
printk("nfs_read_super: get root inode failed\n");
iput(root_inode);
@@ -342,6 +347,7 @@ out_no_xprt:
printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
out_free_host:
+ nfs_reqlist_free(server);
kfree(server->hostname);
out_unlock:
goto out_fail;
@@ -440,7 +446,6 @@ nfs_invalidate_inode(struct inode *inode)
make_bad_inode(inode);
inode->i_mode = save_mode;
- nfs_inval(inode);
nfs_zap_caches(inode);
}
@@ -864,7 +869,7 @@ nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
* to look at the size or the mtime the server sends us
* too closely, as we're in the middle of modifying them.
*/
- if (NFS_WRITEBACK(inode))
+ if (nfs_have_writebacks(inode))
goto out;
if (inode->i_size != fattr->size) {
@@ -925,7 +930,7 @@ printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, 0);
extern int nfs_init_fhcache(void);
-extern int nfs_init_wreqcache(void);
+extern int nfs_init_nfspagecache(void);
/*
* Initialize NFS
@@ -939,7 +944,7 @@ init_nfs_fs(void)
if (err)
return err;
- err = nfs_init_wreqcache();
+ err = nfs_init_nfspagecache();
if (err)
return err;
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index a7e53e6db..5ad2aaa67 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -63,6 +63,7 @@ static int nfs_stat_to_errno(int stat);
#define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
#define NFS_readlinkres_sz 1
#define NFS_readres_sz 1+NFS_fattr_sz+1
+#define NFS_writeres_sz NFS_attrstat_sz
#define NFS_stat_sz 1
#define NFS_readdirres_sz 1
#define NFS_statfsres_sz 1+NFS_info_sz
@@ -273,6 +274,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
static int
nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
{
+ unsigned int nr;
u32 count = args->count;
p = xdr_encode_fhandle(p, args->fh);
@@ -282,28 +284,35 @@ nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
*p++ = htonl(count);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- req->rq_svec[1].iov_base = (void *) args->buffer;
- req->rq_svec[1].iov_len = count;
- req->rq_slen += count;
- req->rq_snr = 2;
+ /* Get the number of buffers in the send iovec */
+ nr = args->nriov;
+
+ if (nr+2 > MAX_IOVEC) {
+ printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
+ "(nr %d max %d)\n", nr, MAX_IOVEC);
+ return -EINVAL;
+ }
+
+ /* Copy the iovec */
+ memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
#ifdef NFS_PAD_WRITES
/*
* Some old servers require that the message length
* be a multiple of 4, so we pad it here if needed.
*/
- count = ((count + 3) & ~3) - count;
- if (count) {
-#if 0
-printk("nfs_writeargs: padding write, len=%d, slen=%d, pad=%d\n",
-req->rq_svec[1].iov_len, req->rq_slen, count);
-#endif
- req->rq_svec[2].iov_base = (void *) "\0\0\0";
- req->rq_svec[2].iov_len = count;
- req->rq_slen += count;
- req->rq_snr = 3;
+ if (count & 3) {
+ struct iovec *iov = req->rq_svec + nr + 1;
+ int pad = 4 - (count & 3);
+
+ iov->iov_base = (void *) "\0\0\0";
+ iov->iov_len = pad;
+ count += pad;
+ nr++;
}
#endif
+ req->rq_slen += count;
+ req->rq_snr += nr;
return 0;
}
@@ -593,6 +602,16 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
}
/*
+ * Decode WRITE reply
+ */
+static int
+nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+{
+ res->verf->committed = NFS_FILE_SYNC;
+ return nfs_xdr_attrstat(req, p, res->fattr);
+}
+
+/*
* Decode STATFS reply
*/
static int
@@ -678,7 +697,7 @@ static struct rpc_procinfo nfs_procedures[18] = {
PROC(readlink, readlinkargs, readlinkres),
PROC(read, readargs, readres),
PROC(writecache, enc_void, dec_void),
- PROC(write, writeargs, attrstat),
+ PROC(write, writeargs, writeres),
PROC(create, createargs, diropres),
PROC(remove, diropargs, stat),
PROC(rename, renameargs, stat),
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index d9a423f16..a592608be 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -145,6 +145,8 @@ static struct nfs_bool_opts {
{ "nocto", ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO },
{ "ac", ~NFS_MOUNT_NOAC, 0 },
{ "noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC },
+ { "lock", ~NFS_MOUNT_NONLM, 0 },
+ { "nolock", ~NFS_MOUNT_NONLM, NFS_MOUNT_NONLM },
{ NULL, 0, 0 }
};
@@ -320,7 +322,7 @@ int __init root_nfs_init(void)
* Parse NFS server and directory information passed on the kernel
* command line.
*/
-void __init nfs_root_setup(char *line)
+int __init nfs_root_setup(char *line)
{
ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
@@ -333,6 +335,7 @@ void __init nfs_root_setup(char *line)
sprintf(nfs_root_name, NFS_ROOT, line);
}
root_nfs_parse_addr(nfs_root_name);
+ return 1;
}
__setup("nfsroot=", nfs_root_setup);
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index bb55ce6d6..3823c3118 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -111,11 +111,15 @@ nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, int swap,
unsigned long offset, unsigned int count,
const void *buffer, struct nfs_fattr *fattr)
{
- struct nfs_writeargs arg = { fhandle, offset, count, buffer };
+ struct nfs_writeargs arg = { fhandle, offset, count, 1, 1,
+ {{(void *) buffer, count}, {0,0}, {0,0}, {0,0},
+ {0,0}, {0,0}, {0,0}, {0,0}}};
+ struct nfs_writeverf verf;
+ struct nfs_writeres res = {fattr, &verf, count};
int status;
dprintk("NFS call write %d @ %ld\n", count, offset);
- status = rpc_call(server->client, NFSPROC_WRITE, &arg, fattr,
+ status = rpc_call(server->client, NFSPROC_WRITE, &arg, &res,
swap? (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) : 0);
dprintk("NFS reply read: %d\n", status);
return status < 0? status : count;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 717d12bbb..aa17780e5 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -171,6 +171,7 @@ static inline int
nfs_readpage_async(struct dentry *dentry, struct inode *inode,
struct page *page)
{
+ struct rpc_message msg;
unsigned long address;
struct nfs_rreq *req;
int result = -1, flags;
@@ -195,8 +196,13 @@ nfs_readpage_async(struct dentry *dentry, struct inode *inode,
/* Start the async call */
dprintk("NFS: executing async READ request.\n");
- result = rpc_do_call(NFS_CLIENT(inode), NFSPROC_READ,
- &req->ra_args, &req->ra_res, flags,
+
+ msg.rpc_proc = NFSPROC_READ;
+ msg.rpc_argp = &req->ra_args;
+ msg.rpc_resp = &req->ra_res;
+ msg.rpc_cred = NULL;
+
+ result = rpc_call_async(NFS_CLIENT(inode), &msg, flags,
nfs_readpage_result, req);
if (result < 0)
goto out_free;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 5f847bec8..af023a121 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -46,6 +46,7 @@
* Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/swap.h>
@@ -54,33 +55,126 @@
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_flushd.h>
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
#define NFS_PARANOIA 1
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
-static void nfs_wback_begin(struct rpc_task *task);
-static void nfs_wback_result(struct rpc_task *task);
-static void nfs_cancel_request(struct nfs_wreq *req);
+/*
+ * Spinlock
+ */
+spinlock_t nfs_wreq_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int nfs_nr_requests = 0;
/*
- * Cache parameters
+ * Local structures
+ *
+ * Valid flags for a dirty buffer
*/
-#define NFS_WRITEBACK_DELAY (10 * HZ)
-#define NFS_WRITEBACK_MAX 64
+#define PG_BUSY 0x0001
/*
- * Limit number of delayed writes
+ * This is the struct where the WRITE/COMMIT arguments go.
*/
-static int nr_write_requests = 0;
-static struct rpc_wait_queue write_queue = RPC_INIT_WAITQ("write_chain");
+struct nfs_write_data {
+ struct rpc_task task;
+ struct file *file;
+ struct rpc_cred *cred;
+ struct nfs_writeargs args; /* argument struct */
+ struct nfs_writeres res; /* result struct */
+ struct nfs_fattr fattr;
+ struct nfs_writeverf verf;
+ struct list_head pages; /* Coalesced requests we wish to flush */
+};
+
+struct nfs_page {
+ struct list_head wb_hash, /* Inode */
+ wb_list,
+ *wb_list_head;
+ struct file *wb_file;
+ struct rpc_cred *wb_cred;
+ struct page *wb_page; /* page to write out */
+ wait_queue_head_t wb_wait; /* wait queue */
+ unsigned long wb_timeout; /* when to write/commit */
+ unsigned int wb_offset, /* Offset of write */
+ wb_bytes, /* Length of request */
+ wb_count, /* reference count */
+ wb_flags;
+ struct nfs_writeverf wb_verf; /* Commit cookie */
+};
+
+#define NFS_WBACK_BUSY(req) ((req)->wb_flags & PG_BUSY)
+
+/*
+ * Local function declarations
+ */
+static void nfs_writeback_done(struct rpc_task *);
+#ifdef CONFIG_NFS_V3
+static void nfs_commit_done(struct rpc_task *);
+#endif
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
#endif
+static kmem_cache_t *nfs_page_cachep = NULL;
+static kmem_cache_t *nfs_wdata_cachep = NULL;
+
+static __inline__ struct nfs_page *nfs_page_alloc(void)
+{
+ struct nfs_page *p;
+ p = kmem_cache_alloc(nfs_page_cachep, SLAB_KERNEL);
+ if (p) {
+ memset(p, 0, sizeof(*p));
+ INIT_LIST_HEAD(&p->wb_hash);
+ INIT_LIST_HEAD(&p->wb_list);
+ init_waitqueue_head(&p->wb_wait);
+ }
+ return p;
+}
+
+static __inline__ void nfs_page_free(struct nfs_page *p)
+{
+ kmem_cache_free(nfs_page_cachep, p);
+}
+
+static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
+{
+ struct nfs_write_data *p;
+ p = kmem_cache_alloc(nfs_wdata_cachep, SLAB_NFS);
+ if (p) {
+ memset(p, 0, sizeof(*p));
+ INIT_LIST_HEAD(&p->pages);
+ }
+ return p;
+}
+
+static __inline__ void nfs_writedata_free(struct nfs_write_data *p)
+{
+ kmem_cache_free(nfs_wdata_cachep, p);
+}
+
+static void nfs_writedata_release(struct rpc_task *task)
+{
+ struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
+ rpc_release_task(task);
+ nfs_writedata_free(wdata);
+}
+
+/*
+ * This function will be used to simulate weak cache consistency
+ * under NFSv2 when the NFSv3 attribute patch is included.
+ * For the moment, we just call nfs_refresh_inode().
+ */
+static __inline__ int
+nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
+{
+ return nfs_refresh_inode(inode, fattr);
+}
+
/*
* Write a page synchronously.
* Offset is the data offset within the page.
@@ -161,278 +255,770 @@ io_error:
}
/*
- * Append a writeback request to a list
+ * Write a page to the server. This was supposed to be used for
+ * NFS swapping only.
+ * FIXME: Using this for mmap is pointless, breaks asynchronous
+ * writebacks, and is extremely slow.
*/
-static inline void
-append_write_request(struct nfs_wreq **q, struct nfs_wreq *wreq)
+int
+nfs_writepage(struct dentry * dentry, struct page *page)
{
- dprintk("NFS: append_write_request(%p, %p)\n", q, wreq);
- rpc_append_list(q, wreq);
+ struct inode *inode = dentry->d_inode;
+ unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ unsigned offset = PAGE_CACHE_SIZE;
+ int err;
+
+ /* easy case */
+ if (page->index < end_index)
+ goto do_it;
+ /* things got complicated... */
+ offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+ /* OK, are we completely out? */
+ if (page->index >= end_index+1 || !offset)
+ return -EIO;
+do_it:
+ err = nfs_writepage_sync(dentry, inode, page, 0, offset);
+ if ( err == offset) return 0;
+ return err;
+}
+
+/*
+ * Check whether the file range we want to write to is locked by
+ * us.
+ */
+static int
+region_locked(struct inode *inode, struct nfs_page *req)
+{
+ struct file_lock *fl;
+ unsigned long rqstart, rqend;
+
+ /* Don't optimize writes if we don't use NLM */
+ if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
+ return 0;
+
+ rqstart = page_offset(req->wb_page) + req->wb_offset;
+ rqend = rqstart + req->wb_bytes;
+ for (fl = inode->i_flock; fl; fl = fl->fl_next) {
+ if (fl->fl_owner == current->files && (fl->fl_flags & FL_POSIX)
+ && fl->fl_type == F_WRLCK
+ && fl->fl_start <= rqstart && rqend <= fl->fl_end) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static inline struct nfs_page *
+nfs_inode_wb_entry(struct list_head *head)
+{
+ return list_entry(head, struct nfs_page, wb_hash);
}
/*
- * Remove a writeback request from a list
+ * Insert a write request into an inode
*/
static inline void
-remove_write_request(struct nfs_wreq **q, struct nfs_wreq *wreq)
+nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
{
- dprintk("NFS: remove_write_request(%p, %p)\n", q, wreq);
- rpc_remove_list(q, wreq);
+ if (!list_empty(&req->wb_hash))
+ return;
+ if (!NFS_WBACK_BUSY(req))
+ printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
+ inode->u.nfs_i.npages++;
+ list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
+ req->wb_count++;
}
/*
- * Find a non-busy write request for a given page to
- * try to combine with.
+ * Insert a write request into an inode
*/
-static inline struct nfs_wreq *
-find_write_request(struct inode *inode, struct page *page)
+static inline void
+nfs_inode_remove_request(struct nfs_page *req)
{
- pid_t pid = current->pid;
- struct nfs_wreq *head, *req;
+ struct inode *inode;
+ spin_lock(&nfs_wreq_lock);
+ if (list_empty(&req->wb_hash)) {
+ spin_unlock(&nfs_wreq_lock);
+ return;
+ }
+ if (!NFS_WBACK_BUSY(req))
+ printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
+ inode = req->wb_file->f_dentry->d_inode;
+ list_del(&req->wb_hash);
+ INIT_LIST_HEAD(&req->wb_hash);
+ inode->u.nfs_i.npages--;
+ if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
+ if (!nfs_have_writebacks(inode))
+ inode_remove_flushd(inode);
+ spin_unlock(&nfs_wreq_lock);
+ nfs_release_request(req);
+}
- dprintk("NFS: find_write_request(%x/%ld, %p)\n",
- inode->i_dev, inode->i_ino, page);
- if (!(req = head = NFS_WRITEBACK(inode)))
- return NULL;
- do {
- /*
- * We can't combine with canceled requests or
- * requests that have already been started..
- */
- if (req->wb_flags & (NFS_WRITE_CANCELLED | NFS_WRITE_INPROGRESS))
+/*
+ * Find a request
+ */
+static inline struct nfs_page *
+_nfs_find_request(struct inode *inode, struct page *page)
+{
+ struct list_head *head, *next;
+
+ head = &inode->u.nfs_i.writeback;
+ next = head->next;
+ while (next != head) {
+ struct nfs_page *req = nfs_inode_wb_entry(next);
+ next = next->next;
+ if (page_index(req->wb_page) != page_index(page))
continue;
+ req->wb_count++;
+ return req;
+ }
+ return NULL;
+}
- if (req->wb_page == page && req->wb_pid == pid)
- return req;
+struct nfs_page *
+nfs_find_request(struct inode *inode, struct page *page)
+{
+ struct nfs_page *req;
- /*
- * Ehh, don't keep too many tasks queued..
- */
- rpc_wake_up_task(&req->wb_task);
+ spin_lock(&nfs_wreq_lock);
+ req = _nfs_find_request(inode, page);
+ spin_unlock(&nfs_wreq_lock);
+ return req;
+}
- } while ((req = WB_NEXT(req)) != head);
- return NULL;
+static inline struct nfs_page *
+nfs_list_entry(struct list_head *head)
+{
+ return list_entry(head, struct nfs_page, wb_list);
}
/*
- * Find and release all failed requests for this inode.
+ * Insert a write request into a sorted list
*/
-int
-nfs_check_failed_request(struct inode * inode)
+static inline void
+nfs_list_add_request(struct nfs_page *req, struct list_head *head)
{
- /* FIXME! */
- return 0;
+ struct list_head *prev;
+
+ if (!list_empty(&req->wb_list)) {
+ printk(KERN_ERR "NFS: Add to list failed!\n");
+ return;
+ }
+ if (list_empty(&req->wb_hash)) {
+ printk(KERN_ERR "NFS: Unhashed request attempted added to a list!\n");
+ return;
+ }
+ if (!NFS_WBACK_BUSY(req))
+ printk(KERN_ERR "NFS: unlocked request attempted added to list!\n");
+ prev = head->prev;
+ while (prev != head) {
+ struct nfs_page *p = nfs_list_entry(prev);
+ if (page_index(p->wb_page) < page_index(req->wb_page))
+ break;
+ prev = prev->prev;
+ }
+ list_add(&req->wb_list, prev);
+ req->wb_list_head = head;
}
/*
- * Try to merge adjacent write requests. This works only for requests
- * issued by the same user.
+ * Insert a write request into an inode
*/
-static inline int
-update_write_request(struct nfs_wreq *req, unsigned int first,
- unsigned int bytes)
+static inline void
+nfs_list_remove_request(struct nfs_page *req)
{
- unsigned int rqfirst = req->wb_offset,
- rqlast = rqfirst + req->wb_bytes,
- last = first + bytes;
+ if (list_empty(&req->wb_list))
+ return;
+ if (!NFS_WBACK_BUSY(req))
+ printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n");
+ list_del(&req->wb_list);
+ INIT_LIST_HEAD(&req->wb_list);
+ req->wb_list_head = NULL;
+}
- dprintk("nfs: trying to update write request %p\n", req);
+/*
+ * Add a request to the inode's dirty list.
+ */
+static inline void
+nfs_mark_request_dirty(struct nfs_page *req)
+{
+ struct inode *inode = req->wb_file->f_dentry->d_inode;
- /* not contiguous? */
- if (rqlast < first || last < rqfirst)
- return 0;
+ spin_lock(&nfs_wreq_lock);
+ if (list_empty(&req->wb_list)) {
+ nfs_list_add_request(req, &inode->u.nfs_i.dirty);
+ inode->u.nfs_i.ndirty++;
+ }
+ spin_unlock(&nfs_wreq_lock);
+ /*
+ * NB: the call to inode_schedule_scan() must lie outside the
+ * spinlock since it can run flushd().
+ */
+ inode_schedule_scan(inode, req->wb_timeout);
+}
- if (first < rqfirst)
- rqfirst = first;
- if (rqlast < last)
- rqlast = last;
+/*
+ * Check if a request is dirty
+ */
+static inline int
+nfs_dirty_request(struct nfs_page *req)
+{
+ struct inode *inode = req->wb_file->f_dentry->d_inode;
+ return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
+}
- req->wb_offset = rqfirst;
- req->wb_bytes = rqlast - rqfirst;
- req->wb_count++;
+#ifdef CONFIG_NFS_V3
+/*
+ * Add a request to the inode's commit list.
+ */
+static inline void
+nfs_mark_request_commit(struct nfs_page *req)
+{
+ struct inode *inode = req->wb_file->f_dentry->d_inode;
- return 1;
+ spin_lock(&nfs_wreq_lock);
+ if (list_empty(&req->wb_list)) {
+ nfs_list_add_request(req, &inode->u.nfs_i.commit);
+ inode->u.nfs_i.ncommit++;
+ }
+ spin_unlock(&nfs_wreq_lock);
+ /*
+ * NB: the call to inode_schedule_scan() must lie outside the
+ * spinlock since it can run flushd().
+ */
+ inode_schedule_scan(inode, req->wb_timeout);
}
+#endif
-static kmem_cache_t *nfs_wreq_cachep;
-
-int nfs_init_wreqcache(void)
+/*
+ * Lock the page of an asynchronous request
+ */
+static inline int
+nfs_lock_request(struct nfs_page *req)
{
- nfs_wreq_cachep = kmem_cache_create("nfs_wreq",
- sizeof(struct nfs_wreq),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (nfs_wreq_cachep == NULL)
- return -ENOMEM;
- return 0;
+ if (NFS_WBACK_BUSY(req))
+ return 0;
+ req->wb_count++;
+ req->wb_flags |= PG_BUSY;
+ return 1;
}
static inline void
-free_write_request(struct nfs_wreq * req)
+nfs_unlock_request(struct nfs_page *req)
{
- if (!--req->wb_count)
- kmem_cache_free(nfs_wreq_cachep, req);
+ if (!NFS_WBACK_BUSY(req)) {
+ printk(KERN_ERR "NFS: Invalid unlock attempted\n");
+ return;
+ }
+ req->wb_flags &= ~PG_BUSY;
+ wake_up(&req->wb_wait);
+ nfs_release_request(req);
}
/*
- * Create and initialize a writeback request
+ * Create a write request.
+ * Page must be locked by the caller. This makes sure we never create
+ * two different requests for the same page, and avoids possible deadlock
+ * when we reach the hard limit on the number of dirty pages.
*/
-static inline struct nfs_wreq *
-create_write_request(struct file * file, struct page *page, unsigned int offset, unsigned int bytes)
+static struct nfs_page *
+nfs_create_request(struct inode *inode, struct file *file, struct page *page,
+ unsigned int offset, unsigned int count)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct rpc_clnt *clnt = NFS_CLIENT(inode);
- struct nfs_wreq *wreq;
- struct rpc_task *task;
+ struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
+ struct nfs_page *req = NULL;
+ long timeout;
- dprintk("NFS: create_write_request(%s/%s, %ld+%d)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
- (page->index << PAGE_CACHE_SHIFT) + offset, bytes);
-
- /* FIXME: Enforce hard limit on number of concurrent writes? */
- wreq = kmem_cache_alloc(nfs_wreq_cachep, SLAB_KERNEL);
- if (!wreq)
- goto out_fail;
- memset(wreq, 0, sizeof(*wreq));
+ /* Deal with hard/soft limits.
+ */
+ do {
+ /* If we're over the soft limit, flush out old requests */
+ if (nfs_nr_requests >= MAX_REQUEST_SOFT)
+ nfs_wb_file(inode, file);
+
+ /* If we're still over the soft limit, wake up some requests */
+ if (nfs_nr_requests >= MAX_REQUEST_SOFT) {
+ dprintk("NFS: hit soft limit (%d requests)\n",
+ nfs_nr_requests);
+ if (!cache->task)
+ nfs_reqlist_init(NFS_SERVER(inode));
+ nfs_wake_flushd();
+ }
- task = &wreq->wb_task;
- rpc_init_task(task, clnt, nfs_wback_result, RPC_TASK_NFSWRITE);
- task->tk_calldata = wreq;
- task->tk_action = nfs_wback_begin;
+ /* If we haven't reached the hard limit yet,
+ * try to allocate the request struct */
+ if (nfs_nr_requests < MAX_REQUEST_HARD) {
+ req = nfs_page_alloc();
+ if (req != NULL)
+ break;
+ }
- rpcauth_lookupcred(task); /* Obtain user creds */
- if (task->tk_status < 0)
- goto out_req;
+ /* We're over the hard limit. Wait for better times */
+ dprintk("NFS: create_request sleeping (total %d pid %d)\n",
+ nfs_nr_requests, current->pid);
+
+ timeout = 1 * HZ;
+ if (NFS_SERVER(inode)->flags & NFS_MOUNT_INTR) {
+ interruptible_sleep_on_timeout(&cache->request_wait,
+ timeout);
+ if (signalled())
+ break;
+ } else
+ sleep_on_timeout(&cache->request_wait, timeout);
+
+ dprintk("NFS: create_request waking up (tot %d pid %d)\n",
+ nfs_nr_requests, current->pid);
+ } while (!req);
+ if (!req)
+ return NULL;
- /* Put the task on inode's writeback request list. */
+ /* Initialize the request struct. Initially, we assume a
+ * long write-back delay. This will be adjusted in
+ * update_nfs_request below if the region is not locked. */
+ req->wb_page = page;
+ atomic_inc(&page->count);
+ req->wb_offset = offset;
+ req->wb_bytes = count;
+ /* If the region is locked, adjust the timeout */
+ if (region_locked(inode, req))
+ req->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
+ else
+ req->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;
+ req->wb_file = file;
+ req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
get_file(file);
- wreq->wb_file = file;
- wreq->wb_pid = current->pid;
- wreq->wb_page = page;
- init_waitqueue_head(&wreq->wb_wait);
- wreq->wb_offset = offset;
- wreq->wb_bytes = bytes;
- wreq->wb_count = 2; /* One for the IO, one for us */
+ req->wb_count = 1;
- kmap(page);
- append_write_request(&NFS_WRITEBACK(inode), wreq);
+ /* register request's existence */
+ cache->nr_requests++;
+ nfs_nr_requests++;
+ return req;
+}
- if (nr_write_requests++ > NFS_WRITEBACK_MAX*3/4)
- rpc_wake_up_next(&write_queue);
- return wreq;
+/*
+ * Release all resources associated with a write request after it
+ * has been committed to stable storage
+ *
+ * Note: Should always be called with the spinlock held!
+ */
+void
+nfs_release_request(struct nfs_page *req)
+{
+ struct inode *inode = req->wb_file->f_dentry->d_inode;
+ struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
+ struct page *page = req->wb_page;
+
+ spin_lock(&nfs_wreq_lock);
+ if (--req->wb_count) {
+ spin_unlock(&nfs_wreq_lock);
+ return;
+ }
+ spin_unlock(&nfs_wreq_lock);
-out_req:
- rpc_release_task(task);
- kmem_cache_free(nfs_wreq_cachep, wreq);
-out_fail:
- return NULL;
+ if (!list_empty(&req->wb_list)) {
+ printk(KERN_ERR "NFS: Request released while still on a list!\n");
+ nfs_list_remove_request(req);
+ }
+ if (!list_empty(&req->wb_hash)) {
+ printk(KERN_ERR "NFS: Request released while still hashed!\n");
+ nfs_inode_remove_request(req);
+ }
+ if (NFS_WBACK_BUSY(req))
+ printk(KERN_ERR "NFS: Request released while still locked!\n");
+
+ rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
+ fput(req->wb_file);
+ page_cache_release(page);
+ nfs_page_free(req);
+ /* wake up anyone waiting to allocate a request */
+ cache->nr_requests--;
+ nfs_nr_requests--;
+ wake_up(&cache->request_wait);
}
/*
- * Schedule a writeback RPC call.
- * If the server is congested, don't add to our backlog of queued
- * requests but call it synchronously.
- * The function returns whether we should wait for the thing or not.
+ * Wait for a request to complete.
*
- * FIXME: Here we could walk the inode's lock list to see whether the
- * page we're currently writing to has been write-locked by the caller.
- * If it is, we could schedule an async write request with a long
- * delay in order to avoid writing back the page until the lock is
- * released.
+ * Interruptible by signals only if mounted with intr flag.
*/
-static inline int
-schedule_write_request(struct nfs_wreq *req, int sync)
+static int
+nfs_wait_on_request(struct nfs_page *req)
{
- struct rpc_task *task = &req->wb_task;
- struct file *file = req->wb_file;
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = req->wb_file->f_dentry->d_inode;
+ struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ int retval;
- if (NFS_CONGESTED(inode) || nr_write_requests >= NFS_WRITEBACK_MAX)
- sync = 1;
-
- if (sync) {
- sigset_t oldmask;
- struct rpc_clnt *clnt = NFS_CLIENT(inode);
- dprintk("NFS: %4d schedule_write_request (sync)\n",
- task->tk_pid);
- /* Page is already locked */
- rpc_clnt_sigmask(clnt, &oldmask);
- rpc_execute(task);
- rpc_clnt_sigunmask(clnt, &oldmask);
- } else {
- dprintk("NFS: %4d schedule_write_request (async)\n",
- task->tk_pid);
- task->tk_flags |= RPC_TASK_ASYNC;
- task->tk_timeout = NFS_WRITEBACK_DELAY;
- rpc_sleep_on(&write_queue, task, NULL, NULL);
+ if (!NFS_WBACK_BUSY(req))
+ return 0;
+ req->wb_count++;
+ retval = nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
+ nfs_release_request(req);
+ return retval;
+}
+
+/*
+ * Wait for a request to complete.
+ *
+ * Interruptible by signals only if mounted with intr flag.
+ */
+static int
+nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long start, unsigned int count)
+{
+ struct list_head *p, *head;
+ unsigned long idx_start, idx_end;
+ unsigned int pages = 0;
+ int error;
+
+ idx_start = start >> PAGE_CACHE_SHIFT;
+ if (count == 0)
+ idx_end = ~0;
+ else {
+ unsigned long idx_count = (count-1) >> PAGE_CACHE_SHIFT;
+ idx_end = idx_start + idx_count;
}
+ spin_lock(&nfs_wreq_lock);
+ head = &inode->u.nfs_i.writeback;
+ p = head->next;
+ while (p != head) {
+ unsigned long pg_idx;
+ struct nfs_page *req = nfs_inode_wb_entry(p);
+
+ p = p->next;
+
+ if (file && req->wb_file != file)
+ continue;
+
+ pg_idx = page_index(req->wb_page);
+ if (pg_idx < idx_start || pg_idx > idx_end)
+ continue;
- return sync;
+ if (!NFS_WBACK_BUSY(req))
+ continue;
+ req->wb_count++;
+ spin_unlock(&nfs_wreq_lock);
+ error = nfs_wait_on_request(req);
+ nfs_release_request(req);
+ if (error < 0)
+ return error;
+ spin_lock(&nfs_wreq_lock);
+ p = head->next;
+ pages++;
+ }
+ spin_unlock(&nfs_wreq_lock);
+ return pages;
}
/*
- * Wait for request to complete.
+ * Scan cluster for dirty pages and send as many of them to the
+ * server as possible.
*/
static int
-wait_on_write_request(struct nfs_wreq *req)
+nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode)
{
- struct file *file = req->wb_file;
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct rpc_clnt *clnt = NFS_CLIENT(inode);
- DECLARE_WAITQUEUE(wait, current);
- sigset_t oldmask;
- int retval;
+ struct list_head *p;
+ struct nfs_page *req;
+ int pages = 0;
+
+ p = head->next;
+ while (p != head) {
+ req = nfs_list_entry(p);
+ p = p->next;
+ if (time_after(req->wb_timeout, jiffies)) {
+ if (time_after(NFS_NEXTSCAN(inode), req->wb_timeout))
+ NFS_NEXTSCAN(inode) = req->wb_timeout;
+ continue;
+ }
+ if (!nfs_lock_request(req))
+ continue;
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, dst);
+ pages++;
+ }
+ return pages;
+}
+
+static int
+nfs_scan_dirty_timeout(struct inode *inode, struct list_head *dst)
+{
+ int pages;
+ spin_lock(&nfs_wreq_lock);
+ pages = nfs_scan_list_timeout(&inode->u.nfs_i.dirty, dst, inode);
+ inode->u.nfs_i.ndirty -= pages;
+ if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty))
+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
+ spin_unlock(&nfs_wreq_lock);
+ return pages;
+}
- /* Make sure it's started.. */
- if (!WB_INPROGRESS(req))
- rpc_wake_up_task(&req->wb_task);
+#ifdef CONFIG_NFS_V3
+static int
+nfs_scan_commit_timeout(struct inode *inode, struct list_head *dst)
+{
+ int pages;
+ spin_lock(&nfs_wreq_lock);
+ pages = nfs_scan_list_timeout(&inode->u.nfs_i.commit, dst, inode);
+ inode->u.nfs_i.ncommit -= pages;
+ if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit))
+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
+ spin_unlock(&nfs_wreq_lock);
+ return pages;
+}
+#endif
+
+static int
+nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+{
+ struct list_head *p;
+ struct nfs_page *req;
+ unsigned long idx_start, idx_end;
+ int pages;
+
+ pages = 0;
+ idx_start = start >> PAGE_CACHE_SHIFT;
+ if (count == 0)
+ idx_end = ~0;
+ else
+ idx_end = idx_start + ((count-1) >> PAGE_CACHE_SHIFT);
+ p = src->next;
+ while (p != src) {
+ unsigned long pg_idx;
+
+ req = nfs_list_entry(p);
+ p = p->next;
+
+ if (file && req->wb_file != file)
+ continue;
+
+ pg_idx = page_index(req->wb_page);
+ if (pg_idx < idx_start || pg_idx > idx_end)
+ continue;
+
+ if (!nfs_lock_request(req))
+ continue;
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, dst);
+ pages++;
+ }
+ return pages;
+}
+
+static int
+nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+{
+ int pages;
+ spin_lock(&nfs_wreq_lock);
+ pages = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, start, count);
+ inode->u.nfs_i.ndirty -= pages;
+ if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty))
+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
+ spin_unlock(&nfs_wreq_lock);
+ return pages;
+}
+
+#ifdef CONFIG_NFS_V3
+static int
+nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+{
+ int pages;
+ spin_lock(&nfs_wreq_lock);
+ pages = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, start, count);
+ inode->u.nfs_i.ncommit -= pages;
+ if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit))
+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
+ spin_unlock(&nfs_wreq_lock);
+ return pages;
+}
+#endif
+
+
+static int
+coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages)
+{
+ struct nfs_page *req = NULL;
+ unsigned int pages = 0;
+
+ while (!list_empty(src)) {
+ struct nfs_page *prev = req;
+
+ req = nfs_list_entry(src->next);
+ if (prev) {
+ if (req->wb_file != prev->wb_file)
+ break;
+
+ if (page_index(req->wb_page) != page_index(prev->wb_page)+1)
+ break;
+
+ if (req->wb_offset != 0)
+ break;
+ }
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, dst);
+ pages++;
+ if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE)
+ break;
+ if (pages >= maxpages)
+ break;
+ }
+ return pages;
+}
+
+/*
+ * Try to update any existing write request, or create one if there is none.
+ * In order to match, the request's credentials must match those of
+ * the calling process.
+ *
+ * Note: Should always be called with the Page Lock held!
+ */
+static struct nfs_page *
+nfs_update_request(struct file* file, struct page *page,
+ unsigned long offset, unsigned int bytes)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct nfs_page *req, *new = NULL;
+ unsigned long rqend, end;
+
+ end = offset + bytes;
- rpc_clnt_sigmask(clnt, &oldmask);
- add_wait_queue(&req->wb_wait, &wait);
for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- retval = 0;
- if (req->wb_flags & NFS_WRITE_COMPLETE)
+ /* Loop over all inode entries and see if we find
+ * A request for the page we wish to update
+ */
+ spin_lock(&nfs_wreq_lock);
+ req = _nfs_find_request(inode, page);
+ if (req) {
+ if (!nfs_lock_request(req)) {
+ spin_unlock(&nfs_wreq_lock);
+ nfs_wait_on_request(req);
+ nfs_release_request(req);
+ continue;
+ }
+ spin_unlock(&nfs_wreq_lock);
+ if (new)
+ nfs_release_request(new);
break;
- retval = -ERESTARTSYS;
- if (signalled())
+ }
+
+ req = new;
+ if (req) {
+ nfs_lock_request(req);
+ nfs_inode_add_request(inode, req);
+ spin_unlock(&nfs_wreq_lock);
+ nfs_mark_request_dirty(req);
break;
- schedule();
+ }
+ spin_unlock(&nfs_wreq_lock);
+
+ /* Create the request. It's safe to sleep in this call because
+ * we only get here if the page is locked.
+ */
+ new = nfs_create_request(inode, file, page, offset, bytes);
+ if (!new)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* We have a request for our page.
+ * If the creds don't match, or the
+ * page addresses don't match,
+ * tell the caller to wait on the conflicting
+ * request.
+ */
+ rqend = req->wb_offset + req->wb_bytes;
+ if (req->wb_file != file
+ || req->wb_page != page
+ || !nfs_dirty_request(req)
+ || offset > rqend || end < req->wb_offset) {
+ nfs_unlock_request(req);
+ nfs_release_request(req);
+ return ERR_PTR(-EBUSY);
+ }
+
+ /* Okay, the request matches. Update the region */
+ if (offset < req->wb_offset) {
+ req->wb_offset = offset;
+ req->wb_bytes = rqend - req->wb_offset;
}
- remove_wait_queue(&req->wb_wait, &wait);
- current->state = TASK_RUNNING;
- rpc_clnt_sigunmask(clnt, &oldmask);
- return retval;
+
+ if (end > rqend)
+ req->wb_bytes = end - req->wb_offset;
+
+ nfs_unlock_request(req);
+
+ return req;
}
/*
- * Write a page to the server. This will be used for NFS swapping only
- * (for now), and we currently do this synchronously only.
+ * This is the strategy routine for NFS.
+ * It is called by nfs_updatepage whenever the user wrote up to the end
+ * of a page.
+ *
+ * We always try to submit a set of requests in parallel so that the
+ * server's write code can gather writes. This is mainly for the benefit
+ * of NFSv2.
+ *
+ * We never submit more requests than we think the remote can handle.
+ * For UDP sockets, we make sure we don't exceed the congestion window;
+ * for TCP, we limit the number of requests to 8.
+ *
+ * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that
+ * should be sent out in one go. This is for the benefit of NFSv2 servers
+ * that perform write gathering.
+ *
+ * FIXME: Different servers may have different sweet spots.
+ * Record the average congestion window in server struct?
*/
-int
-nfs_writepage(struct dentry * dentry, struct page *page)
+#define NFS_STRATEGY_PAGES 8
+static void
+nfs_strategy(struct file *file)
{
- struct inode *inode = dentry->d_inode;
- unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
- unsigned offset = PAGE_CACHE_SIZE;
- int err;
+ struct inode *inode = file->f_dentry->d_inode;
+ unsigned int dirty, wpages;
+
+ dirty = inode->u.nfs_i.ndirty;
+ wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT;
+#ifdef CONFIG_NFS_V3
+ if (NFS_PROTO(inode)->version == 2) {
+ if (dirty >= NFS_STRATEGY_PAGES * wpages)
+ nfs_flush_file(inode, file, 0, 0, 0);
+ } else {
+ if (dirty >= wpages)
+ nfs_flush_file(inode, file, 0, 0, 0);
+ }
+#else
+ if (dirty >= NFS_STRATEGY_PAGES * wpages)
+ nfs_flush_file(inode, file, 0, 0, 0);
+#endif
+ /*
+ * If we're running out of requests, flush out everything
+ * in order to reduce memory useage...
+ */
+ if (nfs_nr_requests > MAX_REQUEST_SOFT)
+ nfs_wb_file(inode, file);
+}
- /* easy case */
- if (page->index < end_index)
- goto do_it;
- /* things got complicated... */
- offset = inode->i_size & (PAGE_CACHE_SIZE-1);
- /* OK, are we completely out? */
- if (page->index >= end_index+1 || !offset)
- return -EIO;
-do_it:
- err = nfs_writepage_sync(dentry, inode, page, 0, offset);
- if ( err == offset) return 0;
- return err;
+int
+nfs_flush_incompatible(struct file *file, struct page *page)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct nfs_page *req;
+ int status = 0;
+ /*
+ * Look for a request corresponding to this page. If there
+ * is one, and it belongs to another file, we flush it out
+ * before we try to copy anything into the page. Do this
+ * due to the lack of an ACCESS-type call in NFSv2.
+ * Also do the same if we find a request from an existing
+ * dropped page.
+ */
+ req = nfs_find_request(inode,page);
+ if (req) {
+ if (req->wb_file != file || req->wb_page != page)
+ status = nfs_wb_page(inode, page);
+ nfs_release_request(req);
+ }
+ return (status < 0) ? status : 0;
}
/*
@@ -446,27 +1032,13 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- struct nfs_wreq *req;
+ struct nfs_page *req;
int synchronous = file->f_flags & O_SYNC;
- int retval;
+ int status = 0;
- dprintk("NFS: nfs_updatepage(%s/%s %d@%ld)\n",
+ dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, (page->index << PAGE_CACHE_SHIFT) +offset);
-
- /*
- * Try to find a corresponding request on the writeback queue.
- * If there is one, we can be sure that this request is not
- * yet being processed, because we hold a lock on the page.
- *
- * If the request was created by us, update it. Otherwise,
- * transfer the page lock and flush out the dirty page now.
- * After returning, generic_file_write will wait on the
- * page and retry the update.
- */
- req = find_write_request(inode, page);
- if (req && req->wb_file == file && update_write_request(req, offset, count))
- goto updated;
+ count, page_offset(page) +offset);
/*
* If wsize is smaller than page size, update and write
@@ -475,241 +1047,542 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
return nfs_writepage_sync(dentry, inode, page, offset, count);
- /* Create the write request. */
- req = create_write_request(file, page, offset, count);
- if (!req)
- return -ENOBUFS;
-
/*
- * Ok, there's another user of this page with the new request..
- * The IO completion will then free the page and the dentry.
+ * Try to find an NFS request corresponding to this page
+ * and update it.
+ * If the existing request cannot be updated, we must flush
+ * it out now.
*/
- get_page(page);
-
- /* Schedule request */
- synchronous = schedule_write_request(req, synchronous);
+ do {
+ req = nfs_update_request(file, page, offset, count);
+ status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
+ if (status != -EBUSY)
+ break;
+ /* Request could not be updated. Flush it out and try again */
+ status = nfs_wb_page(inode, page);
+ } while (status >= 0);
+ if (status < 0)
+ goto done;
-updated:
- if (req->wb_bytes == PAGE_SIZE)
+ if (req->wb_bytes == PAGE_CACHE_SIZE)
SetPageUptodate(page);
- retval = 0;
+ status = 0;
if (synchronous) {
- int status = wait_on_write_request(req);
- if (status) {
- nfs_cancel_request(req);
- retval = status;
- } else {
- status = req->wb_status;
- if (status < 0)
- retval = status;
- }
+ int error;
- if (retval < 0)
- ClearPageUptodate(page);
+ error = nfs_sync_file(inode, file, page_offset(page) + offset, count, FLUSH_SYNC|FLUSH_STABLE);
+ if (error < 0 || (error = file->f_error) < 0)
+ status = error;
+ file->f_error = 0;
+ } else {
+ /* If we wrote past the end of the page.
+ * Call the strategy routine so it can send out a bunch
+ * of requests.
+ */
+ if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE)
+ nfs_strategy(file);
}
-
- free_write_request(req);
- return retval;
+ nfs_release_request(req);
+done:
+ dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n",
+ status, inode->i_size);
+ if (status < 0)
+ clear_bit(PG_uptodate, &page->flags);
+ return status;
}
/*
- * Cancel a write request. We always mark it cancelled,
- * but if it's already in progress there's no point in
- * calling rpc_exit, and we don't want to overwrite the
- * tk_status field.
- */
+ * Set up the argument/result storage required for the RPC call.
+ */
static void
-nfs_cancel_request(struct nfs_wreq *req)
+nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
{
- req->wb_flags |= NFS_WRITE_CANCELLED;
- if (!WB_INPROGRESS(req)) {
- rpc_exit(&req->wb_task, 0);
- rpc_wake_up_task(&req->wb_task);
+ struct nfs_page *req;
+ struct iovec *iov;
+ unsigned int count;
+
+ /* Set up the RPC argument and reply structs
+ * NB: take care not to mess about with data->commit et al. */
+
+ iov = data->args.iov;
+ count = 0;
+ while (!list_empty(head)) {
+ struct nfs_page *req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, &data->pages);
+ iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset);
+ iov->iov_len = req->wb_bytes;
+ count += req->wb_bytes;
+ iov++;
+ data->args.nriov++;
}
+ req = nfs_list_entry(data->pages.next);
+ data->file = req->wb_file;
+ data->cred = req->wb_cred;
+ data->args.fh = NFS_FH(req->wb_file->f_dentry);
+ data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+ data->args.count = count;
+ data->res.fattr = &data->fattr;
+ data->res.count = count;
+ data->res.verf = &data->verf;
}
+
/*
- * Cancel all writeback requests, both pending and in progress.
+ * Create an RPC task for the given write request and kick it.
+ * The page must have been locked by the caller.
+ *
+ * It may happen that the page we're passed is not marked dirty.
+ * This is the case if nfs_updatepage detects a conflicting request
+ * that has been written but not committed.
*/
-static void
-nfs_cancel_dirty(struct inode *inode, pid_t pid)
+static int
+nfs_flush_one(struct list_head *head, struct file *file, int how)
{
- struct nfs_wreq *head, *req;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ struct nfs_write_data *data;
+ struct rpc_task *task;
+ struct rpc_message msg;
+ int flags,
+ async = !(how & FLUSH_SYNC),
+ stable = (how & FLUSH_STABLE);
+ sigset_t oldset;
+
+
+ data = nfs_writedata_alloc();
+ if (!data)
+ goto out_bad;
+ task = &data->task;
+
+ /* Set the initial flags for the task. */
+ flags = (async) ? RPC_TASK_ASYNC : 0;
+
+ /* Set up the argument struct */
+ nfs_write_rpcsetup(head, data);
+ if (stable) {
+ if (!inode->u.nfs_i.ncommit)
+ data->args.stable = NFS_FILE_SYNC;
+ else
+ data->args.stable = NFS_DATA_SYNC;
+ } else
+ data->args.stable = NFS_UNSTABLE;
+
+ /* Finalize the task. */
+ rpc_init_task(task, clnt, nfs_writeback_done, flags);
+ task->tk_calldata = data;
+
+#ifdef CONFIG_NFS_V3
+ msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE;
+#else
+ msg.rpc_proc = NFSPROC_WRITE;
+#endif
+ msg.rpc_argp = &data->args;
+ msg.rpc_resp = &data->res;
+ msg.rpc_cred = data->cred;
+
+ dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n",
+ task->tk_pid,
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name,
+ data->args.count, data->args.nriov);
+
+ rpc_clnt_sigmask(clnt, &oldset);
+ rpc_call_setup(task, &msg, 0);
+ rpc_execute(task);
+ rpc_clnt_sigunmask(clnt, &oldset);
+ return 0;
+ out_bad:
+ while (!list_empty(head)) {
+ struct nfs_page *req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_mark_request_dirty(req);
+ nfs_unlock_request(req);
+ }
+ return -ENOMEM;
+}
- req = head = NFS_WRITEBACK(inode);
- while (req != NULL) {
- if (pid == 0 || req->wb_pid == pid)
- nfs_cancel_request(req);
- if ((req = WB_NEXT(req)) == head)
+static int
+nfs_flush_list(struct inode *inode, struct list_head *head, int how)
+{
+ LIST_HEAD(one_request);
+ struct nfs_page *req;
+ int error = 0;
+ unsigned int pages = 0,
+ wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT;
+
+ while (!list_empty(head)) {
+ pages += coalesce_requests(head, &one_request, wpages);
+ req = nfs_list_entry(one_request.next);
+ error = nfs_flush_one(&one_request, req->wb_file, how);
+ if (error < 0)
break;
}
+ if (error >= 0)
+ return pages;
+
+ while (!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_mark_request_dirty(req);
+ nfs_unlock_request(req);
+ }
+ return error;
}
+
/*
- * If we're waiting on somebody else's request
- * we need to increment the counter during the
- * wait so that the request doesn't disappear
- * from under us during the wait..
+ * This function is called when the WRITE call is complete.
*/
-static int FASTCALL(wait_on_other_req(struct nfs_wreq *));
-static int wait_on_other_req(struct nfs_wreq *req)
+static void
+nfs_writeback_done(struct rpc_task *task)
{
- int retval;
- req->wb_count++;
- retval = wait_on_write_request(req);
- free_write_request(req);
- return retval;
-}
+ struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+ struct nfs_writeargs *argp = &data->args;
+ struct nfs_writeres *resp = &data->res;
+ struct dentry *dentry = data->file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct nfs_page *req;
+
+ dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
+ task->tk_pid, task->tk_status);
+
+ /* We can't handle that yet but we check for it nevertheless */
+ if (resp->count < argp->count && task->tk_status >= 0) {
+ static unsigned long complain = 0;
+ if (time_before(complain, jiffies)) {
+ printk(KERN_WARNING
+ "NFS: Server wrote less than requested.\n");
+ complain = jiffies + 300 * HZ;
+ }
+ /* Can't do anything about it right now except throw
+ * an error. */
+ task->tk_status = -EIO;
+ }
+#ifdef CONFIG_NFS_V3
+ if (resp->verf->committed < argp->stable && task->tk_status >= 0) {
+ /* We tried a write call, but the server did not
+ * commit data to stable storage even though we
+ * requested it.
+ */
+ static unsigned long complain = 0;
+
+ if (time_before(complain, jiffies)) {
+ printk(KERN_NOTICE "NFS: faulty NFSv3 server %s:"
+ " (committed = %d) != (stable = %d)\n",
+ NFS_SERVER(inode)->hostname,
+ resp->verf->committed, argp->stable);
+ complain = jiffies + 300 * HZ;
+ }
+ }
+#endif
-/*
- * This writes back a set of requests according to the condition.
- *
- * If this ever gets much more convoluted, use a fn pointer for
- * the condition..
- */
-#define NFS_WB(inode, cond) { int retval = 0 ; \
- do { \
- struct nfs_wreq *req = NFS_WRITEBACK(inode); \
- struct nfs_wreq *head = req; \
- if (!req) break; \
- for (;;) { \
- if (!(req->wb_flags & NFS_WRITE_COMPLETE)) \
- if (cond) break; \
- req = WB_NEXT(req); \
- if (req == head) goto out; \
- } \
- retval = wait_on_other_req(req); \
- } while (!retval); \
-out: return retval; \
-}
+ /* Update attributes as result of writeback. */
+ if (task->tk_status >= 0)
+ nfs_write_attributes(inode, resp->fattr);
-int
-nfs_wb_all(struct inode *inode)
-{
- NFS_WB(inode, 1);
+ while (!list_empty(&data->pages)) {
+ req = nfs_list_entry(data->pages.next);
+ nfs_list_remove_request(req);
+
+ kunmap(req->wb_page);
+
+ dprintk("NFS: write (%s/%s %d@%Ld)",
+ req->wb_file->f_dentry->d_parent->d_name.name,
+ req->wb_file->f_dentry->d_name.name,
+ req->wb_bytes,
+ page_offset(req->wb_page) + req->wb_offset);
+
+ if (task->tk_status < 0) {
+ req->wb_file->f_error = task->tk_status;
+ nfs_inode_remove_request(req);
+ dprintk(", error = %d\n", task->tk_status);
+ goto next;
+ }
+
+#ifdef CONFIG_NFS_V3
+ if (resp->verf->committed != NFS_UNSTABLE) {
+ nfs_inode_remove_request(req);
+ dprintk(" OK\n");
+ goto next;
+ }
+ memcpy(&req->wb_verf, resp->verf, sizeof(req->wb_verf));
+ req->wb_timeout = jiffies + NFS_COMMIT_DELAY;
+ nfs_mark_request_commit(req);
+ dprintk(" marked for commit\n");
+#else
+ nfs_inode_remove_request(req);
+#endif
+ next:
+ nfs_unlock_request(req);
+ }
+ nfs_writedata_release(task);
}
+
+#ifdef CONFIG_NFS_V3
/*
- * Write back all requests on one page - we do this before reading it.
+ * Set up the argument/result storage required for the RPC call.
*/
-int
-nfs_wb_page(struct inode *inode, struct page *page)
+static void
+nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
{
- NFS_WB(inode, req->wb_page == page);
+ struct nfs_page *req;
+ struct dentry *dentry;
+ struct inode *inode;
+ unsigned long start, end, len;
+
+ /* Set up the RPC argument and reply structs
+ * NB: take care not to mess about with data->commit et al. */
+
+ end = 0;
+ start = ~0;
+ req = nfs_list_entry(head->next);
+ data->file = req->wb_file;
+ data->cred = req->wb_cred;
+ dentry = data->file->f_dentry;
+ inode = dentry->d_inode;
+ while (!list_empty(head)) {
+ struct nfs_page *req;
+ unsigned long rqstart, rqend;
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, &data->pages);
+ rqstart = page_offset(req->wb_page) + req->wb_offset;
+ rqend = rqstart + req->wb_bytes;
+ if (rqstart < start)
+ start = rqstart;
+ if (rqend > end)
+ end = rqend;
+ }
+ data->args.fh = NFS_FH(dentry);
+ data->args.offset = start;
+ len = end - start;
+ if (end >= inode->i_size || len > (~((u32)0) >> 1))
+ len = 0;
+ data->res.count = data->args.count = (u32)len;
+ data->res.fattr = &data->fattr;
+ data->res.verf = &data->verf;
}
/*
- * Write back all pending writes from one file descriptor..
+ * Commit dirty pages
*/
-int
-nfs_wb_file(struct inode *inode, struct file *file)
-{
- NFS_WB(inode, req->wb_file == file);
-}
-
-void
-nfs_inval(struct inode *inode)
+static int
+nfs_commit_list(struct list_head *head, int how)
{
- nfs_cancel_dirty(inode,0);
+ struct rpc_message msg;
+ struct file *file;
+ struct rpc_clnt *clnt;
+ struct nfs_write_data *data;
+ struct rpc_task *task;
+ struct nfs_page *req;
+ int flags,
+ async = !(how & FLUSH_SYNC);
+ sigset_t oldset;
+
+ data = nfs_writedata_alloc();
+
+ if (!data)
+ goto out_bad;
+ task = &data->task;
+
+ flags = (async) ? RPC_TASK_ASYNC : 0;
+
+ /* Set up the argument struct */
+ nfs_commit_rpcsetup(head, data);
+ req = nfs_list_entry(data->pages.next);
+ file = req->wb_file;
+ clnt = NFS_CLIENT(file->f_dentry->d_inode);
+
+ rpc_init_task(task, clnt, nfs_commit_done, flags);
+ task->tk_calldata = data;
+
+ msg.rpc_proc = NFS3PROC_COMMIT;
+ msg.rpc_argp = &data->args;
+ msg.rpc_resp = &data->res;
+ msg.rpc_cred = data->cred;
+
+ dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
+ rpc_clnt_sigmask(clnt, &oldset);
+ rpc_call_setup(task, &msg, 0);
+ rpc_execute(task);
+ rpc_clnt_sigunmask(clnt, &oldset);
+ return 0;
+ out_bad:
+ while (!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_mark_request_commit(req);
+ nfs_unlock_request(req);
+ }
+ return -ENOMEM;
}
/*
- * The following procedures make up the writeback finite state machinery:
- *
- * 1. Try to lock the page if not yet locked by us,
- * set up the RPC call info, and pass to the call FSM.
+ * COMMIT call returned
*/
static void
-nfs_wback_begin(struct rpc_task *task)
+nfs_commit_done(struct rpc_task *task)
{
- struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata;
- struct page *page = req->wb_page;
- struct file *file = req->wb_file;
- struct dentry *dentry = file->f_dentry;
-
- dprintk("NFS: %4d nfs_wback_begin (%s/%s, status=%d flags=%x)\n",
- task->tk_pid, dentry->d_parent->d_name.name,
- dentry->d_name.name, task->tk_status, req->wb_flags);
+ struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
+ struct nfs_writeres *resp = &data->res;
+ struct nfs_page *req;
+ struct dentry *dentry = data->file->f_dentry;
+ struct inode *inode = dentry->d_inode;
- task->tk_status = 0;
+ dprintk("NFS: %4d nfs_commit_done (status %d)\n",
+ task->tk_pid, task->tk_status);
+
+ nfs_refresh_inode(inode, resp->fattr);
+ while (!list_empty(&data->pages)) {
+ req = nfs_list_entry(data->pages.next);
+ nfs_list_remove_request(req);
+
+ dprintk("NFS: commit (%s/%s %d@%ld)",
+ req->wb_file->f_dentry->d_parent->d_name.name,
+ req->wb_file->f_dentry->d_name.name,
+ req->wb_bytes,
+ page_offset(req->wb_page) + req->wb_offset);
+ if (task->tk_status < 0) {
+ req->wb_file->f_error = task->tk_status;
+ nfs_inode_remove_request(req);
+ dprintk(", error = %d\n", task->tk_status);
+ goto next;
+ }
- /* Setup the task struct for a writeback call */
- req->wb_flags |= NFS_WRITE_INPROGRESS;
- req->wb_args.fh = NFS_FH(dentry);
- req->wb_args.offset = (page->index << PAGE_CACHE_SHIFT) + req->wb_offset;
- req->wb_args.count = req->wb_bytes;
- req->wb_args.buffer = (void *) (page_address(page) + req->wb_offset);
+ /* Okay, COMMIT succeeded, apparently. Check the verifier
+ * returned by the server against all stored verfs. */
+ if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
+ /* We have a match */
+ nfs_inode_remove_request(req);
+ dprintk(" OK\n");
+ goto next;
+ }
+ /* We have a mismatch. Write the page again */
+ dprintk(" mismatch\n");
+ nfs_mark_request_dirty(req);
+ next:
+ nfs_unlock_request(req);
+ }
+ nfs_writedata_release(task);
+}
+#endif
- rpc_call_setup(task, NFSPROC_WRITE, &req->wb_args, &req->wb_fattr, 0);
+int nfs_flush_file(struct inode *inode, struct file *file, unsigned long start,
+ unsigned int count, int how)
+{
+ LIST_HEAD(head);
+ int pages,
+ error = 0;
+
+ pages = nfs_scan_dirty(inode, &head, file, start, count);
+ if (pages)
+ error = nfs_flush_list(inode, &head, how);
+ if (error < 0)
+ return error;
+ return pages;
+}
- return;
+int nfs_flush_timeout(struct inode *inode, int how)
+{
+ LIST_HEAD(head);
+ int pages,
+ error = 0;
+
+ pages = nfs_scan_dirty_timeout(inode, &head);
+ if (pages)
+ error = nfs_flush_list(inode, &head, how);
+ if (error < 0)
+ return error;
+ return pages;
}
-/*
- * 2. Collect the result
- */
-static void
-nfs_wback_result(struct rpc_task *task)
+#ifdef CONFIG_NFS_V3
+int nfs_commit_file(struct inode *inode, struct file *file, unsigned long start,
+ unsigned int count, int how)
{
- struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata;
- struct file *file = req->wb_file;
- struct page *page = req->wb_page;
- int status = task->tk_status;
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ LIST_HEAD(head);
+ int pages,
+ error = 0;
+
+ pages = nfs_scan_commit(inode, &head, file, start, count);
+ if (pages)
+ error = nfs_commit_list(&head, how);
+ if (error < 0)
+ return error;
+ return pages;
+}
- dprintk("NFS: %4d nfs_wback_result (%s/%s, status=%d, flags=%x)\n",
- task->tk_pid, dentry->d_parent->d_name.name,
- dentry->d_name.name, status, req->wb_flags);
-
- /* Set the WRITE_COMPLETE flag, but leave WRITE_INPROGRESS set */
- req->wb_flags |= NFS_WRITE_COMPLETE;
- req->wb_status = status;
-
- if (status < 0) {
- req->wb_flags |= NFS_WRITE_INVALIDATE;
- file->f_error = status;
- } else if (!WB_CANCELLED(req)) {
- struct nfs_fattr *fattr = &req->wb_fattr;
- /* Update attributes as result of writeback.
- * Beware: when UDP replies arrive out of order, we
- * may end up overwriting a previous, bigger file size.
- *
- * When the file size shrinks we cancel all pending
- * writebacks.
- */
- if (fattr->mtime.seconds >= inode->i_mtime) {
- if (fattr->size < inode->i_size)
- fattr->size = inode->i_size;
-
- /* possible Solaris 2.5 server bug workaround */
- if (inode->i_ino == fattr->fileid) {
- /*
- * We expect these values to change, and
- * don't want to invalidate the caches.
- */
- inode->i_size = fattr->size;
- inode->i_mtime = fattr->mtime.seconds;
- nfs_refresh_inode(inode, fattr);
- }
- else
- printk("nfs_wback_result: inode %ld, got %u?\n",
- inode->i_ino, fattr->fileid);
- }
+int nfs_commit_timeout(struct inode *inode, int how)
+{
+ LIST_HEAD(head);
+ int pages,
+ error = 0;
+
+ pages = nfs_scan_commit_timeout(inode, &head);
+ if (pages) {
+ pages += nfs_scan_commit(inode, &head, NULL, 0, 0);
+ error = nfs_commit_list(&head, how);
}
+ if (error < 0)
+ return error;
+ return pages;
+}
+#endif
- rpc_release_task(task);
+int nfs_sync_file(struct inode *inode, struct file *file, unsigned long start,
+ unsigned int count, int how)
+{
+ int error,
+ wait;
- if (WB_INVALIDATE(req))
- ClearPageUptodate(page);
+ wait = how & FLUSH_WAIT;
+ how &= ~FLUSH_WAIT;
- kunmap(page);
- __free_page(page);
- remove_write_request(&NFS_WRITEBACK(inode), req);
- nr_write_requests--;
- fput(req->wb_file);
+ if (!inode && file)
+ inode = file->f_dentry->d_inode;
- wake_up(&req->wb_wait);
- free_write_request(req);
+ do {
+ error = 0;
+ if (wait)
+ error = nfs_wait_on_requests(inode, file, start, count);
+ if (error == 0)
+ error = nfs_flush_file(inode, file, start, count, how);
+#ifdef CONFIG_NFS_V3
+ if (error == 0)
+ error = nfs_commit_file(inode, file, start, count, how);
+#endif
+ } while (error > 0);
+ return error;
+}
+
+int nfs_init_nfspagecache(void)
+{
+ nfs_page_cachep = kmem_cache_create("nfs_page",
+ sizeof(struct nfs_page),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (nfs_page_cachep == NULL)
+ return -ENOMEM;
+
+ nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
+ sizeof(struct nfs_write_data),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (nfs_wdata_cachep == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void nfs_destroy_nfspagecache(void)
+{
+ if (kmem_cache_destroy(nfs_page_cachep))
+ printk(KERN_INFO "nfs_page: not all structures were freed\n");
+ if (kmem_cache_destroy(nfs_wdata_cachep))
+ printk(KERN_INFO "nfs_write_data: not all structures were freed\n");
}
+
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 8d2b610a8..c6ea9074c 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -483,7 +483,10 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
* fh must be initialized before calling fh_compose
*/
fh_init(&fh, maxsize);
- err = fh_compose(&fh, exp, dentry);
+ if (fh_compose(&fh, exp, dentry))
+ err = -EINVAL;
+ else
+ err = 0;
memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
fh_put(&fh);
return err;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 6e102db9c..969ff54a9 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -748,6 +748,7 @@ encode_entry(struct readdir_cd *cd, const char *name,
if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode)
goto noexec;
p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
+ *p++ = xdr_one; /* yes, a file handle follows */
p = encode_fh(p, &fh);
fh_put(&fh);
}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index f755adc8c..97b46f0c7 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -42,8 +42,8 @@ static int nfsctl_export(struct nfsctl_export *data);
static int nfsctl_unexport(struct nfsctl_export *data);
static int nfsctl_getfh(struct nfsctl_fhparm *, __u8 *);
static int nfsctl_getfd(struct nfsctl_fdparm *, __u8 *);
-#ifdef notyet
static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
+#ifdef notyet
static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data);
#endif
@@ -112,7 +112,6 @@ nfsctl_ugidupdate(nfs_ugidmap *data)
}
#endif
-#ifdef notyet
static inline int
nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
{
@@ -131,10 +130,9 @@ nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
else
err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
exp_unlock();
-
+ /*HACK*/ res->fh_size = NFS_FHSIZE; /* HACK until lockd handles var-length handles */
return err;
}
-#endif
static inline int
nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res)
@@ -206,6 +204,21 @@ nfsctl_getfh(struct nfsctl_fhparm *data, __u8 *res)
#define handle_sys_nfsservctl sys_nfsservctl
#endif
+static struct {
+ int argsize, respsize;
+} sizes[] = {
+ /* NFSCTL_SVC */ { sizeof(struct nfsctl_svc), 0 },
+ /* NFSCTL_ADDCLIENT */ { sizeof(struct nfsctl_client), 0},
+ /* NFSCTL_DELCLIENT */ { sizeof(struct nfsctl_client), 0},
+ /* NFSCTL_EXPORT */ { sizeof(struct nfsctl_export), 0},
+ /* NFSCTL_UNEXPORT */ { sizeof(struct nfsctl_export), 0},
+ /* NFSCTL_UGIDUPDATE */ { sizeof(struct nfsctl_uidmap), 0},
+ /* NFSCTL_GETFH */ { sizeof(struct nfsctl_fhparm), NFS_FHSIZE},
+ /* NFSCTL_GETFD */ { sizeof(struct nfsctl_fdparm), NFS_FHSIZE},
+ /* NFSCTL_GETFS */ { sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)},
+};
+#define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1)
+
int
asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
{
@@ -214,6 +227,7 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
struct nfsctl_arg * arg = NULL;
union nfsctl_res * res = NULL;
int err;
+ int argsize, respsize;
MOD_INC_USE_COUNT;
lock_kernel ();
@@ -223,12 +237,16 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
if (!capable(CAP_SYS_ADMIN)) {
goto done;
}
+ err = -EINVAL;
+ if (cmd<0 || cmd > CMD_MAX)
+ goto done;
err = -EFAULT;
- if (!access_ok(VERIFY_READ, argp, sizeof(*argp))
- || (resp && !access_ok(VERIFY_WRITE, resp, sizeof(*resp)))) {
+ argsize = sizes[cmd].argsize + sizeof(int); /* int for ca_version */
+ respsize = sizes[cmd].respsize; /* maximum */
+ if (!access_ok(VERIFY_READ, argp, argsize)
+ || (resp && !access_ok(VERIFY_WRITE, resp, respsize))) {
goto done;
}
-
err = -ENOMEM; /* ??? */
if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) ||
(resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) {
@@ -236,7 +254,7 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
}
err = -EINVAL;
- copy_from_user(arg, argp, sizeof(*argp));
+ copy_from_user(arg, argp, argsize);
if (arg->ca_version != NFSCTL_VERSION) {
printk(KERN_WARNING "nfsd: incompatible version in syscall.\n");
goto done;
@@ -269,16 +287,16 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
case NFSCTL_GETFD:
err = nfsctl_getfd(&arg->ca_getfd, res->cr_getfh);
break;
-#ifdef notyet
case NFSCTL_GETFS:
err = nfsctl_getfs(&arg->ca_getfs, &res->cr_getfs);
-#endif
+ respsize = res->cr_getfs.fh_size+sizeof(int);
+ break;
default:
err = -EINVAL;
}
- if (!err && resp)
- copy_to_user(resp, res, sizeof(*resp));
+ if (!err && resp && respsize)
+ copy_to_user(resp, res, respsize);
done:
if (arg)
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 6f69225cc..5c312b906 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -223,9 +223,10 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
goto done;
fh_lock(dirfhp);
dchild = lookup_one(argp->name, dget(dirfhp->fh_dentry));
- nfserr = nfserrno(PTR_ERR(dchild));
- if (IS_ERR(dchild))
+ if (IS_ERR(dchild)) {
+ nfserr = nfserrno(PTR_ERR(dchild));
goto out_unlock;
+ }
fh_init(newfhp, NFS_FHSIZE);
nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild);
if (!nfserr && !dchild->d_inode)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index d69bba8d0..fb3b32f8d 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -43,6 +43,8 @@ extern struct svc_program nfsd_program;
static void nfsd(struct svc_rqst *rqstp);
struct timeval nfssvc_boot = { 0, 0 };
static struct svc_serv *nfsd_serv = NULL;
+static int nfsd_busy = 0;
+static unsigned long nfsd_last_call;
struct nfsd_list {
struct list_head list;
@@ -115,6 +117,24 @@ nfsd_svc(unsigned short port, int nrservs)
return error;
}
+static void inline
+update_thread_usage(int busy_threads)
+{
+ unsigned long prev_call;
+ unsigned long diff;
+ int decile;
+
+ prev_call = nfsd_last_call;
+ nfsd_last_call = jiffies;
+ decile = busy_threads*10/nfsdstats.th_cnt;
+ if (decile>0 && decile <= 10) {
+ diff = nfsd_last_call - prev_call;
+ nfsdstats.th_usage[decile-1] += diff;
+ if (decile == 10)
+ nfsdstats.th_fullcnt++;
+ }
+}
+
/*
* This is the NFS server kernel thread
*/
@@ -134,6 +154,7 @@ nfsd(struct svc_rqst *rqstp)
sprintf(current->comm, "nfsd");
current->fs->umask = 0;
+ nfsdstats.th_cnt++;
/* Let svc_process check client's authentication. */
rqstp->rq_auth = 1;
@@ -161,6 +182,8 @@ nfsd(struct svc_rqst *rqstp)
;
if (err < 0)
break;
+ update_thread_usage(nfsd_busy);
+ nfsd_busy++;
/* Lock the export hash tables for reading. */
exp_readlock();
@@ -179,6 +202,8 @@ nfsd(struct svc_rqst *rqstp)
/* Unlock export hash tables */
exp_unlock();
+ update_thread_usage(nfsd_busy);
+ nfsd_busy--;
}
if (err != -EINTR) {
@@ -202,6 +227,7 @@ nfsd(struct svc_rqst *rqstp)
nfsd_racache_shutdown(); /* release read-ahead cache */
}
list_del(&me.list);
+ nfsdstats.th_cnt --;
/* Release the thread */
svc_exit_thread(rqstp);
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c
index 69defe790..254242fb6 100644
--- a/fs/nfsd/stats.c
+++ b/fs/nfsd/stats.c
@@ -8,6 +8,16 @@
* Format:
* rc <hits> <misses> <nocache>
* Statistsics for the reply cache
+ * fh <stale> <total-lookups> <anonlookups> <dir-not-in-dcache> <nondir-not-in-dcache>
+ * statistics for filehandle lookup
+ * io <bytes-read> <bytes-writtten>
+ * statistics for IO throughput
+ * th <threads> <fullcnt> <10%-20%> <20%-30%> ... <90%-100%> <100%>
+ * time (milliseconds) when nfsd thread usage above thresholds
+ * and number of times that all threads were in use
+ * ra cache-size <10% <20% <30% ... <100% not-found
+ * number of times that read-ahead entry was found that deep in
+ * the cache.
* plus generic RPC stats (see net/sunrpc/stats.c)
*
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
@@ -33,17 +43,30 @@ nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
int *eof, void *data)
{
int len;
+ int i;
- len = sprintf(buffer, "rc %d %d %d %d %d %d %d %d\n",
- nfsdstats.rchits,
- nfsdstats.rcmisses,
- nfsdstats.rcnocache,
- nfsdstats.fh_stale,
- nfsdstats.fh_lookup,
- nfsdstats.fh_anon,
- nfsdstats.fh_nocache_dir,
- nfsdstats.fh_nocache_nondir);
+ len = sprintf(buffer, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n",
+ nfsdstats.rchits,
+ nfsdstats.rcmisses,
+ nfsdstats.rcnocache,
+ nfsdstats.fh_stale,
+ nfsdstats.fh_lookup,
+ nfsdstats.fh_anon,
+ nfsdstats.fh_nocache_dir,
+ nfsdstats.fh_nocache_nondir,
+ nfsdstats.io_read,
+ nfsdstats.io_write);
+ /* thread usage: */
+ len += sprintf(buffer+len, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
+ for (i=0; i<10; i++)
+ len += sprintf(buffer+len, " %u", nfsdstats.th_usage[i]);
+ /* newline and ra-cache */
+ len += sprintf(buffer+len, "\nra %u", nfsdstats.ra_size);
+ for (i=0; i<11; i++)
+ len += sprintf(buffer+len, " %u", nfsdstats.ra_depth[i]);
+ len += sprintf(buffer+len, "\n");
+
/* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
*eof = 0;
@@ -53,13 +76,13 @@ nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
*/
if (len <= offset) {
len = svc_proc_read(buffer, start, offset - len, count,
- eof, data);
+ eof, data);
return len;
}
if (len < count) {
len += svc_proc_read(buffer + len, start, 0, count - len,
- eof, data);
+ eof, data);
}
if (offset >= len) {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index e3be271a2..5cd55fda8 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -539,13 +539,16 @@ static inline struct raparms *
nfsd_get_raparms(dev_t dev, ino_t ino)
{
struct raparms *ra, **rap, **frap = NULL;
-
+ int depth = 0;
+
for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
if (ra->p_ino == ino && ra->p_dev == dev)
goto found;
+ depth++;
if (ra->p_count == 0)
frap = rap;
}
+ depth = nfsdstats.ra_size*11/10;
if (!frap)
return NULL;
rap = frap;
@@ -560,6 +563,7 @@ found:
raparm_cache = ra;
}
ra->p_count++;
+ nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
return ra;
}
@@ -598,6 +602,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
oldfs = get_fs(); set_fs(KERNEL_DS);
err = file.f_op->read(&file, buf, *count, &file.f_pos);
set_fs(oldfs);
+ nfsdstats.io_read += *count;
/* Write back readahead params */
if (ra != NULL) {
@@ -691,6 +696,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
#else
err = file.f_op->write(&file, buf, cnt, &file.f_pos);
#endif
+ nfsdstats.io_write += cnt;
set_fs(oldfs);
/* clear setuid/setgid flag after write */
@@ -1559,5 +1565,6 @@ nfsd_racache_init(int cache_size)
"nfsd: Could not allocate memory read-ahead cache.\n");
return -ENOMEM;
}
+ nfsdstats.ra_size = cache_size;
return 0;
}
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index e95a36179..e6abd178e 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -595,7 +595,7 @@ static int ntfs_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,ntfs_get_block);
}
-static int ntfs_prepare_write(struct page *page, unsigned from, unsigned to)
+static int ntfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,ntfs_get_block,
&((struct inode*)page->mapping->host)->u.ntfs_i.mmu_private);
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 8a5e404b1..bd8aa6b98 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -258,7 +258,7 @@ static void ntfs_load_attributes(ntfs_inode* ino)
if( !buf )
return;
delta=0;
- for(offset=0;datasize;datasize-=len)
+ for(offset=0;datasize;datasize-=len,offset+=len)
{
ntfs_io io;
io.fn_put=ntfs_put;
@@ -268,7 +268,7 @@ static void ntfs_load_attributes(ntfs_inode* ino)
if(ntfs_read_attr(ino,vol->at_attribute_list,0,offset,&io)){
ntfs_error("error in load_attributes\n");
}
- delta=len;
+ delta+=len;
parse_attributes(ino,buf,&delta);
if(delta)
/* move remaining bytes to buffer start */
diff --git a/fs/open.c b/fs/open.c
index 9f4d50a79..44202fe4e 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -298,7 +298,6 @@ asmlinkage long sys_access(const char * filename, int mode)
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
- lock_kernel();
old_fsuid = current->fsuid;
old_fsgid = current->fsgid;
old_cap = current->cap_effective;
@@ -311,7 +310,8 @@ asmlinkage long sys_access(const char * filename, int mode)
cap_clear(current->cap_effective);
else
current->cap_effective = current->cap_permitted;
-
+
+ lock_kernel();
dentry = namei(filename);
res = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
@@ -321,12 +321,12 @@ asmlinkage long sys_access(const char * filename, int mode)
res = -EROFS;
dput(dentry);
}
+ unlock_kernel();
current->fsuid = old_fsuid;
current->fsgid = old_fsgid;
current->cap_effective = old_cap;
- unlock_kernel();
return res;
}
@@ -646,25 +646,35 @@ out:
*/
struct file *filp_open(const char * filename, int flags, int mode, struct dentry * base)
{
- struct inode * inode;
struct dentry * dentry;
- struct file * f;
int flag,error;
- error = -ENFILE;
- f = get_empty_filp();
- if (!f)
- goto out;
- f->f_flags = flag = flags;
- f->f_mode = (flag+1) & O_ACCMODE;
- if (f->f_mode)
+ flag = flags;
+ if ((flag+1) & O_ACCMODE)
flag++;
if (flag & O_TRUNC)
flag |= 2;
+
dentry = __open_namei(filename, flag, mode, base);
error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto cleanup_file;
+ if (!IS_ERR(dentry))
+ return dentry_open(dentry, flags);
+
+ return ERR_PTR(error);
+}
+
+struct file *dentry_open(struct dentry *dentry, int flags)
+{
+ struct file * f;
+ struct inode *inode;
+ int error;
+
+ error = -ENFILE;
+ f = get_empty_filp();
+ if (!f)
+ goto cleanup_dentry;
+ f->f_flags = flags;
+ f->f_mode = (flags+1) & O_ACCMODE;
inode = dentry->d_inode;
if (f->f_mode & FMODE_WRITE) {
error = get_write_access(inode);
@@ -692,12 +702,10 @@ struct file *filp_open(const char * filename, int flags, int mode, struct dentry
cleanup_all:
if (f->f_mode & FMODE_WRITE)
put_write_access(inode);
-cleanup_dentry:
f->f_dentry = NULL;
+cleanup_dentry:
dput(dentry);
-cleanup_file:
put_filp(f);
-out:
return ERR_PTR(error);
}
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 27b4be8cb..92eed7559 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.9 2000/03/13 21:59:43 davem Exp $
+/* $Id: inode.c,v 1.10 2000/03/24 01:32:51 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
@@ -980,10 +980,6 @@ static void openprom_read_inode(struct inode * inode)
}
}
-static void openprom_put_super(struct super_block *sb)
-{
-}
-
static int openprom_statfs(struct super_block *sb, struct statfs *buf)
{
buf->f_type = OPENPROM_SUPER_MAGIC;
@@ -997,7 +993,6 @@ static int openprom_statfs(struct super_block *sb, struct statfs *buf)
static struct super_operations openprom_sops = {
read_inode: openprom_read_inode,
- put_super: openprom_put_super,
statfs: openprom_statfs,
};
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index fc9555b77..21330f499 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -26,7 +26,10 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/blk.h>
+
+#ifdef CONFIG_IDE
#include <linux/ide.h> /* IDE xlate */
+#endif /* CONFIG_IDE */
#include <asm/system.h>
@@ -347,19 +350,19 @@ int msdos_partition(struct gendisk *hd, kdev_t dev,
unsigned char *data;
int mask = (1 << hd->minor_shift) - 1;
int sector_size = get_hardsect_size(dev) / 512;
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_IDE
int tested_for_xlate = 0;
read_mbr:
-#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif /* CONFIG_IDE */
if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
if (warn_no_part) printk(" unable to read partition table\n");
return -1;
}
data = bh->b_data;
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_IDE
check_table:
-#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif /* CONFIG_IDE */
/* Use bforget(), because we may have changed the disk geometry */
if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
bforget(bh);
@@ -367,7 +370,7 @@ check_table:
}
p = (struct partition *) (0x1be + data);
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_IDE
if (!tested_for_xlate++) { /* Do this only once per disk */
/*
* Look for various forms of IDE disk geometry translation
@@ -423,7 +426,7 @@ check_table:
(void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
}
}
-#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif /* CONFIG_IDE */
/* Look for partitions in two passes:
First find the primary partitions, and the DOS-type extended partitions.
diff --git a/fs/pipe.c b/fs/pipe.c
index 020416013..f25f5e514 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -13,16 +13,6 @@
#include <asm/uaccess.h>
/*
- * Define this if you want SunOS compatibility wrt braindead
- * select behaviour on FIFO's.
- */
-#ifdef __sparc__
-#define FIFO_SUNOS_BRAINDAMAGE
-#else
-#undef FIFO_SUNOS_BRAINDAMAGE
-#endif
-
-/*
* We use a start+len construction, which provides full use of the
* allocated memory.
* -- Florian Coosmann (FGC)
@@ -32,7 +22,7 @@
*/
/* Drop the inode semaphore and wait for a pipe event, atomically */
-static void pipe_wait(struct inode * inode)
+void pipe_wait(struct inode * inode)
{
DECLARE_WAITQUEUE(wait, current);
current->state = TASK_INTERRUPTIBLE;
@@ -296,7 +286,7 @@ pipe_poll(struct file *filp, poll_table *wait)
mask = POLLIN | POLLRDNORM;
if (PIPE_EMPTY(*inode))
mask = POLLOUT | POLLWRNORM;
- if (!PIPE_WRITERS(*inode))
+ if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode))
mask |= POLLHUP;
if (!PIPE_READERS(*inode))
mask |= POLLERR;
@@ -304,72 +294,9 @@ pipe_poll(struct file *filp, poll_table *wait)
return mask;
}
-#ifdef FIFO_SUNOS_BRAINDAMAGE
-/*
- * Argh! Why does SunOS have to have different select() behaviour
- * for pipes and FIFOs? Hate, hate, hate! SunOS lacks POLLHUP.
- */
-static unsigned int
-fifo_poll(struct file *filp, poll_table *wait)
-{
- unsigned int mask;
- struct inode *inode = filp->f_dentry->d_inode;
-
- poll_wait(filp, PIPE_WAIT(*inode), wait);
-
- /* Reading only -- no need for aquiring the semaphore. */
- mask = POLLIN | POLLRDNORM;
- if (PIPE_EMPTY(*inode))
- mask = POLLOUT | POLLWRNORM;
- if (!PIPE_READERS(*inode))
- mask |= POLLERR;
-
- return mask;
-}
-#else
-
+/* FIXME: most Unices do not set POLLERR for fifos */
#define fifo_poll pipe_poll
-#endif /* FIFO_SUNOS_BRAINDAMAGE */
-
-/*
- * The 'connect_xxx()' functions are needed for named pipes when
- * the open() code hasn't guaranteed a connection (O_NONBLOCK),
- * and we need to act differently until we do get a writer..
- */
-static ssize_t
-connect_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
-{
- struct inode *inode = filp->f_dentry->d_inode;
-
- /* Reading only -- no need for aquiring the semaphore. */
- if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode))
- return 0;
-
- filp->f_op = &read_fifo_fops;
- return pipe_read(filp, buf, count, ppos);
-}
-
-static unsigned int
-connect_poll(struct file *filp, poll_table *wait)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- unsigned int mask = 0;
-
- poll_wait(filp, PIPE_WAIT(*inode), wait);
-
- /* Reading only -- no need for aquiring the semaphore. */
- if (!PIPE_EMPTY(*inode)) {
- filp->f_op = &read_fifo_fops;
- mask = POLLIN | POLLRDNORM;
- } else if (PIPE_WRITERS(*inode)) {
- filp->f_op = &read_fifo_fops;
- mask = POLLOUT | POLLWRNORM;
- }
-
- return mask;
-}
-
static int
pipe_release(struct inode *inode, int decr, int decw)
{
@@ -450,16 +377,6 @@ pipe_rdwr_open(struct inode *inode, struct file *filp)
* The file_operations structs are not static because they
* are also used in linux/fs/fifo.c to do operations on FIFOs.
*/
-struct file_operations connecting_fifo_fops = {
- llseek: pipe_lseek,
- read: connect_read,
- write: bad_pipe_w,
- poll: connect_poll,
- ioctl: pipe_ioctl,
- open: pipe_read_open,
- release: pipe_read_release,
-};
-
struct file_operations read_fifo_fops = {
llseek: pipe_lseek,
read: pipe_read,
@@ -520,29 +437,42 @@ struct file_operations rdwr_pipe_fops = {
release: pipe_rdwr_release,
};
-static struct inode * get_pipe_inode(void)
+struct inode* pipe_new(struct inode* inode)
{
- struct inode *inode = get_empty_inode();
unsigned long page;
- if (!inode)
- goto fail_inode;
-
page = __get_free_page(GFP_USER);
if (!page)
- goto fail_iput;
+ return NULL;
inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
if (!inode->i_pipe)
goto fail_page;
- inode->i_fop = &rdwr_pipe_fops;
-
init_waitqueue_head(PIPE_WAIT(*inode));
- PIPE_BASE(*inode) = (char *) page;
+ PIPE_BASE(*inode) = (char*) page;
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
- PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
PIPE_WAITING_READERS(*inode) = PIPE_WAITING_WRITERS(*inode) = 0;
+ PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1;
+
+ return inode;
+fail_page:
+ free_page(page);
+ return NULL;
+}
+
+static struct inode * get_pipe_inode(void)
+{
+ struct inode *inode = get_empty_inode();
+
+ if (!inode)
+ goto fail_inode;
+
+ if(!pipe_new(inode))
+ goto fail_iput;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
+ inode->i_fop = &rdwr_pipe_fops;
/*
* Mark the inode dirty from the very beginning,
@@ -558,8 +488,6 @@ static struct inode * get_pipe_inode(void)
inode->i_blksize = PAGE_SIZE;
return inode;
-fail_page:
- free_page(page);
fail_iput:
iput(inode);
fail_inode:
@@ -606,11 +534,13 @@ int do_pipe(int *fd)
f1->f_flags = O_RDONLY;
f1->f_op = &read_pipe_fops;
f1->f_mode = 1;
+ f1->f_version = 0;
/* write file */
f2->f_flags = O_WRONLY;
f2->f_op = &write_pipe_fops;
f2->f_mode = 2;
+ f2->f_version = 0;
fd_install(i, f1);
fd_install(j, f2);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 3e1c58ad7..54e594634 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -402,7 +402,8 @@ static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned
++*pages;
if (pte_dirty(page))
++*dirty;
- if (pte_pagenr(page) >= max_mapnr)
+ if ((pte_pagenr(page) >= max_mapnr) ||
+ PageReserved(pte_pagenr(page) + mem_map))
continue;
if (page_count(pte_page(page)) > 1)
++*shared;
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 9e78119c9..c6511354b 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -418,7 +418,7 @@ static int qnx4_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,qnx4_get_block);
}
-static int qnx4_prepare_write(struct page *page, unsigned from, unsigned to)
+static int qnx4_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,qnx4_get_block,
&((struct inode*)page->mapping->host)->u.qnx4_i.mmu_private);
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 7f5f2dee6..63d5a58ab 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -161,14 +161,6 @@ outnobh:
return s;
}
-/* Nothing to do.. */
-
-static void
-romfs_put_super(struct super_block *sb)
-{
- return;
-}
-
/* That's simple too. */
static int
@@ -526,7 +518,6 @@ romfs_read_inode(struct inode *i)
static struct super_operations romfs_ops = {
read_inode: romfs_read_inode,
- put_super: romfs_put_super,
statfs: romfs_statfs,
};
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 1360ca994..12e2bf295 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -268,7 +268,7 @@ out:
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-static int smb_prepare_write(struct page *page, unsigned offset, unsigned to)
+static int smb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
kmap(page);
return 0;
diff --git a/fs/super.c b/fs/super.c
index dd34ddc70..302487807 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -147,7 +147,6 @@ static int fs_index(const char * __name)
err = index;
break;
}
- index++;
}
spin_unlock(&file_systems_lock);
putname(name);
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 3367c02ef..b6396ff04 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -949,7 +949,7 @@ static int sysv_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,sysv_get_block);
}
-static int sysv_prepare_write(struct page *page, unsigned from, unsigned to)
+static int sysv_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return block_prepare_write(page,from,to,sysv_get_block);
}
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 1aa3aa1c4..2be4e8562 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -85,14 +85,14 @@ found_middle:
#define find_first_one_bit(addr, size)\
find_next_one_bit((addr), (size), 0)
-static int read_block_bitmap(struct super_block * sb, unsigned int block,
- unsigned long bitmap_nr)
+static int read_block_bitmap(struct super_block * sb, Uint32 bitmap,
+ unsigned int block, unsigned long bitmap_nr)
{
struct buffer_head *bh = NULL;
int retval = 0;
lb_addr loc;
- loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap;
+ loc.logicalBlockNum = bitmap;
loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block), sb->s_blocksize);
@@ -105,7 +105,8 @@ static int read_block_bitmap(struct super_block * sb, unsigned int block,
return retval;
}
-static int __load_block_bitmap(struct super_block * sb, unsigned int block_group)
+static int __load_block_bitmap(struct super_block * sb, Uint32 bitmap,
+ unsigned int block_group)
{
int i, j, retval = 0;
unsigned long block_bitmap_number;
@@ -125,7 +126,7 @@ static int __load_block_bitmap(struct super_block * sb, unsigned int block_group
if (UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group)
return block_group;
}
- retval = read_block_bitmap(sb, block_group, block_group);
+ retval = read_block_bitmap(sb, bitmap, block_group, block_group);
if (retval < 0)
return retval;
return block_group;
@@ -150,7 +151,7 @@ static int __load_block_bitmap(struct super_block * sb, unsigned int block_group
UDF_SB_BLOCK_BITMAP(sb, 0) = block_bitmap;
if (!block_bitmap)
- retval = read_block_bitmap(sb, block_group, 0);
+ retval = read_block_bitmap(sb, bitmap, block_group, 0);
}
else
{
@@ -163,12 +164,12 @@ static int __load_block_bitmap(struct super_block * sb, unsigned int block_group
UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1);
UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1);
}
- retval = read_block_bitmap(sb, block_group, 0);
+ retval = read_block_bitmap(sb, bitmap, block_group, 0);
}
return retval;
}
-static inline int load_block_bitmap(struct super_block *sb,
+static inline int load_block_bitmap(struct super_block *sb, Uint32 bitmap,
unsigned int block_group)
{
int slot;
@@ -189,7 +190,7 @@ static inline int load_block_bitmap(struct super_block *sb,
}
else
{
- slot = __load_block_bitmap(sb, block_group);
+ slot = __load_block_bitmap(sb, bitmap, block_group);
}
if (slot < 0)
@@ -201,8 +202,8 @@ static inline int load_block_bitmap(struct super_block *sb,
return slot;
}
-void udf_free_blocks(const struct inode * inode, lb_addr bloc, Uint32 offset,
- Uint32 count)
+static void udf_bitmap_free_blocks(const struct inode * inode, Uint32 bitmap,
+ lb_addr bloc, Uint32 offset, Uint32 count)
{
struct buffer_head * bh = NULL;
unsigned long block;
@@ -220,9 +221,6 @@ void udf_free_blocks(const struct inode * inode, lb_addr bloc, Uint32 offset,
return;
}
- if (UDF_SB_PARTMAPS(sb)[bloc.partitionReferenceNum].s_uspace_bitmap == 0xFFFFFFFF)
- return;
-
lock_super(sb);
if (bloc.logicalBlockNum < 0 ||
(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
@@ -248,7 +246,7 @@ do_more:
overflow = bit + count - (sb->s_blocksize << 3);
count -= overflow;
}
- bitmap_nr = load_block_bitmap(sb, block_group);
+ bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
if (bitmap_nr < 0)
goto error_return;
@@ -285,8 +283,8 @@ error_return:
return;
}
-int udf_prealloc_blocks(const struct inode * inode, Uint16 partition,
- Uint32 first_block, Uint32 block_count)
+static int udf_bitmap_prealloc_blocks(const struct inode * inode, Uint32 bitmap,
+ Uint16 partition, Uint32 first_block, Uint32 block_count)
{
int alloc_count = 0;
int bit, block, block_group, group_start;
@@ -312,7 +310,7 @@ repeat:
block_group = block >> (sb->s_blocksize_bits + 3);
group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
- bitmap_nr = load_block_bitmap(sb, block_group);
+ bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
if (bitmap_nr < 0)
goto out;
bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
@@ -351,7 +349,8 @@ out:
return alloc_count;
}
-int udf_new_block(const struct inode * inode, Uint16 partition, Uint32 goal, int *err)
+static int udf_bitmap_new_block(const struct inode * inode, Uint32 bitmap,
+ Uint16 partition, Uint32 goal, int *err)
{
int tmp, newbit, bit=0, block, block_group, group_start;
int end_goal, nr_groups, bitmap_nr, i;
@@ -379,7 +378,7 @@ repeat:
block_group = block >> (sb->s_blocksize_bits + 3);
group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
- bitmap_nr = load_block_bitmap(sb, block_group);
+ bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
if (bitmap_nr < 0)
goto error_return;
bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
@@ -419,7 +418,7 @@ repeat:
block_group = 0;
group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
- bitmap_nr = load_block_bitmap(sb, block_group);
+ bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
if (bitmap_nr < 0)
goto error_return;
bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
@@ -497,3 +496,64 @@ error_return:
unlock_super(sb);
return 0;
}
+
+inline void udf_free_blocks(const struct inode * inode, lb_addr bloc,
+ Uint32 offset, Uint32 count)
+{
+ if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_UNALLOC_BITMAP)
+ {
+ return udf_bitmap_free_blocks(inode,
+ UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_uspace.bitmap,
+ bloc, offset, count);
+ }
+ else if (UDF_SB_PARTFLAGS(inode->i_sb, bloc.partitionReferenceNum) & UDF_PART_FLAG_FREED_BITMAP)
+ {
+ return udf_bitmap_free_blocks(inode,
+ UDF_SB_PARTMAPS(inode->i_sb)[bloc.partitionReferenceNum].s_fspace.bitmap,
+ bloc, offset, count);
+ }
+ else
+ return;
+}
+
+inline int udf_prealloc_blocks(const struct inode * inode, Uint16 partition,
+ Uint32 first_block, Uint32 block_count)
+{
+ if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
+ {
+ return udf_bitmap_prealloc_blocks(inode,
+ UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.bitmap,
+ partition, first_block, block_count);
+ }
+ else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
+ {
+ return udf_bitmap_prealloc_blocks(inode,
+ UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.bitmap,
+ partition, first_block, block_count);
+ }
+ else
+ return 0;
+}
+
+inline int udf_new_block(const struct inode * inode, Uint16 partition,
+ Uint32 goal, int *err)
+{
+ if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
+ {
+ return udf_bitmap_new_block(inode,
+ UDF_SB_PARTMAPS(inode->i_sb)[partition].s_uspace.bitmap,
+ partition, goal, err);
+ }
+ else if (UDF_SB_PARTFLAGS(inode->i_sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
+ {
+ return udf_bitmap_new_block(inode,
+ UDF_SB_PARTMAPS(inode->i_sb)[partition].s_fspace.bitmap,
+ partition, goal, err);
+ }
+ else
+ {
+ *err = -EIO;
+ return 0;
+ }
+}
+
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 73d47ac10..96297521b 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -87,7 +87,7 @@ static int udf_adinicb_writepage(struct dentry *dentry, struct page *page)
return 0;
}
-static int udf_adinicb_prepare_write(struct page *page, unsigned offset, unsigned to)
+static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
kmap(page);
return 0;
@@ -246,7 +246,7 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
struct FileEntry *fe;
fe = (struct FileEntry *)bh->b_data;
- eaicb = fe->extendedAttrICB;
+ eaicb = lela_to_cpu(fe->extendedAttrICB);
if (UDF_I_LENEATTR(inode))
ea = fe->extendedAttr;
}
@@ -255,7 +255,7 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
struct ExtendedFileEntry *efe;
efe = (struct ExtendedFileEntry *)bh->b_data;
- eaicb = efe->extendedAttrICB;
+ eaicb = lela_to_cpu(efe->extendedAttrICB);
if (UDF_I_LENEATTR(inode))
ea = efe->extendedAttr;
}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 264086135..ed1507fa7 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -74,10 +74,13 @@ static int udf_get_block(struct inode *, long, struct buffer_head *, int);
*/
void udf_put_inode(struct inode * inode)
{
- lock_kernel();
- udf_discard_prealloc(inode);
- write_inode_now(inode);
- unlock_kernel();
+ if (!(inode->i_sb->s_flags & MS_RDONLY))
+ {
+ lock_kernel();
+ udf_discard_prealloc(inode);
+ write_inode_now(inode);
+ unlock_kernel();
+ }
}
/*
@@ -130,7 +133,7 @@ static int udf_readpage(struct dentry *dentry, struct page *page)
return block_read_full_page(page, udf_get_block);
}
-static int udf_prepare_write(struct page *page, unsigned from, unsigned to)
+static int udf_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return block_prepare_write(page, from, to, udf_get_block);
}
@@ -1554,16 +1557,18 @@ int udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
case ICB_FLAG_AD_SHORT:
{
sad = (short_ad *)sptr;
- sad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
- inode->i_sb->s_blocksize;
+ sad->extLength = cpu_to_le32(
+ EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+ inode->i_sb->s_blocksize);
sad->extPosition = cpu_to_le32(bloc->logicalBlockNum);
break;
}
case ICB_FLAG_AD_LONG:
{
lad = (long_ad *)sptr;
- lad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
- inode->i_sb->s_blocksize;
+ lad->extLength = cpu_to_le32(
+ EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+ inode->i_sb->s_blocksize);
lad->extLocation = cpu_to_lelb(*bloc);
break;
}
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
index 653997033..1403cec52 100644
--- a/fs/udf/lowlevel.c
+++ b/fs/udf/lowlevel.c
@@ -70,8 +70,6 @@ udf_get_last_session(struct super_block *sb)
unsigned int
udf_get_last_block(struct super_block *sb)
{
- extern int *blksize_size[];
- kdev_t dev = sb->s_dev;
struct block_device *bdev = sb->s_bdev;
int ret;
unsigned long lblock = 0;
@@ -80,28 +78,10 @@ udf_get_last_block(struct super_block *sb)
if (ret) /* Hard Disk */
{
- unsigned int hbsize = get_hardblocksize(dev);
- unsigned int blocksize = sb->s_blocksize;
- unsigned int mult = 0;
- unsigned int div = 0;
-
- if (!hbsize)
- hbsize = blksize_size[MAJOR(dev)][MINOR(dev)];
-
- if (hbsize > blocksize)
- mult = hbsize / blocksize;
- else if (blocksize > hbsize)
- div = blocksize / hbsize;
-
ret = ioctl_by_bdev(bdev, BLKGETSIZE, (unsigned long) &lblock);
if (!ret && lblock != 0x7FFFFFFF)
- {
- if (mult)
- lblock *= mult;
- else if (div)
- lblock /= div;
- }
+ lblock = ((512 * lblock) / sb->s_blocksize);
}
if (!ret && lblock)
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index bed1e3984..ae998258e 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -90,7 +90,7 @@ udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
struct FileEntry *fe;
fe = (struct FileEntry *)(*bh)->b_data;
- eaicb = fe->extendedAttrICB;
+ eaicb = lela_to_cpu(fe->extendedAttrICB);
offset = sizeof(struct FileEntry);
}
else
@@ -98,7 +98,7 @@ udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
struct ExtendedFileEntry *efe;
efe = (struct ExtendedFileEntry *)(*bh)->b_data;
- eaicb = efe->extendedAttrICB;
+ eaicb = lela_to_cpu(efe->extendedAttrICB);
offset = sizeof(struct ExtendedFileEntry);
}
@@ -206,7 +206,7 @@ udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
struct FileEntry *fe;
fe = (struct FileEntry *)(*bh)->b_data;
- eaicb = fe->extendedAttrICB;
+ eaicb = lela_to_cpu(fe->extendedAttrICB);
if (UDF_I_LENEATTR(inode))
ea = fe->extendedAttr;
}
@@ -215,7 +215,7 @@ udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
struct ExtendedFileEntry *efe;
efe = (struct ExtendedFileEntry *)(*bh)->b_data;
- eaicb = efe->extendedAttrICB;
+ eaicb = lela_to_cpu(efe->extendedAttrICB);
if (UDF_I_LENEATTR(inode))
ea = efe->extendedAttr;
}
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index c371b5d52..a44e19043 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -935,7 +935,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
inode->i_data.a_ops = &udf_symlink_aops;
inode->i_op = &page_symlink_inode_operations;
- if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ if (UDF_I_ALLOCTYPE(inode) != ICB_FLAG_AD_IN_ICB)
{
struct buffer_head *bh = NULL;
lb_addr bloc, eloc;
@@ -964,7 +964,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
bh = udf_tread(inode->i_sb, block, inode->i_sb->s_blocksize);
ea = bh->b_data + udf_ext0_offset(inode);
- eoffset = inode->i_sb->s_blocksize - (ea - bh->b_data);
+ eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
pc = (struct PathComponent *)ea;
if (*symname == '/')
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 81f59e9a3..5f76abbb0 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -100,14 +100,14 @@ static DECLARE_FSTYPE_DEV(udf_fstype, "udf", udf_read_super);
/* Superblock operations */
static struct super_operations udf_sb_ops = {
- read_inode: udf_read_inode,
+ read_inode: udf_read_inode,
write_inode: udf_write_inode,
- put_inode: udf_put_inode,
+ put_inode: udf_put_inode,
delete_inode: udf_delete_inode,
- put_super: udf_put_super,
+ put_super: udf_put_super,
write_super: udf_write_super,
- statfs: udf_statfs,
- remount_fs: udf_remount_fs,
+ statfs: udf_statfs,
+ remount_fs: udf_remount_fs,
};
struct udf_options
@@ -127,7 +127,6 @@ struct udf_options
uid_t uid;
};
-
static int __init init_udf_fs(void)
{
printk(KERN_NOTICE "udf: registering filesystem\n");
@@ -745,8 +744,9 @@ udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
{
if (udf_CS0toUTF8(&outstr, &instr))
{
- udf_debug("volIdent[] = '%s'\n", outstr.u_name);
- strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name, outstr.u_len);
+ strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name,
+ outstr.u_len > 31 ? 31 : outstr.u_len);
+ udf_debug("volIdent[] = '%s'\n", UDF_SB_VOLIDENT(sb));
}
}
@@ -788,7 +788,6 @@ udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
{
UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation) + UDF_SB_SESSION(sb);
- UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF;
if (UDF_SB_PARTTYPE(sb,i) == UDF_SPARABLE_MAP15)
udf_fill_spartable(sb, &UDF_SB_TYPESPAR(sb,i), UDF_SB_PARTLEN(sb,i));
@@ -803,17 +802,24 @@ udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
udf_debug("unallocatedSpaceTable (part %d)\n", i);
if (phd->unallocatedSpaceBitmap.extLength)
{
- UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap =
+ UDF_SB_PARTMAPS(sb)[i].s_uspace.bitmap =
le32_to_cpu(phd->unallocatedSpaceBitmap.extPosition);
+ UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP;
udf_debug("unallocatedSpaceBitmap (part %d) @ %d\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap);
+ i, UDF_SB_PARTMAPS(sb)[i].s_uspace.bitmap);
}
if (phd->partitionIntegrityTable.extLength)
udf_debug("partitionIntegrityTable (part %d)\n", i);
if (phd->freedSpaceTable.extLength)
udf_debug("freedSpaceTable (part %d)\n", i);
if (phd->freedSpaceBitmap.extLength)
- udf_debug("freedSpaceBitmap (part %d\n", i);
+ {
+ UDF_SB_PARTMAPS(sb)[i].s_fspace.bitmap =
+ le32_to_cpu(phd->freedSpaceBitmap.extPosition);
+ UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP;
+ udf_debug("freedSpaceBitmap (part %d) @ %d\n",
+ i, UDF_SB_PARTMAPS(sb)[i].s_fspace.bitmap);
+ }
}
break;
}
@@ -1184,7 +1190,6 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset)
}
UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
- UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF;
}
}
}
@@ -1520,34 +1525,27 @@ static unsigned int
udf_count_free(struct super_block *sb)
{
struct buffer_head *bh = NULL;
- unsigned int accum=0;
- int index;
- int block=0, newblock;
+ unsigned int accum = 0;
lb_addr loc;
- Uint32 bytes;
- Uint8 value;
- Uint8 * ptr;
- Uint16 ident;
-
- if (UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap == 0xFFFFFFFF)
- {
- if (UDF_SB_LVIDBH(sb))
- {
- if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
- accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
-
- if (accum == 0xFFFFFFFF)
- accum = 0;
+ Uint32 bitmap;
- return accum;
- }
- else
- return 0;
- }
+ if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
+ bitmap = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.bitmap;
+ else if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
+ bitmap = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.bitmap;
else
+ bitmap = 0xFFFFFFFF;
+
+ if (bitmap != 0xFFFFFFFF)
{
struct SpaceBitmapDesc *bm;
- loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap;
+ int block = 0, newblock, index;
+ Uint16 ident;
+ Uint32 bytes;
+ Uint8 value;
+ Uint8 * ptr;
+
+ loc.logicalBlockNum = bitmap;
loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
bh = udf_read_ptagged(sb, loc, 0, &ident);
@@ -1593,6 +1591,18 @@ udf_count_free(struct super_block *sb)
}
}
udf_release_data(bh);
- return accum;
}
+ else
+ {
+ if (UDF_SB_LVIDBH(sb))
+ {
+ if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
+ accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
+
+ if (accum == 0xFFFFFFFF)
+ accum = 0;
+ }
+ }
+
+ return accum;
}
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 6084c5613..6988a7238 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -18,6 +18,11 @@
#define UDF_FLAG_UNDELETE 6
#define UDF_FLAG_UNHIDE 7
#define UDF_FLAG_VARCONV 8
+
+#define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001
+#define UDF_PART_FLAG_UNALLOC_TABLE 0x0002
+#define UDF_PART_FLAG_FREED_BITMAP 0x0004
+#define UDF_PART_FLAG_FREED_TABLE 0x0008
#define UDF_SB_FREE(X)\
{\
@@ -52,6 +57,7 @@
#define UDF_SB_TYPESPAR(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_sparing )
#define UDF_SB_TYPEVIRT(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_virtual )
#define UDF_SB_PARTFUNC(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func )
+#define UDF_SB_PARTFLAGS(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags )
#define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident )
#define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions )
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index b92eed7db..7dd00bc19 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -106,7 +106,7 @@ struct ktm
struct ustr
{
Uint8 u_cmpID;
- Uint8 u_name[UDF_NAME_LEN-1];
+ Uint8 u_name[UDF_NAME_LEN];
Uint8 u_len;
Uint8 padding;
unsigned long u_hash;
@@ -182,6 +182,8 @@ extern void udf_truncate(struct inode *);
extern void udf_free_blocks(const struct inode *, lb_addr, Uint32, Uint32);
extern int udf_prealloc_blocks(const struct inode *, Uint16, Uint32, Uint32);
extern int udf_new_block(const struct inode *, Uint16, Uint32, int *);
+
+/* fsync.c */
extern int udf_sync_file(struct file *, struct dentry *);
/* directory.c */
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 134b3c755..7cb2d3c1f 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -177,7 +177,8 @@ int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
return 0;
}
- for (i = 0; (i < ocu_len) && (utf_o->u_len < UDF_NAME_LEN) ;) {
+ for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
+ {
/* Expand OSTA compressed Unicode to Unicode */
c = ocu[i++];
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index af07961e1..8c5c15d55 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -548,7 +548,7 @@ static int ufs_readpage(struct dentry *dentry, struct page *page)
{
return block_read_full_page(page,ufs_getfrag_block);
}
-static int ufs_prepare_write(struct page *page, unsigned from, unsigned to)
+static int ufs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return block_prepare_write(page,from,to,ufs_getfrag_block);
}
diff --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h
index 118941b3c..b9d8faa61 100644
--- a/include/asm-alpha/fpu.h
+++ b/include/asm-alpha/fpu.h
@@ -27,7 +27,7 @@
#define FPCR_DYN_PLUS (0x3UL << FPCR_DYN_SHIFT) /* towards +INF */
#define FPCR_DYN_MASK (0x3UL << FPCR_DYN_SHIFT)
-#define FPCR_MASK 0xfffe000000000000
+#define FPCR_MASK 0xffff800000000000
/*
* IEEE trap enables are implemented in software. These per-thread
@@ -67,7 +67,8 @@
IEEE_STATUS_OVF | IEEE_STATUS_UNF | \
IEEE_STATUS_INE | IEEE_STATUS_DNO)
-#define IEEE_SW_MASK (IEEE_TRAP_ENABLE_MASK | IEEE_STATUS_MASK | IEEE_MAP_MASK)
+#define IEEE_SW_MASK (IEEE_TRAP_ENABLE_MASK | \
+ IEEE_STATUS_MASK | IEEE_MAP_MASK)
#define IEEE_CURRENT_RM_SHIFT 32
#define IEEE_CURRENT_RM_MASK (3UL<<IEEE_CURRENT_RM_SHIFT)
@@ -78,7 +79,12 @@
/*
* Convert the software IEEE trap enable and status bits into the
- * hardware fpcr format.
+ * hardware fpcr format.
+ *
+ * Digital Unix engineers receive my thanks for not defining the
+ * software bits identical to the hardware bits. The chip designers
+ * receive my thanks for making all the not-implemented fpcr bits
+ * RAZ forcing us to use system calls to read/write this value.
*/
static inline unsigned long
@@ -86,11 +92,13 @@ ieee_swcr_to_fpcr(unsigned long sw)
{
unsigned long fp;
fp = (sw & IEEE_STATUS_MASK) << 35;
- fp |= sw & IEEE_STATUS_MASK ? FPCR_SUM : 0;
+ fp |= (sw & IEEE_MAP_DMZ) << 36;
+ fp |= (sw & IEEE_STATUS_MASK ? FPCR_SUM : 0);
fp |= (~sw & (IEEE_TRAP_ENABLE_INV
| IEEE_TRAP_ENABLE_DZE
| IEEE_TRAP_ENABLE_OVF)) << 48;
fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57;
+ fp |= (sw & IEEE_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
fp |= (~sw & IEEE_TRAP_ENABLE_DNO) << 41;
return fp;
}
@@ -100,10 +108,12 @@ ieee_fpcr_to_swcr(unsigned long fp)
{
unsigned long sw;
sw = (fp >> 35) & IEEE_STATUS_MASK;
+ sw |= (fp >> 36) & IEEE_MAP_DMZ;
sw |= (~fp >> 48) & (IEEE_TRAP_ENABLE_INV
| IEEE_TRAP_ENABLE_DZE
| IEEE_TRAP_ENABLE_OVF);
sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
+ sw |= (fp >> 47) & IEEE_MAP_UMZ;
sw |= (~fp >> 41) & IEEE_TRAP_ENABLE_DNO;
return sw;
}
@@ -115,26 +125,59 @@ ieee_fpcr_to_swcr(unsigned long fp)
never generates arithmetic faults and (b) call_pal instructions
are implied trap barriers. */
-static inline unsigned long rdfpcr(void)
+static inline unsigned long
+rdfpcr(void)
{
unsigned long tmp, ret;
+
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
+ __asm__ ("ftoit $f0,%0\n\t"
+ "mf_fpcr $f0\n\t"
+ "ftoit $f0,%1\n\t"
+ "itoft %0,$f0"
+ : "=r"(tmp), "=r"(ret));
+#else
__asm__ ("stt $f0,%0\n\t"
"mf_fpcr $f0\n\t"
"stt $f0,%1\n\t"
"ldt $f0,%0"
- : "=m"(tmp), "=m"(ret));
+ : "=m"(tmp), "=m"(ret));
+#endif
+
return ret;
}
-static inline void wrfpcr(unsigned long val)
+static inline void
+wrfpcr(unsigned long val)
{
unsigned long tmp;
+
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
+ __asm__ ("ftoit $f0,%0\n\t"
+ "itoft %1,$f0\n\t"
+ "mt_fpcr $f0\n\t"
+ "itoft %0,$f0"
+ : "=&r"(tmp) : "r"(val));
+#else
__asm__ __volatile__ (
"stt $f0,%0\n\t"
"ldt $f0,%1\n\t"
"mt_fpcr $f0\n\t"
"ldt $f0,%0"
: "=m"(tmp) : "m"(val));
+#endif
+}
+
+static inline unsigned long
+swcr_update_status(unsigned long swcr, unsigned long fpcr)
+{
+ /* EV6 implements most of the bits in hardware. Collect
+ the acrued exception bits from the real fpcr. */
+ if (implver() == IMPLVER_EV6) {
+ swcr &= ~IEEE_STATUS_MASK;
+ swcr |= (fpcr >> 35) & IEEE_STATUS_MASK;
+ }
+ return swcr;
}
extern unsigned long alpha_read_fp_reg (unsigned long reg);
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 8f89479b5..27e06783a 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -1,6 +1,8 @@
#ifndef __ALPHA_PCI_H
#define __ALPHA_PCI_H
+#ifdef __KERNEL__
+
#include <linux/spinlock.h>
#include <asm/scatterlist.h>
#include <asm/machvec.h>
@@ -22,7 +24,17 @@ struct pci_controler {
struct resource *io_space;
struct resource *mem_space;
- unsigned long config_space;
+ /* The following are for reporting to userland. The invariant is
+ that if we report a BWX-capable dense memory, we do not report
+ a sparse memory at all, even if it exists. */
+ unsigned long sparse_mem_base;
+ unsigned long dense_mem_base;
+ unsigned long sparse_io_base;
+ unsigned long dense_io_base;
+
+ /* This one's for the kernel only. It's in KSEG somewhere. */
+ unsigned long config_space_base;
+
unsigned int index;
unsigned int first_busno;
unsigned int last_busno;
@@ -132,4 +144,13 @@ pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents,
extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask);
+#endif /* __KERNEL__ */
+
+/* Values for the `which' argument to sys_pciconfig_iobase. */
+#define IOBASE_HOSE 0
+#define IOBASE_SPARSE_MEM 1
+#define IOBASE_DENSE_MEM 2
+#define IOBASE_SPARSE_IO 3
+#define IOBASE_DENSE_IO 4
+
#endif /* __ALPHA_PCI_H */
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 0c5052788..ef04b09ba 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -159,6 +159,16 @@ extern unsigned long __zero_page(void);
* On certain platforms whose physical address space can overlap KSEG,
* namely EV6 and above, we must re-twiddle the physaddr to restore the
* correct high-order bits.
+ *
+ * This is extremely confusing until you realize that this is actually
+ * just working around a userspace bug. The X server was intending to
+ * provide the physical address but instead provided the KSEG address.
+ * Or tried to, except it's not representable.
+ *
+ * On Tsunami there's nothing meaningful at 0x40000000000, so this is
+ * a safe thing to do. Come the first core logic that does put something
+ * in this area -- memory or whathaveyou -- then this hack will have
+ * to go away. So be prepared!
*/
#if defined(CONFIG_ALPHA_GENERIC) && defined(USE_48_BIT_KSEG)
diff --git a/include/asm-alpha/sfp-machine.h b/include/asm-alpha/sfp-machine.h
index 8adc0e74c..5fe63afbd 100644
--- a/include/asm-alpha/sfp-machine.h
+++ b/include/asm-alpha/sfp-machine.h
@@ -74,9 +74,7 @@
#define FP_EX_INEXACT IEEE_TRAP_ENABLE_INE
#define FP_EX_DENORM IEEE_TRAP_ENABLE_DNO
-#define FP_DENORM_ZERO (fpcw & IEEE_MAP_DMZ)
-
-#define FP_HANDLE_EXCEPTIONS return _fex
+#define FP_DENORM_ZERO (swcr & IEEE_MAP_DMZ)
/* We write the results always */
#define FP_INHIBIT_RESULTS 0
diff --git a/include/asm-alpha/smplock.h b/include/asm-alpha/smplock.h
index 2a5c62700..911a06573 100644
--- a/include/asm-alpha/smplock.h
+++ b/include/asm-alpha/smplock.h
@@ -10,6 +10,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
index 93ed9ed85..b71c3a708 100644
--- a/include/asm-alpha/unistd.h
+++ b/include/asm-alpha/unistd.h
@@ -313,6 +313,7 @@
#define __NR_dipc 373
#define __NR_pivot_root 374
#define __NR_mincore 375
+#define __NR_pciconfig_iobase 376
#if defined(__LIBRARY__) && defined(__GNUC__)
diff --git a/include/asm-arm/smplock.h b/include/asm-arm/smplock.h
index 1590fafe9..96565069c 100644
--- a/include/asm-arm/smplock.h
+++ b/include/asm-arm/smplock.h
@@ -8,6 +8,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-generic/smplock.h b/include/asm-generic/smplock.h
index 1590fafe9..96565069c 100644
--- a/include/asm-generic/smplock.h
+++ b/include/asm-generic/smplock.h
@@ -8,6 +8,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-i386/cache.h b/include/asm-i386/cache.h
index 7260b50e4..de4a7a87c 100644
--- a/include/asm-i386/cache.h
+++ b/include/asm-i386/cache.h
@@ -4,11 +4,9 @@
#ifndef __ARCH_I386_CACHE_H
#define __ARCH_I386_CACHE_H
+#include <linux/config.h>
+
/* bytes per L1 cache line */
-#if CPU==586 || CPU==686
-#define L1_CACHE_BYTES 32
-#else
-#define L1_CACHE_BYTES 16
-#endif
+#define L1_CACHE_BYTES CONFIG_X86_L1_CACHE_BYTES
#endif
diff --git a/include/asm-i386/smplock.h b/include/asm-i386/smplock.h
index 2c4b30791..f6f29383b 100644
--- a/include/asm-i386/smplock.h
+++ b/include/asm-i386/smplock.h
@@ -10,6 +10,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h
index 515ffa7d5..ef0dd75d8 100644
--- a/include/asm-i386/string.h
+++ b/include/asm-i386/string.h
@@ -2,6 +2,7 @@
#define _I386_STRING_H_
#ifdef __KERNEL__
+#include <linux/config.h>
/*
* On a 486 or Pentium, we are better off not using the
* byte string operations. But on a 386 or a PPro the
@@ -11,7 +12,7 @@
* Also, the byte strings actually work correctly. Forget
* the i486 routines for now as they may be broken..
*/
-#if FIXED_486_STRING && (CPU == 486 || CPU == 586)
+#if FIXED_486_STRING && defined(CONFIG_X86_USE_STRING_486)
#include <asm/string-486.h>
#else
@@ -284,8 +285,6 @@ __asm__ __volatile__( \
#define __HAVE_ARCH_MEMCPY
-#include <linux/config.h>
-
#ifdef CONFIG_X86_USE_3DNOW
/* All this just for in_interrupt() ... */
@@ -529,7 +528,7 @@ extern inline void * memscan(void * addr, int c, size_t size)
return addr;
}
+#endif /* CONFIG_X86_USE_STRING_486 */
#endif /* __KERNEL__ */
#endif
-#endif
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 36f2c8855..75e04e938 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -1,6 +1,7 @@
#ifndef __ASM_SYSTEM_H
#define __ASM_SYSTEM_H
+#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <linux/bitops.h> /* for LOCK_PREFIX */
@@ -215,7 +216,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
* indicated by comparing RETURN with OLD.
*/
-#if CPU != 386
+#ifdef CONFIG_X86_CMPXCHG
#define __HAVE_ARCH_CMPXCHG 1
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 7546159f6..2e3081a5c 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -56,7 +56,7 @@ extern int __verify_write(const void *, unsigned long);
segment_eq(get_fs(),KERNEL_DS) || \
__verify_write((void *)(addr),(size))))
-#endif /* CPU */
+#endif
extern inline int verify_area(int type, const void * addr, unsigned long size)
{
diff --git a/include/asm-ia64/smplock.h b/include/asm-ia64/smplock.h
index 136a777b9..a5c48a8d2 100644
--- a/include/asm-ia64/smplock.h
+++ b/include/asm-ia64/smplock.h
@@ -10,6 +10,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-m68k/smplock.h b/include/asm-m68k/smplock.h
index 1590fafe9..96565069c 100644
--- a/include/asm-m68k/smplock.h
+++ b/include/asm-m68k/smplock.h
@@ -8,6 +8,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-mips/smplock.h b/include/asm-mips/smplock.h
index 67a4bb617..188c4b4c9 100644
--- a/include/asm-mips/smplock.h
+++ b/include/asm-mips/smplock.h
@@ -1,4 +1,4 @@
-/* $Id: smplock.h,v 1.1 1998/08/25 09:22:02 ralf Exp $
+/* $Id: smplock.h,v 1.2 1999/10/09 00:01:43 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -11,6 +11,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-mips64/smplock.h b/include/asm-mips64/smplock.h
index ad3bfd6ad..f0b627e6a 100644
--- a/include/asm-mips64/smplock.h
+++ b/include/asm-mips64/smplock.h
@@ -3,8 +3,8 @@
*
* Default SMP lock implementation
*/
-#ifndef __ASM_SMPLOCK_H
-#define __ASM_SMPLOCK_H
+#ifndef _ASM_SMPLOCK_H
+#define _ASM_SMPLOCK_H
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -12,6 +12,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
@@ -51,4 +53,4 @@ static __inline__ void unlock_kernel(void)
spin_unlock(&kernel_flag);
}
-#endif /* __ASM_SMPLOCK_H */
+#endif /* _ASM_SMPLOCK_H */
diff --git a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h
index 3ae89d9cc..758e1a93c 100644
--- a/include/asm-ppc/elf.h
+++ b/include/asm-ppc/elf.h
@@ -38,9 +38,11 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+#ifdef __KERNEL__
/* Altivec registers */
typedef vector128 elf_vrreg_t;
typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
+#endif /* __KERNEL__ */
#define ELF_CORE_COPY_REGS(gregs, regs) \
memcpy(gregs, regs, \
diff --git a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h
index ebea80172..99a5c8386 100644
--- a/include/asm-ppc/mman.h
+++ b/include/asm-ppc/mman.h
@@ -16,14 +16,20 @@
#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
-#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */
+#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
#define MS_ASYNC 1 /* sync memory asynchronously */
#define MS_INVALIDATE 2 /* invalidate the caches */
#define MS_SYNC 4 /* synchronous memory sync */
-#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */
-#define MCL_FUTURE 0x4000 /* lock all additions to address space */
+#define MCL_CURRENT 1 /* lock all current mappings */
+#define MCL_FUTURE 2 /* lock all future mappings */
+
+#define MADV_NORMAL 0x0 /* default page-in behavior */
+#define MADV_RANDOM 0x1 /* page-in minimum required */
+#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */
+#define MADV_WILLNEED 0x3 /* pre-fault pages */
+#define MADV_DONTNEED 0x4 /* discard these pages */
/* compatibility flags */
#define MAP_ANON MAP_ANONYMOUS
diff --git a/include/asm-ppc/smplock.h b/include/asm-ppc/smplock.h
index 1590fafe9..96565069c 100644
--- a/include/asm-ppc/smplock.h
+++ b/include/asm-ppc/smplock.h
@@ -8,6 +8,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-ppc/types.h b/include/asm-ppc/types.h
index ca2fb0529..4ebbb9e02 100644
--- a/include/asm-ppc/types.h
+++ b/include/asm-ppc/types.h
@@ -2,7 +2,6 @@
#define _PPC_TYPES_H
#ifndef __ASSEMBLY__
-#ifdef __KERNEL__
typedef unsigned short umode_t;
@@ -20,6 +19,11 @@ typedef __signed__ long long __s64;
typedef unsigned long long __u64;
#endif
+typedef struct {
+ __u32 u[4];
+} __attribute((aligned(16))) vector128;
+
+#ifdef __KERNEL__
/*
* These aren't exported outside the kernel to avoid name space clashes
*/
@@ -35,10 +39,6 @@ typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
-typedef struct {
- u32 u[4];
-} __attribute((aligned(16))) vector128;
-
#define BITS_PER_LONG 32
/* DMA addresses are 32-bits wide */
diff --git a/include/asm-sparc/asm_offsets.h b/include/asm-sparc/asm_offsets.h
index 3bbf39b20..57c2ffd9b 100644
--- a/include/asm-sparc/asm_offsets.h
+++ b/include/asm-sparc/asm_offsets.h
@@ -142,21 +142,21 @@
#define ASIZ_task_cap_inheritable 0x00000004
#define AOFF_task_cap_permitted 0x000001c8
#define ASIZ_task_cap_permitted 0x00000004
-#define AOFF_task_user 0x000001cc
+#define AOFF_task_user 0x000001d0
#define ASIZ_task_user 0x00000004
-#define AOFF_task_rlim 0x000001d0
+#define AOFF_task_rlim 0x000001d4
#define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math 0x00000220
+#define AOFF_task_used_math 0x00000224
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x00000222
+#define AOFF_task_comm 0x00000226
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x00000234
+#define AOFF_task_link_count 0x00000238
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x00000238
+#define AOFF_task_tty 0x0000023c
#define ASIZ_task_tty 0x00000004
-#define AOFF_task_semundo 0x0000023c
+#define AOFF_task_semundo 0x00000240
#define ASIZ_task_semundo 0x00000004
-#define AOFF_task_semsleeping 0x00000240
+#define AOFF_task_semsleeping 0x00000244
#define ASIZ_task_semsleeping 0x00000004
#define AOFF_task_thread 0x00000248
#define ASIZ_task_thread 0x00000380
@@ -423,49 +423,49 @@
#define ASIZ_task_cap_inheritable 0x00000004
#define AOFF_task_cap_permitted 0x000002c4
#define ASIZ_task_cap_permitted 0x00000004
-#define AOFF_task_user 0x000002c8
+#define AOFF_task_user 0x000002cc
#define ASIZ_task_user 0x00000004
-#define AOFF_task_rlim 0x000002cc
+#define AOFF_task_rlim 0x000002d0
#define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math 0x0000031c
+#define AOFF_task_used_math 0x00000320
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x0000031e
+#define AOFF_task_comm 0x00000322
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x00000330
+#define AOFF_task_link_count 0x00000334
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x00000334
+#define AOFF_task_tty 0x00000338
#define ASIZ_task_tty 0x00000004
-#define AOFF_task_semundo 0x00000338
+#define AOFF_task_semundo 0x0000033c
#define ASIZ_task_semundo 0x00000004
-#define AOFF_task_semsleeping 0x0000033c
+#define AOFF_task_semsleeping 0x00000340
#define ASIZ_task_semsleeping 0x00000004
-#define AOFF_task_thread 0x00000340
+#define AOFF_task_thread 0x00000348
#define ASIZ_task_thread 0x00000380
-#define AOFF_task_fs 0x000006c0
+#define AOFF_task_fs 0x000006c8
#define ASIZ_task_fs 0x00000004
-#define AOFF_task_files 0x000006c4
+#define AOFF_task_files 0x000006cc
#define ASIZ_task_files 0x00000004
-#define AOFF_task_sigmask_lock 0x000006c8
+#define AOFF_task_sigmask_lock 0x000006d0
#define ASIZ_task_sigmask_lock 0x00000008
-#define AOFF_task_sig 0x000006d0
+#define AOFF_task_sig 0x000006d8
#define ASIZ_task_sig 0x00000004
-#define AOFF_task_signal 0x000006d4
+#define AOFF_task_signal 0x000006dc
#define ASIZ_task_signal 0x00000008
-#define AOFF_task_blocked 0x000006dc
+#define AOFF_task_blocked 0x000006e4
#define ASIZ_task_blocked 0x00000008
-#define AOFF_task_sigqueue 0x000006e4
+#define AOFF_task_sigqueue 0x000006ec
#define ASIZ_task_sigqueue 0x00000004
-#define AOFF_task_sigqueue_tail 0x000006e8
+#define AOFF_task_sigqueue_tail 0x000006f0
#define ASIZ_task_sigqueue_tail 0x00000004
-#define AOFF_task_sas_ss_sp 0x000006ec
+#define AOFF_task_sas_ss_sp 0x000006f4
#define ASIZ_task_sas_ss_sp 0x00000004
-#define AOFF_task_sas_ss_size 0x000006f0
+#define AOFF_task_sas_ss_size 0x000006f8
#define ASIZ_task_sas_ss_size 0x00000004
-#define AOFF_task_parent_exec_id 0x000006f4
+#define AOFF_task_parent_exec_id 0x000006fc
#define ASIZ_task_parent_exec_id 0x00000004
-#define AOFF_task_self_exec_id 0x000006f8
+#define AOFF_task_self_exec_id 0x00000700
#define ASIZ_task_self_exec_id 0x00000004
-#define AOFF_task_exit_sem 0x000006fc
+#define AOFF_task_exit_sem 0x00000704
#define ASIZ_task_exit_sem 0x00000024
#define AOFF_mm_mmap 0x00000000
#define ASIZ_mm_mmap 0x00000004
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index b0543fffb..8925923b0 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.92 2000/03/02 20:37:37 davem Exp $ */
+/* $Id: pgtable.h,v 1.93 2000/03/21 01:04:53 anton Exp $ */
#ifndef _SPARC_PGTABLE_H
#define _SPARC_PGTABLE_H
@@ -96,9 +96,12 @@ BTFIXUPDEF_SIMM13(user_ptrs_per_pgd)
#define VMALLOC_START (0xfe300000)
#define VMALLOC_END ~0x0UL
-#define pte_ERROR(e) __builtin_trap()
-#define pmd_ERROR(e) __builtin_trap()
-#define pgd_ERROR(e) __builtin_trap()
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
BTFIXUPDEF_INT(page_none)
BTFIXUPDEF_INT(page_shared)
diff --git a/include/asm-sparc/smplock.h b/include/asm-sparc/smplock.h
index 1590fafe9..96565069c 100644
--- a/include/asm-sparc/smplock.h
+++ b/include/asm-sparc/smplock.h
@@ -8,6 +8,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index 757f43c4d..7211c7d81 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.32 2000/03/15 07:19:28 davem Exp $ */
+/* $Id: page.h,v 1.33 2000/03/22 02:48:04 davem Exp $ */
#ifndef _SPARC64_PAGE_H
#define _SPARC64_PAGE_H
@@ -96,8 +96,7 @@ typedef unsigned long iopgprot_t;
#ifndef __ASSEMBLY__
/* Do prdele, look what happens to be in %g4... */
-register unsigned long page_offset asm("g4");
-#define PAGE_OFFSET page_offset
+register unsigned long PAGE_OFFSET asm("g4");
#else
#define PAGE_OFFSET 0xFFFFF80000000000
#endif
diff --git a/include/asm-sparc64/smplock.h b/include/asm-sparc64/smplock.h
index 5791e3c7a..6b3c900de 100644
--- a/include/asm-sparc64/smplock.h
+++ b/include/asm-sparc64/smplock.h
@@ -9,6 +9,8 @@
extern spinlock_t kernel_flag;
+#define kernel_locked() spin_is_locked(&kernel_flag)
+
/*
* Release global kernel lock and global interrupt lock
*/
diff --git a/include/linux/atm_idt77105.h b/include/linux/atm_idt77105.h
index 70e9e6e59..05621cf20 100644
--- a/include/linux/atm_idt77105.h
+++ b/include/linux/atm_idt77105.h
@@ -9,6 +9,7 @@
#include <asm/types.h>
#include <linux/atmioc.h>
+#include <linux/atmdev.h>
/*
* Structure for IDT77105_GETSTAT and IDT77105_GETSTATZ ioctls.
@@ -21,20 +22,7 @@ struct idt77105_stats {
__u32 rx_hec_errors; /* Header Error Check errors on receive */
};
-#define IDT77105_GETLOOP _IOW('a',ATMIOC_PHYPRV,struct atmif_sioc) /* get loopback mode */
-#define IDT77105_SETLOOP _IOW('a',ATMIOC_PHYPRV+1,struct atmif_sioc) /* set loopback mode */
#define IDT77105_GETSTAT _IOW('a',ATMIOC_PHYPRV+2,struct atmif_sioc) /* get stats */
#define IDT77105_GETSTATZ _IOW('a',ATMIOC_PHYPRV+3,struct atmif_sioc) /* get stats and zero */
-
-/*
- * TODO: what we need is a global loopback mode get/set ioctl for
- * all devices, not these device-specific hacks -- Greg Banks
- */
-#define IDT77105_LM_NONE 0 /* no loopback */
-#define IDT77105_LM_DIAG 1 /* diagnostic (i.e. loop TX to RX)
- * (a.k.a. local loopback) */
-#define IDT77105_LM_LOOP 2 /* line (i.e. loop RX to TX)
- * (a.k.a. remote loopback) */
-
#endif
diff --git a/include/linux/atm_suni.h b/include/linux/atm_suni.h
index 2e6a01a61..84f3aab54 100644
--- a/include/linux/atm_suni.h
+++ b/include/linux/atm_suni.h
@@ -1,19 +1,12 @@
/* atm_suni.h - Driver-specific declarations of the SUNI driver (for use by
driver-specific utilities) */
-/* Written 1998 by Werner Almesberger, EPFL ICA */
+/* Written 1998,2000 by Werner Almesberger, EPFL ICA */
#ifndef LINUX_ATM_SUNI_H
#define LINUX_ATM_SUNI_H
-#include <linux/atmioc.h>
-
-#define SUNI_GETLOOP _IOR('a',ATMIOC_PHYPRV,int) /* get loopback mode */
-#define SUNI_SETLOOP _IO('a',ATMIOC_PHYPRV+1) /* set loopback mode */
-
-#define SUNI_LM_NONE 0 /* no loopback */
-#define SUNI_LM_DIAG 1 /* diagnostic (i.e. loop TX to RX) */
-#define SUNI_LM_LOOP 2 /* line (i.e. loop RX to TX) */
+/* everything obsoleted */
#endif
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index 95e97de35..0a9eb9762 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -1,6 +1,6 @@
/* atmdev.h - ATM device driver declarations and various related items */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_ATMDEV_H
@@ -20,6 +20,8 @@
SONET overhead: /270*260 (9 section, 1 path)
bits per cell: /8/53
max cell rate: 353207.547 cells/sec */
+#define ATM_25_PCR ((25600000/8-8000)/54)
+ /* 25 Mbps ATM cell rate (59111) */
#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer
quota per PDU */
@@ -27,10 +29,17 @@
#define ATM_SD(s) ((s)->sk->protinfo.af_atm)
+#define __AAL_STAT_ITEMS \
+ __HANDLE_ITEM(tx); /* TX okay */ \
+ __HANDLE_ITEM(tx_err); /* TX errors */ \
+ __HANDLE_ITEM(rx); /* RX okay */ \
+ __HANDLE_ITEM(rx_err); /* RX errors */ \
+ __HANDLE_ITEM(rx_drop); /* RX out of memory */
+
struct atm_aal_stats {
- int tx,tx_err; /* TX okay and errors */
- int rx,rx_err; /* RX okay and errors */
- int rx_drop; /* RX out of memory */
+#define __HANDLE_ITEM(i) int i
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
};
@@ -69,12 +78,53 @@ struct atm_dev_stats {
/* get AAL layer statistics */
#define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc)
/* get AAL layer statistics and zero */
+#define ATM_GETLOOP _IOW('a',ATMIOC_SARCOM+2,struct atmif_sioc)
+ /* get loopback mode */
+#define ATM_SETLOOP _IOW('a',ATMIOC_SARCOM+3,struct atmif_sioc)
+ /* set loopback mode */
+#define ATM_QUERYLOOP _IOW('a',ATMIOC_SARCOM+4,struct atmif_sioc)
+ /* query supported loopback modes */
#define ATM_SETSC _IOW('a',ATMIOC_SPECIAL+1,int)
/* enable or disable single-copy */
/* for ATM_GETTYPE */
#define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */
+/*
+ * Loopback modes for ATM_{PHY,SAR}_{GET,SET}LOOP
+ */
+
+/* Point of loopback CPU-->SAR-->PHY-->line--> ... */
+#define __ATM_LM_NONE 0 /* no loop back ^ ^ ^ ^ */
+#define __ATM_LM_AAL 1 /* loop back PDUs --' | | | */
+#define __ATM_LM_ATM 2 /* loop back ATM cells ---' | | */
+/* RESERVED 4 loop back on PHY side ---' */
+#define __ATM_LM_PHY 8 /* loop back bits (digital) ----' | */
+#define __ATM_LM_ANALOG 16 /* loop back the analog signal --------' */
+
+/* Direction of loopback */
+#define __ATM_LM_MKLOC(n) ((n)) /* Local (i.e. loop TX to RX) */
+#define __ATM_LM_MKRMT(n) ((n) << 8) /* Remote (i.e. loop RX to TX) */
+
+#define __ATM_LM_XTLOC(n) ((n) & 0xff)
+#define __ATM_LM_XTRMT(n) (((n) >> 8) & 0xff)
+
+#define ATM_LM_NONE 0 /* no loopback */
+
+#define ATM_LM_LOC_AAL __ATM_LM_MKLOC(__ATM_LM_AAL)
+#define ATM_LM_LOC_ATM __ATM_LM_MKLOC(__ATM_LM_ATM)
+#define ATM_LM_LOC_PHY __ATM_LM_MKLOC(__ATM_LM_PHY)
+#define ATM_LM_LOC_ANALOG __ATM_LM_MKLOC(__ATM_LM_ANALOG)
+
+#define ATM_LM_RMT_AAL __ATM_LM_MKRMT(__ATM_LM_AAL)
+#define ATM_LM_RMT_ATM __ATM_LM_MKRMT(__ATM_LM_ATM)
+#define ATM_LM_RMT_PHY __ATM_LM_MKRMT(__ATM_LM_PHY)
+#define ATM_LM_RMT_ANALOG __ATM_LM_MKRMT(__ATM_LM_ANALOG)
+
+/*
+ * Note: ATM_LM_LOC_* and ATM_LM_RMT_* can be combined, provided that
+ * __ATM_LM_XTLOC(x) <= __ATM_LM_XTRMT(x)
+ */
struct atm_iobuf {
@@ -132,7 +182,9 @@ struct atm_cirange {
"SESSION", "HASSAP", "BOUND", "CLOSE"
-#ifdef __KERNEL__
+#ifndef __KERNEL__
+#undef __AAL_STAT_ITEMS
+#else
#include <linux/sched.h> /* wait_queue_head_t */
#include <linux/time.h> /* struct timeval */
@@ -147,39 +199,56 @@ struct atm_cirange {
#endif
-#define ATM_VF_ADDR 1 /* Address is in use. Set by anybody, cleared
+struct k_atm_aal_stats {
+#define __HANDLE_ITEM(i) atomic_t i
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
+};
+
+
+struct k_atm_dev_stats {
+ struct k_atm_aal_stats aal0;
+ struct k_atm_aal_stats aal34;
+ struct k_atm_aal_stats aal5;
+};
+
+
+enum {
+ ATM_VF_ADDR, /* Address is in use. Set by anybody, cleared
by device driver. */
-#define ATM_VF_READY 2 /* VC is ready to transfer data. Set by device
+ ATM_VF_READY, /* VC is ready to transfer data. Set by device
driver, cleared by anybody. */
-#define ATM_VF_PARTIAL 4 /* resources are bound to PVC (partial PVC
+ ATM_VF_PARTIAL, /* resources are bound to PVC (partial PVC
setup), controlled by socket layer */
-#define ATM_VF_BOUND 16384 /* local SAP is set, controlled by SVC socket
- layer */
-#define ATM_VF_REGIS 8 /* registered with demon, controlled by SVC
+ ATM_VF_REGIS, /* registered with demon, controlled by SVC
socket layer */
-#define ATM_VF_RELEASED 16 /* demon has indicated/requested release,
+ ATM_VF_BOUND, /* local SAP is set, controlled by SVC socket
+ layer */
+ ATM_VF_RELEASED, /* demon has indicated/requested release,
controlled by SVC socket layer */
-#define ATM_VF_HASQOS 32 /* QOS parameters have been set */
-#define ATM_VF_LISTEN 64 /* socket is used for listening */
-#define ATM_VF_META 128 /* SVC socket isn't used for normal data
+ ATM_VF_HASQOS, /* QOS parameters have been set */
+ ATM_VF_LISTEN, /* socket is used for listening */
+ ATM_VF_META, /* SVC socket isn't used for normal data
traffic and doesn't depend on signaling
to be available */
- /* 256; unused */
- /* 512; unused */
- /* 1024; unused */
- /* 2048; unused */
-#define ATM_VF_SESSION 4096 /* VCC is p2mp session control descriptor */
-#define ATM_VF_HASSAP 8192 /* SAP has been set */
-#define ATM_VF_CLOSE 32768 /* asynchronous close - treat like VF_RELEASED*/
+ ATM_VF_SESSION, /* VCC is p2mp session control descriptor */
+ ATM_VF_HASSAP, /* SAP has been set */
+ ATM_VF_CLOSE, /* asynchronous close - treat like VF_RELEASED*/
+};
+
#define ATM_VF2VS(flags) \
- ((flags) & ATM_VF_READY ? ATM_VS_CONNECTED : \
- (flags) & ATM_VF_RELEASED ? ATM_VS_CLOSING : \
- (flags) & ATM_VF_LISTEN ? ATM_VS_LISTEN : \
- (flags) & ATM_VF_REGIS ? ATM_VS_INUSE : \
- (flags) & ATM_VF_BOUND ? ATM_VS_BOUND : ATM_VS_IDLE)
+ (test_bit(ATM_VF_READY,&(flags)) ? ATM_VS_CONNECTED : \
+ test_bit(ATM_VF_RELEASED,&(flags)) ? ATM_VS_CLOSING : \
+ test_bit(ATM_VF_LISTEN,&(flags)) ? ATM_VS_LISTEN : \
+ test_bit(ATM_VF_REGIS,&(flags)) ? ATM_VS_INUSE : \
+ test_bit(ATM_VF_BOUND,&(flags)) ? ATM_VS_BOUND : ATM_VS_IDLE)
+
+
+enum {
+ ATM_DF_CLOSE, /* close device when last VCC is closed */
+};
-#define ATM_DF_CLOSE 1 /* close device when last VCC is closed */
#define ATM_PHY_SIG_LOST 0 /* no carrier/light */
#define ATM_PHY_SIG_UNKNOWN 1 /* carrier/light status is unknown */
@@ -188,8 +257,11 @@ struct atm_cirange {
#define ATM_ATMOPT_CLP 1 /* set CLP bit */
+typedef struct { unsigned short bits; } atm_vcc_flags_t;
+
+
struct atm_vcc {
- unsigned short flags; /* VCC flags (ATM_VF_*) */
+ atm_vcc_flags_t flags; /* VCC flags (ATM_VF_*) */
unsigned char family; /* address family; 0 if unused */
short vpi; /* VPI and VCI (types must be equal */
/* with sockaddr) */
@@ -207,11 +279,12 @@ struct atm_vcc {
/* modified by protocol or by driver.*/
/* NOTE: this interface will change */
int (*push_oam)(struct atm_vcc *vcc,void *cell);
+ int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
void *dev_data; /* per-device data */
void *proto_data; /* per-protocol data */
struct timeval timestamp; /* AAL timestamps */
struct sk_buff_head recvq; /* receive queue */
- struct atm_aal_stats *stats; /* pointer to AAL stats group */
+ struct k_atm_aal_stats *stats; /* pointer to AAL stats group */
wait_queue_head_t sleep; /* if socket is busy */
wait_queue_head_t wsleep; /* if waiting for write buffer space */
struct sock *sk; /* socket backpointer */
@@ -240,6 +313,9 @@ struct atm_dev_addr {
};
+typedef struct { unsigned int bits; } atm_dev_flags_t;
+
+
struct atm_dev {
const struct atmdev_ops *ops; /* device operations; NULL if unused */
const struct atmphy_ops *phy; /* PHY operations, may be undefined */
@@ -250,11 +326,11 @@ struct atm_dev {
struct atm_vcc *last; /* last VCC (or undefined) */
void *dev_data; /* per-device data */
void *phy_data; /* private PHY date */
- unsigned long flags; /* device flags (ATM_DF_*) */
+ atm_dev_flags_t flags; /* device flags (ATM_DF_*) */
struct atm_dev_addr *local; /* local ATM addresses */
unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */
struct atm_cirange ci_range; /* VPI/VCI range */
- struct atm_dev_stats stats; /* statistics */
+ struct k_atm_dev_stats stats; /* statistics */
char signal; /* signal status (ATM_PHY_SIG_*) */
int link_rate; /* link rate (default: OC3) */
#ifdef CONFIG_PROC_FS
@@ -307,6 +383,7 @@ struct atmphy_ops {
int (*start)(struct atm_dev *dev);
int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
void (*interrupt)(struct atm_dev *dev);
+ int (*stop)(struct atm_dev *dev);
};
struct atm_skb_data {
@@ -318,7 +395,7 @@ struct atm_skb_data {
#define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
- int number,unsigned long flags); /* number == -1: pick first available */
+ int number,atm_dev_flags_t *flags); /* number == -1: pick first available */
struct atm_dev *atm_find_dev(int number);
void atm_dev_deregister(struct atm_dev *dev);
void shutdown_atm_dev(struct atm_dev *dev);
diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h
index aed60f5c2..9ca80334f 100644
--- a/include/linux/awe_voice.h
+++ b/include/linux/awe_voice.h
@@ -3,9 +3,9 @@
*
* Voice information definitions for the low level driver for the
* AWE32/SB32/AWE64 wave table synth.
- * version 0.4.3; Feb. 1, 1999
+ * version 0.4.4; Jan. 4, 2000
*
- * Copyright (C) 1996-1999 Takashi Iwai
+ * Copyright (C) 1996-2000 Takashi Iwai
*
* 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
@@ -57,6 +57,7 @@ typedef struct awe_patch_info {
#define AWE_MAP_PRESET 6 /* awe_voice_map */
/*#define AWE_PROBE_INFO 7*/ /* awe_voice_map (pat only) */
#define AWE_PROBE_DATA 8 /* optarg=sample */
+#define AWE_REMOVE_INFO 9 /* optarg=(bank<<8)|instr */
#define AWE_LOAD_CHORUS_FX 0x10 /* awe_chorus_fx_rec (optarg=mode) */
#define AWE_LOAD_REVERB_FX 0x11 /* awe_reverb_fx_rec (optarg=mode) */
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 14e163b0e..04e9963de 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -21,7 +21,7 @@ struct linux_binprm{
struct page *page[MAX_ARG_PAGES];
unsigned long p; /* current top of mem */
int sh_bang;
- struct dentry * dentry;
+ struct file * file;
int e_uid, e_gid;
kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
int argc, envc;
@@ -45,11 +45,6 @@ struct linux_binfmt {
extern int register_binfmt(struct linux_binfmt *);
extern int unregister_binfmt(struct linux_binfmt *);
-extern int read_exec(struct dentry *, unsigned long offset,
- char * addr, unsigned long count, int to_kmem);
-
-extern int open_dentry(struct dentry *, int mode);
-
extern int prepare_binprm(struct linux_binprm *);
extern void remove_arg_zero(struct linux_binprm *);
extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
diff --git a/include/linux/capi.h b/include/linux/capi.h
index 9876da085..b5cd26c52 100644
--- a/include/linux/capi.h
+++ b/include/linux/capi.h
@@ -1,11 +1,28 @@
/*
- * $Id: capi.h,v 1.1 1997/03/04 21:27:33 calle Exp $
+ * $Id: capi.h,v 1.3 2000/03/08 17:06:34 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.h,v $
+ * Revision 1.3 2000/03/08 17:06:34 calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.2 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.1 1997/03/04 21:27:33 calle
* First version in isdn4linux
*
@@ -108,6 +125,7 @@ typedef struct capi_manufacturer_cmd {
*/
#define CAPI_INSTALLED _IOR('C',0x22, __u16)
+
/*
* member contr is input for
* CAPI_GET_MANUFACTURER, CAPI_VERSION, CAPI_GET_SERIAL
@@ -124,4 +142,18 @@ typedef union capi_ioctl_struct {
__u16 errcode;
} capi_ioctl_struct;
+/*
+ * Middleware extension
+ */
+
+#define CAPIFLAG_HIGHJACKING 0x0001
+
+#define CAPI_GET_FLAGS _IOR('C',0x23, unsigned)
+#define CAPI_SET_FLAGS _IOR('C',0x24, unsigned)
+#define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned)
+
+#define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned)
+
+#define CAPI_NCCI_GETUNIT _IOR('C',0x27, unsigned)
+
#endif /* __LINUX_CAPI_H__ */
diff --git a/include/linux/circ_buf.h b/include/linux/circ_buf.h
new file mode 100644
index 000000000..a2ed0591f
--- /dev/null
+++ b/include/linux/circ_buf.h
@@ -0,0 +1,32 @@
+#ifndef _LINUX_CIRC_BUF_H
+#define _LINUX_CIRC_BUF_H 1
+
+struct circ_buf {
+ char *buf;
+ int head;
+ int tail;
+};
+
+/* Return count in buffer. */
+#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
+
+/* Return space available, 0..size-1. We always leave one free char
+ as a completely full buffer has head == tail, which is the same as
+ empty. */
+#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
+
+/* Return count up to the end of the buffer. Carefully avoid
+ accessing head and tail more than once, so they can change
+ underneath us without returning inconsistent results. */
+#define CIRC_CNT_TO_END(head,tail,size) \
+ ({int end = (size) - (tail); \
+ int n = ((head) + end) & ((size)-1); \
+ n < end ? n : end;})
+
+/* Return space available up to the end of the buffer. */
+#define CIRC_SPACE_TO_END(head,tail,size) \
+ ({int end = (size) - 1 - (head); \
+ int n = (end + (tail)) & ((size)-1); \
+ n <= end ? n : end+1;})
+
+#endif /* _LINUX_CIRC_BUF_H */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index c5ef464b4..4cc4c56ce 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -157,6 +157,9 @@ extern struct dentry * d_alloc_root(struct inode *);
/* test whether root is busy without destroying dcache */
extern int is_root_busy(struct dentry *);
+/* test whether we have any submounts in a subdir tree */
+extern int have_submounts(struct dentry *);
+
/*
* This adds the entry to the hash queues.
*/
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 85e8d092f..25178b66b 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -306,10 +306,7 @@ struct ext2_inode {
/*
* Mount flags
*/
-#define EXT2_MOUNT_CHECK_NORMAL 0x0001 /* Do some more checks */
-#define EXT2_MOUNT_CHECK_STRICT 0x0002 /* Do again more checks */
-#define EXT2_MOUNT_CHECK (EXT2_MOUNT_CHECK_NORMAL | \
- EXT2_MOUNT_CHECK_STRICT)
+#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index d763e4ba8..c7df47297 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -435,12 +435,41 @@ struct fb_videomode {
u32 vmode;
};
+#ifdef MODULE
+static inline int fb_find_mode(struct fb_var_screeninfo *var,
+ struct fb_info *info, const char *mode_option,
+ const struct fb_videomode *db,
+ unsigned int dbsize,
+ const struct fb_videomode *default_mode,
+ unsigned int default_bpp)
+{
+ extern int __fb_try_mode(struct fb_var_screeninfo *var,
+ struct fb_info *info,
+ const struct fb_videomode *mode,
+ unsigned int bpp);
+ /*
+ * FIXME: How to make the compiler optimize vga640x400 away if
+ * default_mode is non-NULL?
+ */
+ static const struct fb_videomode vga640x400 = {
+ /* 640x400 @ 70 Hz, 31.5 kHz hsync */
+ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+ };
+ if (!default_mode)
+ default_mode = &vga640x400;
+ if (!default_bpp)
+ default_bpp = 8;
+ return __fb_try_mode(var, info, default_mode, default_bpp);
+}
+#else
extern int __init fb_find_mode(struct fb_var_screeninfo *var,
struct fb_info *info, const char *mode_option,
const struct fb_videomode *db,
unsigned int dbsize,
const struct fb_videomode *default_mode,
unsigned int default_bpp);
+#endif
#endif /* __KERNEL__ */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1001d5cba..c1d3ffe75 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -339,7 +339,7 @@ struct address_space;
struct address_space_operations {
int (*writepage) (struct dentry *, struct page *);
int (*readpage)(struct dentry *, struct page *);
- int (*prepare_write)(struct page *, unsigned, unsigned);
+ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
int (*bmap)(struct address_space *, long);
@@ -751,8 +751,7 @@ static inline int vfs_statfs(struct super_block *sb, struct statfs *buf)
return -ENODEV;
if (!sb->s_op || !sb->s_op->statfs)
return -ENOSYS;
- memset(buf, 0xff, sizeof(struct statfs));
- buf->f_blocks = 0; /* Darn GNU df... */
+ memset(buf, 0, sizeof(struct statfs));
return sb->s_op->statfs(sb, buf);
}
@@ -814,6 +813,7 @@ extern int get_unused_fd(void);
extern void put_unused_fd(unsigned int);
extern struct file *filp_open(const char *, int, int, struct dentry *);
+extern struct file *dentry_open(struct dentry *, int);
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char *);
@@ -938,6 +938,9 @@ static inline struct dentry * open_namei(const char *pathname)
return __open_namei(pathname, 0, 0, NULL);
}
+extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
+extern struct file * open_exec(const char *);
+
/* fs/dcache.c -- generic fs support functions */
extern int is_subdir(struct dentry *, struct dentry *);
extern ino_t find_inode_number(struct dentry *, struct qstr *);
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index 94030b18d..70635b491 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -193,8 +193,20 @@ struct hd_geometry {
#define HDIO_SET_NICE 0x0329 /* set nice flags */
#define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */
-#define __NEW_HD_DRIVE_ID
+/* BIG GEOMETRY */
+struct hd_big_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned int cylinders;
+ unsigned long start;
+};
+
+/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
+#define HDIO_GETGEO_BIG 0x0330 /* */
+#define HDIO_GETGEO_BIG_RAW 0x0331 /* */
+
+#define __NEW_HD_DRIVE_ID
/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
struct hd_driveid {
unsigned short config; /* lots of obsolete bit flags */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 248c37b39..ae597c151 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -326,6 +326,7 @@ typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin,
ide_dma_end, ide_dma_check, ide_dma_on,
ide_dma_off, ide_dma_off_quietly, ide_dma_test_irq,
ide_dma_bad_drive, ide_dma_good_drive,
+ ide_dma_verbose, ide_dma_retune,
ide_dma_lostirq, ide_dma_timeout
} ide_dma_action_t;
@@ -857,6 +858,7 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
void ide_destroy_dmatable (ide_drive_t *drive);
ide_startstop_t ide_dma_intr (ide_drive_t *drive);
int check_drive_lists (ide_drive_t *drive, int good_bad);
+int report_drive_dmaing (ide_drive_t *drive);
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
int ide_release_dma (ide_hwif_t *hwif);
void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
diff --git a/include/linux/input.h b/include/linux/input.h
index d5b75700a..4cc82fbf4 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -302,9 +302,10 @@ struct input_event {
#define BTN_TOOL_AIRBRUSH 0x144
#define BTN_TOOL_FINGER 0x145
#define BTN_TOOL_MOUSE 0x146
-#define BTN_TOUCH 0x147
-#define BTN_STYLUS 0x148
-#define BTN_STYLUS2 0x149
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
#define KEY_MAX 0x1ff
diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h
index 7a52a7c4d..0985c29fb 100644
--- a/include/linux/isapnp.h
+++ b/include/linux/isapnp.h
@@ -128,6 +128,24 @@ struct isapnp_resources {
struct isapnp_resources *next; /* next resource */
};
+#define ISAPNP_ANY_ID 0xffff
+#define ISAPNP_CARD_DEVS 8
+
+#define ISAPNP_CARD_ID(_va, _vb, _vc, _device) \
+ vendor: ISAPNP_VENDOR(_va, _vb, _vc), device: ISAPNP_DEVICE(_device)
+#define ISAPNP_CARD_END \
+ vendor: 0, device: 0
+#define ISAPNP_DEVICE_ID(_va, _vb, _vc, _function) \
+ { vendor: ISAPNP_VENDOR(_va, _vb, _vc), function: ISAPNP_FUNCTION(_function) }
+
+struct isapnp_card_id {
+ unsigned short vendor, device;
+ struct {
+ unsigned short vendor, function;
+ } devs[ISAPNP_CARD_DEVS]; /* logical devices */
+ unsigned long driver_data; /* data private to the driver */
+};
+
#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
#define __ISAPNP__
@@ -158,6 +176,9 @@ struct pci_dev *isapnp_find_dev(struct pci_bus *card,
unsigned short vendor,
unsigned short function,
struct pci_dev *from);
+int isapnp_probe_cards(const struct isapnp_card_id *ids,
+ int (*probe)(struct pci_bus *card,
+ const struct isapnp_card_id *id));
/* misc */
void isapnp_resource_change(struct resource *resource,
unsigned long start,
@@ -196,7 +217,10 @@ extern inline struct pci_bus *isapnp_find_card(unsigned short vendor,
extern inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
unsigned short vendor,
unsigned short function,
- struct pci_dev *from) { return NULL; }
+ struct pci_dev *from) { return NULL; }
+extern inline int isapnp_probe_cards(const struct isapnp_card_id *ids,
+ int (*probe)(struct pci_bus *card,
+ const struct isapnp_card_id *id)) { return -ENODEV; }
extern inline void isapnp_resource_change(struct resource *resource,
unsigned long start,
unsigned long size) { ; }
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index f34122fc3..c916a8fa0 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.94 2000/02/26 00:29:40 keil Exp $
+/* $Id: isdn.h,v 1.101 2000/03/20 22:37:47 detabc Exp $
*
* Main header for the Linux ISDN subsystem (linklevel).
*
@@ -21,6 +21,35 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn.h,v $
+ * Revision 1.101 2000/03/20 22:37:47 detabc
+ * modify abc-extension to work together with the new LL.
+ * remove abc frame-counter (is obsolete now).
+ * use the new lp->super_tx_queue for internal queueing (bsd-rawip-compress).
+ * modify isdn_net_xmit() and isdn_net_write_super().
+ * -- Kai, please have a look to this two function's. Thank's.
+ *
+ * Revision 1.100 2000/03/19 15:27:53 kai
+ * no known bugs left...
+ *
+ * Revision 1.99 2000/03/18 16:20:26 kai
+ * cosmetics / renaming
+ *
+ * Revision 1.98 2000/03/17 18:20:47 kai
+ * moved to frame_cnt based flow control
+ * some races still need to be fixed
+ *
+ * Revision 1.97 2000/03/17 16:22:55 kai
+ * we keep track of outstanding packets (given to HL, but not confirmed yet)
+ * now, but we don't use it for flow control yet.
+ *
+ * Revision 1.96 2000/03/17 12:49:42 kai
+ * calling statcallb with ISDN_STAT_BSENT in hard-IRQ context is now
+ * officially allowed. writebuf_skb() will never be called in hard-IRQ context
+ * anymore.
+ *
+ * Revision 1.95 2000/03/04 16:20:42 detabc
+ * copy frames before rewriting frame's saddr
+ *
* Revision 1.94 2000/02/26 00:29:40 keil
* more softnet changes
*
@@ -395,7 +424,6 @@
#undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
#undef CONFIG_ISDN_WITH_ABC_CONN_ERROR
#undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
-#undef CONFIG_ISDN_WITH_ABC_FRAME_LIMIT
#undef CONFIG_ISDN_WITH_ABC_IPV4_RW_SOCKADDR
#undef CONFIG_ISDN_WITH_ABC_IPV4_RWUDP_SOCKADDR
@@ -701,7 +729,6 @@ typedef struct isdn_net_local_s {
ulong sqfull_stamp; /* Start-Time of overload */
ulong slavedelay; /* Dynamic bundling delaytime */
int triggercps; /* BogoCPS needed for trigger slave */
- struct net_device *srobin; /* Ptr to Master device for slaves */
isdn_net_phone *phone[2]; /* List of remote-phonenumbers */
/* phone[0] = Incoming Numbers */
/* phone[1] = Outgoing Numbers */
@@ -711,9 +738,15 @@ typedef struct isdn_net_local_s {
struct isdn_net_local_s *next; /* Ptr to next link in bundle */
struct isdn_net_local_s *last; /* Ptr to last link in bundle */
struct isdn_net_dev_s *netdev; /* Ptr to netdev */
- struct sk_buff *first_skb; /* Ptr to skb that triggers dialing */
- struct sk_buff *volatile sav_skb; /* Ptr to skb, rejected by LL-driver*/
+ struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
+ /* be transmitted asap */
+ atomic_t frame_cnt; /* number of frames currently */
+ /* queued in HL driver */
/* Ptr to orig. hard_header_cache */
+ spinlock_t xmit_lock; /* used to protect the xmit path of */
+ /* a particular channel (including */
+ /* the frame_cnt */
+
int (*org_hhc)(
struct neighbour *neigh,
struct hh_cache *hh);
@@ -733,13 +766,17 @@ typedef struct isdn_net_local_s {
int cisco_loop; /* Loop counter for Cisco-SLARP */
ulong cisco_myseq; /* Local keepalive seq. for Cisco */
ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */
+ struct tq_struct tqueue;
} isdn_net_local;
/* the interface itself */
typedef struct isdn_net_dev_s {
isdn_net_local *local;
- isdn_net_local *queue;
- void *next; /* Pointer to next isdn-interface */
+ isdn_net_local *queue; /* circular list of all bundled
+ channels, which are currently
+ online */
+ spinlock_t queue_lock; /* lock to protect queue */
+ void *next; /* Pointer to next isdn-interface */
struct net_device dev; /* interface to upper levels */
#ifdef CONFIG_ISDN_PPP
struct mpqueue *mp_last;
diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h
index 6ba3086ab..5536bd43a 100644
--- a/include/linux/isdn_ppp.h
+++ b/include/linux/isdn_ppp.h
@@ -29,9 +29,6 @@ struct pppcallinfo
#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
#define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] )
-#define PPP_MP 0x003d
-#define PPP_LINK_COMP 0x00fb
-#define PPP_LINK_CCP 0x80fb
#define SC_MP_PROT 0x00000200
#define SC_REJ_MP_PROT 0x00000400
diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h
index b10f304a5..250191081 100644
--- a/include/linux/kernelcapi.h
+++ b/include/linux/kernelcapi.h
@@ -1,11 +1,22 @@
/*
- * $Id: kernelcapi.h,v 1.5 2000/01/28 16:45:40 calle Exp $
+ * $Id: kernelcapi.h,v 1.6 2000/03/03 15:50:42 calle Exp $
*
* Kernel CAPI 2.0 Interface for Linux
*
* (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: kernelcapi.h,v $
+ * Revision 1.6 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.5 2000/01/28 16:45:40 calle
* new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
* will search named driver and call the add_card function if one exist.
@@ -94,8 +105,8 @@ struct capi_interface {
__u16 (*capi_put_message) (__u16 applid, struct sk_buff * msg);
__u16 (*capi_get_message) (__u16 applid, struct sk_buff ** msgp);
__u16 (*capi_set_signal) (__u16 applid,
- void (*signal) (__u16 applid, __u32 param),
- __u32 param);
+ void (*signal) (__u16 applid, void *param),
+ void *param);
__u16 (*capi_get_manufacturer) (__u32 contr, __u8 buf[CAPI_MANUFACTURER_LEN]);
__u16 (*capi_get_version) (__u32 contr, struct capi_version * verp);
__u16(*capi_get_serial) (__u32 contr, __u8 serial[CAPI_SERIAL_LEN]);
@@ -108,8 +119,15 @@ struct capi_interface {
};
-#define KCI_CONTRUP 0
-#define KCI_CONTRDOWN 1
+struct capi_ncciinfo {
+ __u16 applid;
+ __u32 ncci;
+};
+
+#define KCI_CONTRUP 0 /* struct capi_profile */
+#define KCI_CONTRDOWN 1 /* NULL */
+#define KCI_NCCIUP 2 /* struct capi_ncciinfo */
+#define KCI_NCCIDOWN 3 /* struct capi_ncciinfo */
struct capi_interface_user {
char name[20];
@@ -148,6 +166,7 @@ int detach_capi_interface(struct capi_interface_user *);
#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a
#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b
+
#endif /* __KERNEL__ */
#endif /* __KERNELCAPI_H__ */
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index c2619da50..aaf6edf02 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_LINKAGE_H
#define _LINUX_LINKAGE_H
+#include <linux/config.h>
+
#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
@@ -35,13 +37,13 @@
#define __ALIGN .balign 4
#define __ALIGN_STR ".balign 4"
#else
-#if !defined(__i486__) && !defined(__i586__)
-#define __ALIGN .align 4,0x90
-#define __ALIGN_STR ".align 4,0x90"
-#else /* __i486__/__i586__ */
+#if defined(__i386__) && defined(CONFIG_X86_ALIGNMENT_16)
#define __ALIGN .align 16,0x90
#define __ALIGN_STR ".align 16,0x90"
-#endif /* __i486__/__i586__ */
+#else
+#define __ALIGN .align 4,0x90
+#define __ALIGN_STR ".align 4,0x90"
+#endif
#endif /* __sh__ */
#endif /* __mc68000__ */
#endif /* __arm__ */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 13d09502b..bb19b0807 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -42,6 +42,9 @@
#define NET_XMIT_DROP 1 /* skb dropped */
#define NET_XMIT_CN 2 /* congestion notification */
#define NET_XMIT_POLICED 3 /* skb is shot by police */
+#define NET_XMIT_BYPASS 4 /* packet does not leave via dequeue;
+ (TC use only - dev_queue_xmit
+ returns this as NET_XMIT_SUCCESS) */
#define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0)
diff --git a/include/linux/nfs.h b/include/linux/nfs.h
index e476cdbf9..3dca58cbc 100644
--- a/include/linux/nfs.h
+++ b/include/linux/nfs.h
@@ -160,11 +160,35 @@ struct nfs_fsinfo {
__u32 bavail;
};
+/* Arguments to the write call.
+ * Note that NFS_WRITE_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
+ */
+#define NFS_WRITE_MAXIOV 8
+
+enum nfs3_stable_how {
+ NFS_UNSTABLE = 0,
+ NFS_DATA_SYNC = 1,
+ NFS_FILE_SYNC = 2
+};
+
struct nfs_writeargs {
struct nfs_fh * fh;
__u32 offset;
__u32 count;
- const void * buffer;
+ enum nfs3_stable_how stable;
+ unsigned int nriov;
+ struct iovec iov[NFS_WRITE_MAXIOV];
+};
+
+struct nfs_writeverf {
+ enum nfs3_stable_how committed;
+ __u32 verifier[2];
+};
+
+struct nfs_writeres {
+ struct nfs_fattr * fattr;
+ struct nfs_writeverf * verf;
+ __u32 count;
};
#ifdef NFS_NEED_XDR_TYPES
diff --git a/include/linux/nfs_flushd.h b/include/linux/nfs_flushd.h
new file mode 100644
index 000000000..015a3c032
--- /dev/null
+++ b/include/linux/nfs_flushd.h
@@ -0,0 +1,64 @@
+#ifndef NFS_CLUSTER_H
+#define NFS_CLUSTER_H
+
+
+
+#ifdef __KERNEL__
+#include <linux/nfs_fs_sb.h>
+
+/*
+ * Counters of total number and pending number of requests.
+ * When the total number of requests exceeds the soft limit, we start
+ * flushing out requests. If it exceeds the hard limit, we stall until
+ * it drops again.
+ */
+#define MAX_REQUEST_SOFT 192
+#define MAX_REQUEST_HARD 256
+
+/*
+ * Maximum number of requests per write cluster.
+ * 32 requests per cluster account for 128K of data on an intel box.
+ * Note: it's a good idea to make this number smaller than MAX_REQUEST_SOFT.
+ *
+ * For 100Mbps Ethernet, 128 pages (i.e. 256K) per cluster gives much
+ * better performance.
+ */
+#define REQUEST_HASH_SIZE 16
+#define REQUEST_NR(off) ((off) >> PAGE_CACHE_SHIFT)
+#define REQUEST_HASH(ino, off) (((ino) ^ REQUEST_NR(off)) & (REQUEST_HASH_SIZE - 1))
+
+
+/*
+ * Functions
+ */
+extern int nfs_reqlist_alloc(struct nfs_server *);
+extern void nfs_reqlist_free(struct nfs_server *);
+extern int nfs_reqlist_init(struct nfs_server *);
+extern void nfs_reqlist_exit(struct nfs_server *);
+extern void inode_schedule_scan(struct inode *, unsigned long);
+extern void inode_remove_flushd(struct inode *);
+extern void nfs_wake_flushd(void);
+
+/*
+ * This is the per-mount writeback cache.
+ */
+struct nfs_reqlist {
+ unsigned int nr_requests;
+ unsigned long runat;
+ wait_queue_head_t request_wait;
+
+ /* The async RPC task that is responsible for scanning the
+ * requests.
+ */
+ struct rpc_task *task; /* request flush task */
+
+ /* Authentication flavor handle for this NFS client */
+ struct rpc_auth *auth;
+
+ /* The list of all inodes with pending writebacks. */
+ struct inode *inodes;
+};
+
+#endif
+
+#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 3b1ae1764..19f1740f1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -9,8 +9,10 @@
#ifndef _LINUX_NFS_FS_H
#define _LINUX_NFS_FS_H
+#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
+#include <linux/pagemap.h>
#include <linux/in.h>
#include <linux/sunrpc/sched.h>
@@ -34,13 +36,16 @@
*/
#define NFS_MAX_DIRCACHE 16
-#define NFS_MAX_FILE_IO_BUFFER_SIZE 16384
+#define NFS_MAX_FILE_IO_BUFFER_SIZE 32768
#define NFS_DEF_FILE_IO_BUFFER_SIZE 4096
/*
* The upper limit on timeouts for the exponential backoff algorithm.
*/
#define NFS_MAX_RPC_TIMEOUT (6*HZ)
+#define NFS_WRITEBACK_DELAY (5*HZ)
+#define NFS_WRITEBACK_LOCKDELAY (60*HZ)
+#define NFS_COMMIT_DELAY (5*HZ)
/*
* Size of the lookup cache in units of number of entries cached.
@@ -58,11 +63,13 @@
#define NFS_DSERVER(dentry) (&(dentry)->d_sb->u.nfs_sb.s_server)
#define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server)
#define NFS_CLIENT(inode) (NFS_SERVER(inode)->client)
+#define NFS_REQUESTLIST(inode) (NFS_SERVER(inode)->rw_requests)
#define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode)))
#define NFS_CONGESTED(inode) (RPC_CONGESTED(NFS_CLIENT(inode)))
#define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies)
#define NFS_OLDMTIME(inode) ((inode)->u.nfs_i.read_cache_mtime)
+#define NFS_NEXTSCAN(inode) ((inode)->u.nfs_i.nextscan)
#define NFS_CACHEINV(inode) \
do { \
NFS_READTIME(inode) = jiffies - 1000000; \
@@ -78,7 +85,6 @@ do { \
#define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
-#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)
@@ -93,46 +99,31 @@ do { \
/* Flags in the RPC client structure */
#define NFS_CLNTF_BUFSIZE 0x0001 /* readdir buffer in longwords */
-#ifdef __KERNEL__
+#define NFS_RW_SYNC 0x0001 /* O_SYNC handling */
+#define NFS_RW_SWAP 0x0002 /* This is a swap request */
/*
- * This struct describes a file region to be written.
- * It's kind of a pity we have to keep all these lists ourselves, rather
- * than sticking an extra pointer into struct page.
+ * When flushing a cluster of dirty pages, there can be different
+ * strategies:
*/
-struct nfs_wreq {
- struct rpc_listitem wb_list; /* linked list of req's */
- struct rpc_task wb_task; /* RPC task */
- struct file * wb_file; /* dentry referenced */
- struct page * wb_page; /* page to be written */
- wait_queue_head_t wb_wait; /* wait for completion */
- unsigned int wb_offset; /* offset within page */
- unsigned int wb_bytes; /* dirty range */
- unsigned int wb_count; /* user count */
- int wb_status;
- pid_t wb_pid; /* owner process */
- unsigned short wb_flags; /* status flags */
-
- struct nfs_writeargs wb_args; /* NFS RPC stuff */
- struct nfs_fattr wb_fattr; /* file attributes */
-};
-
-#define WB_NEXT(req) ((struct nfs_wreq *) ((req)->wb_list.next))
+#define FLUSH_AGING 0 /* only flush old buffers */
+#define FLUSH_SYNC 1 /* file being synced, or contention */
+#define FLUSH_WAIT 2 /* wait for completion */
+#define FLUSH_STABLE 4 /* commit to stable storage */
-/*
- * Various flags for wb_flags
- */
-#define NFS_WRITE_CANCELLED 0x0004 /* has been cancelled */
-#define NFS_WRITE_UNCOMMITTED 0x0008 /* written but uncommitted (NFSv3) */
-#define NFS_WRITE_INVALIDATE 0x0010 /* invalidate after write */
-#define NFS_WRITE_INPROGRESS 0x0100 /* RPC call in progress */
-#define NFS_WRITE_COMPLETE 0x0200 /* RPC call completed */
-
-#define WB_CANCELLED(req) ((req)->wb_flags & NFS_WRITE_CANCELLED)
-#define WB_UNCOMMITTED(req) ((req)->wb_flags & NFS_WRITE_UNCOMMITTED)
-#define WB_INVALIDATE(req) ((req)->wb_flags & NFS_WRITE_INVALIDATE)
-#define WB_INPROGRESS(req) ((req)->wb_flags & NFS_WRITE_INPROGRESS)
-#define WB_COMPLETE(req) ((req)->wb_flags & NFS_WRITE_COMPLETE)
+static inline
+loff_t page_offset(struct page *page)
+{
+ return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
+}
+
+static inline
+unsigned long page_index(struct page *page)
+{
+ return page->index;
+}
+
+#ifdef __KERNEL__
/*
* linux/fs/nfs/proc.c
@@ -218,21 +209,54 @@ extern int nfs_lock(struct file *, int, struct file_lock *);
*/
extern int nfs_writepage(struct dentry *, struct page *);
extern int nfs_check_failed_request(struct inode *);
-
+extern struct nfs_page* nfs_find_request(struct inode *, struct page *);
+extern void nfs_release_request(struct nfs_page *req);
+extern int nfs_flush_incompatible(struct file *file, struct page *page);
+extern int nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int);
/*
* Try to write back everything synchronously (but check the
* return value!)
*/
-extern int nfs_wb_all(struct inode *);
-extern int nfs_wb_page(struct inode *, struct page *);
-extern int nfs_wb_file(struct inode *, struct file *);
+extern int nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int nfs_flush_timeout(struct inode *, int);
+#ifdef CONFIG_NFS_V3
+extern int nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int nfs_commit_timeout(struct inode *, int);
+#endif
+
+static inline int
+nfs_have_writebacks(struct inode *inode)
+{
+ return !list_empty(&inode->u.nfs_i.writeback);
+}
+
+static inline int
+nfs_wb_all(struct inode *inode)
+{
+ int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT);
+ return (error < 0) ? error : 0;
+}
+
+/*
+ * Write back all requests on one page - we do this before reading it.
+ */
+static inline int
+nfs_wb_page(struct inode *inode, struct page* page)
+{
+ int error = nfs_sync_file(inode, 0, page_offset(page), PAGE_CACHE_SIZE, FLUSH_WAIT | FLUSH_STABLE);
+ return (error < 0) ? error : 0;
+}
/*
- * Invalidate write-backs, possibly trying to write them
- * back first..
+ * Write back all pending writes for one user..
*/
-extern void nfs_inval(struct inode *);
-extern int nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int);
+static inline int
+nfs_wb_file(struct inode *inode, struct file *file)
+{
+ int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
+ return (error < 0) ? error : 0;
+}
/*
* linux/fs/nfs/read.c
@@ -261,6 +285,19 @@ nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
extern int nfs_root_mount(struct super_block *sb);
+#define nfs_wait_event(clnt, wq, condition) \
+({ \
+ int __retval = 0; \
+ if (clnt->cl_intr) { \
+ sigset_t oldmask; \
+ rpc_clnt_sigmask(clnt, &oldmask); \
+ __retval = wait_event_interruptible(wq, condition); \
+ rpc_clnt_sigunmask(clnt, &oldmask); \
+ } else \
+ wait_event(wq, condition); \
+ __retval; \
+})
+
#endif /* __KERNEL__ */
/*
diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h
index 22681be9d..d4a80639b 100644
--- a/include/linux/nfs_fs_i.h
+++ b/include/linux/nfs_fs_i.h
@@ -42,10 +42,19 @@ struct nfs_inode_info {
/*
* This is the list of dirty unwritten pages.
- * NFSv3 will want to add a list for written but uncommitted
- * pages.
*/
- struct nfs_wreq * writeback;
+ struct list_head dirty;
+ struct list_head commit;
+ struct list_head writeback;
+
+ unsigned int ndirty,
+ ncommit,
+ npages;
+
+ /* Flush daemon info */
+ struct inode *hash_next,
+ *hash_prev;
+ unsigned long nextscan;
/* Readdir caching information. */
void *cookies;
@@ -55,8 +64,9 @@ struct nfs_inode_info {
/*
* Legal inode flag values
*/
-#define NFS_INO_REVALIDATING 0x0001 /* revalidating attrs */
+#define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */
#define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */
+#define NFS_INO_FLUSH 0x0020 /* inode is due for flushing */
/*
* NFS lock info
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 343455ec9..418faaa33 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -18,6 +18,7 @@ struct nfs_server {
unsigned int acdirmin;
unsigned int acdirmax;
char * hostname; /* remote hostname */
+ struct nfs_reqlist * rw_requests; /* async read/write requests */
};
/*
diff --git a/include/linux/nfsd/stats.h b/include/linux/nfsd/stats.h
index 4169a1e21..3523a6daa 100644
--- a/include/linux/nfsd/stats.h
+++ b/include/linux/nfsd/stats.h
@@ -16,8 +16,17 @@ struct nfsd_stats {
unsigned int fh_stale; /* FH stale error */
unsigned int fh_lookup; /* dentry cached */
unsigned int fh_anon; /* anon file dentry returned */
- unsigned int fh_nocache_dir; /* filehandle not foudn in dcache */
- unsigned int fh_nocache_nondir; /* filehandle not foudn in dcache */
+ unsigned int fh_nocache_dir; /* filehandle not found in dcache */
+ unsigned int fh_nocache_nondir; /* filehandle not found in dcache */
+ unsigned int io_read; /* bytes returned to read requests */
+ unsigned int io_write; /* bytes passed in write requests */
+ unsigned int th_cnt; /* number of available threads */
+ unsigned int th_usage[10]; /* number of ticks during which n perdeciles
+ * of available threads were in use */
+ unsigned int th_fullcnt; /* number of times last free thread was used */
+ unsigned int ra_size; /* size of ra cache */
+ unsigned int ra_depth[11]; /* number of times ra entry was found that deep
+ * in the cache (10percentiles). [10] = not found */
};
#ifdef __KERNEL__
diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h
index af723ced8..4f20ad01f 100644
--- a/include/linux/nfsd/syscall.h
+++ b/include/linux/nfsd/syscall.h
@@ -111,10 +111,7 @@ struct nfsctl_arg {
struct nfsctl_uidmap u_umap;
struct nfsctl_fhparm u_getfh;
struct nfsctl_fdparm u_getfd;
-#ifdef notyet
struct nfsctl_fsparm u_getfs;
-#endif
- unsigned int u_debug;
} u;
#define ca_svc u.u_svc
#define ca_client u.u_client
@@ -124,15 +121,11 @@ struct nfsctl_arg {
#define ca_getfd u.u_getfd
#define ca_getfs u.u_getfs
#define ca_authd u.u_authd
-#define ca_debug u.u_debug
};
union nfsctl_res {
__u8 cr_getfh[NFS_FHSIZE];
-#ifdef notyet
struct knfsd_fh cr_getfs;
-#endif
- unsigned int cr_debug;
};
#ifdef __KERNEL__
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 472c9d87e..55423de5c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -551,6 +551,8 @@ const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, co
#ifndef CONFIG_PCI
extern inline int pcibios_present(void) { return 0; }
+extern inline int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn)
+{ return PCIBIOS_DEVICE_NOT_FOUND; }
#define _PCI_NOP(o,s,t) \
extern inline int pcibios_##o##_config_##s## (u8 bus, u8 dfn, u8 where, t val) \
@@ -583,6 +585,7 @@ extern inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUS
extern inline int pci_register_driver(struct pci_driver *drv) { return 0;}
extern inline void pci_unregister_driver(struct pci_driver *drv) { }
extern inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; }
+extern inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
#else
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d9909e0cc..2b37bcf20 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1053,6 +1053,12 @@
#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x950A
#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
+#define PCI_VENDOR_ID_TITAN 0x14D2
+#define PCI_DEVICE_ID_TITAN_100 0xA001
+#define PCI_DEVICE_ID_TITAN_200 0xA005
+#define PCI_DEVICE_ID_TITAN_400 0xA003
+#define PCI_DEVICE_ID_TITAN_800B 0xA004
+
#define PCI_VENDOR_ID_PANACOM 0x14d4
#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 25210f8e5..dfcba46fe 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -9,6 +9,8 @@ struct pipe_inode_info {
unsigned int writers;
unsigned int waiting_readers;
unsigned int waiting_writers;
+ unsigned int r_counter;
+ unsigned int w_counter;
};
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
@@ -24,6 +26,8 @@ struct pipe_inode_info {
#define PIPE_WRITERS(inode) ((inode).i_pipe->writers)
#define PIPE_WAITING_READERS(inode) ((inode).i_pipe->waiting_readers)
#define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers)
+#define PIPE_RCOUNTER(inode) ((inode).i_pipe->r_counter)
+#define PIPE_WCOUNTER(inode) ((inode).i_pipe->w_counter)
#define PIPE_EMPTY(inode) (PIPE_LEN(inode) == 0)
#define PIPE_FULL(inode) (PIPE_LEN(inode) == PIPE_SIZE)
@@ -32,4 +36,9 @@ struct pipe_inode_info {
#define PIPE_MAX_RCHUNK(inode) (PIPE_SIZE - PIPE_START(inode))
#define PIPE_MAX_WCHUNK(inode) (PIPE_SIZE - PIPE_END(inode))
+/* Drop the inode semaphore and wait for a pipe event, atomically */
+void pipe_wait(struct inode * inode);
+
+struct inode* pipe_new(struct inode* inode);
+
#endif
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 48db96051..39d2de6e1 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -10,6 +10,8 @@
#ifndef _LINUX_SERIAL_H
#define _LINUX_SERIAL_H
+#include <asm/page.h>
+
/*
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
*/
@@ -23,12 +25,12 @@ struct async_icount {
/*
* The size of the serial xmit buffer is 1 page, or 4096 bytes
*/
-#define SERIAL_XMIT_SIZE 4096
+#define SERIAL_XMIT_SIZE PAGE_SIZE
struct serial_struct {
int type;
int line;
- int port;
+ unsigned long port;
int irq;
int flags;
int xmit_fifo_size;
diff --git a/include/linux/serialP.h b/include/linux/serialP.h
index 6bb99d32f..8329b4580 100644
--- a/include/linux/serialP.h
+++ b/include/linux/serialP.h
@@ -22,6 +22,7 @@
#include <linux/config.h>
#include <linux/termios.h>
#include <linux/tqueue.h>
+#include <linux/circ_buf.h>
#include <linux/wait.h>
struct serial_state {
@@ -42,7 +43,7 @@ struct serial_state {
unsigned short close_delay;
unsigned short closing_wait; /* time to wait before closing */
struct async_icount icount;
- struct termios normal_termios;
+ struct termios normal_termios;
struct termios callout_termios;
int io_type;
struct async_struct *info;
@@ -74,10 +75,8 @@ struct async_struct {
int blocked_open; /* # of blocked opens */
long session; /* Session of opening process */
long pgrp; /* pgrp of opening process */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
+ struct circ_buf xmit;
+ spinlock_t xmit_lock;
u8 *iomem_base;
u16 iomem_reg_shift;
int io_type;
@@ -101,11 +100,6 @@ struct async_struct {
#define SSTATE_MAGIC 0x5302
/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
* Events are used to schedule things to happen at timer-interrupt
* time, instead of at rs interrupt time.
*/
@@ -180,19 +174,22 @@ struct pci_board_inst {
#define SPCI_FL_IRQBASE3 (0x0003 << 4)
#define SPCI_FL_IRQBASE4 (0x0004 << 4)
#define SPCI_FL_GET_IRQBASE(x) ((x & SPCI_FL_IRQ_MASK) >> 4)
-
+
/* Use sucessiveentries base resource table */
#define SPCI_FL_BASE_TABLE 0x0100
-
+
/* Use successive entries in the irq resource table */
#define SPCI_FL_IRQ_TABLE 0x0200
-
+
/* Use the irq resource table instead of dev->irq */
#define SPCI_FL_IRQRESOURCE 0x0400
/* Use the Base address register size to cap number of ports */
#define SPCI_FL_REGION_SZ_CAP 0x0800
-
+
+/* Do not use irq sharing for this device */
+#define SPCI_FL_NO_SHIRQ 0x1000
+
#define SPCI_FL_PNPDEFAULT (SPCI_FL_IRQRESOURCE)
-
+
#endif /* _LINUX_SERIAL_H */
diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h
index 4583e2f5a..320c69612 100644
--- a/include/linux/smp_lock.h
+++ b/include/linux/smp_lock.h
@@ -7,6 +7,7 @@
#define unlock_kernel() do { } while(0)
#define release_kernel_lock(task, cpu) do { } while(0)
#define reacquire_kernel_lock(task) do { } while(0)
+#define kernel_locked() 1
#else
diff --git a/include/linux/sonet.h b/include/linux/sonet.h
index c2307389c..30c45ec59 100644
--- a/include/linux/sonet.h
+++ b/include/linux/sonet.h
@@ -1,23 +1,29 @@
/* sonet.h - SONET/SHD physical layer control */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_SONET_H
#define LINUX_SONET_H
+#define __SONET_ITEMS \
+ __HANDLE_ITEM(section_bip); /* section parity errors (B1) */ \
+ __HANDLE_ITEM(line_bip); /* line parity errors (B2) */ \
+ __HANDLE_ITEM(path_bip); /* path parity errors (B3) */ \
+ __HANDLE_ITEM(line_febe); /* line parity errors at remote */ \
+ __HANDLE_ITEM(path_febe); /* path parity errors at remote */ \
+ __HANDLE_ITEM(corr_hcs); /* correctable header errors */ \
+ __HANDLE_ITEM(uncorr_hcs); /* uncorrectable header errors */ \
+ __HANDLE_ITEM(tx_cells); /* cells sent */ \
+ __HANDLE_ITEM(rx_cells); /* cells received */
+
struct sonet_stats {
- int section_bip; /* section parity errors (B1) */
- int line_bip; /* line parity errors (B2) */
- int path_bip; /* path parity errors (B3) */
- int line_febe; /* line parity errors at remote */
- int path_febe; /* path parity errors at remote */
- int corr_hcs; /* correctable header errors */
- int uncorr_hcs; /* uncorrectable header errors */
- int tx_cells; /* cells sent */
- int rx_cells; /* cells received */
+#define __HANDLE_ITEM(i) int i
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
} __attribute__ ((packed));
+
#define SONET_GETSTAT _IOR('a',ATMIOC_PHYTYP,struct sonet_stats)
/* get statistics */
#define SONET_GETSTATZ _IOR('a',ATMIOC_PHYTYP+1,struct sonet_stats)
@@ -49,4 +55,23 @@ struct sonet_stats {
#define SONET_FRSENSE_SIZE 6 /* C1[3],H1[3] (0xff for unknown) */
+
+#ifndef __KERNEL__
+#undef __SONET_ITEMS
+#else
+
+#include <asm/atomic.h>
+
+struct k_sonet_stats {
+#define __HANDLE_ITEM(i) atomic_t i
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
+};
+
+extern void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to);
+extern void sonet_subtract_stats(struct k_sonet_stats *from,
+ struct sonet_stats *to);
+
+#endif
+
#endif
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index f374af3f4..d106c881a 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -64,10 +64,10 @@ struct rpc_authops {
struct rpc_auth * (*create)(struct rpc_clnt *);
void (*destroy)(struct rpc_auth *);
- struct rpc_cred * (*crcreate)(struct rpc_task *);
+ struct rpc_cred * (*crcreate)(int);
void (*crdestroy)(struct rpc_cred *);
- int (*crmatch)(struct rpc_task *, struct rpc_cred*);
+ int (*crmatch)(struct rpc_cred *, int);
u32 * (*crmarshal)(struct rpc_task *, u32 *, int);
int (*crrefresh)(struct rpc_task *);
u32 * (*crvalidate)(struct rpc_task *, u32 *);
@@ -83,10 +83,14 @@ int rpcauth_register(struct rpc_authops *);
int rpcauth_unregister(struct rpc_authops *);
struct rpc_auth * rpcauth_create(unsigned int, struct rpc_clnt *);
void rpcauth_destroy(struct rpc_auth *);
-struct rpc_cred * rpcauth_lookupcred(struct rpc_task *);
+struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int);
+struct rpc_cred * rpcauth_bindcred(struct rpc_task *);
void rpcauth_holdcred(struct rpc_task *);
-void rpcauth_releasecred(struct rpc_task *);
-int rpcauth_matchcred(struct rpc_task *, struct rpc_cred *);
+void rpcauth_releasecred(struct rpc_auth *,
+ struct rpc_cred *);
+void rpcauth_unbindcred(struct rpc_task *);
+int rpcauth_matchcred(struct rpc_auth *,
+ struct rpc_cred *, int);
u32 * rpcauth_marshcred(struct rpc_task *, u32 *);
u32 * rpcauth_checkverf(struct rpc_task *, u32 *);
int rpcauth_refreshcred(struct rpc_task *);
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index d0be5f044..0d09eb48a 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -111,21 +111,23 @@ void rpc_release_client(struct rpc_clnt *);
void rpc_getport(struct rpc_task *, struct rpc_clnt *);
int rpc_register(u32, u32, int, unsigned short, int *);
-int rpc_call(struct rpc_clnt *clnt, u32 proc,
- void *argp, void *resp, int flags);
-int rpc_call_async(struct rpc_task *task, u32 proc,
- void *argp, void *resp, int flags);
-void rpc_call_setup(struct rpc_task *task, u32 proc,
- void *argp, void *resp, int flags);
-int rpc_do_call(struct rpc_clnt *clnt, u32 proc,
- void *argp, void *resp, int flags,
- rpc_action callback, void *clntdata);
+void rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
+
+int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg,
+ int flags, rpc_action callback, void *clntdata);
+int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
+ int flags);
void rpc_restart_call(struct rpc_task *);
void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
-#define rpc_call(clnt, proc, argp, resp, flags) \
- rpc_do_call(clnt, proc, argp, resp, flags, NULL, NULL)
+static __inline__
+int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
+{
+ struct rpc_message msg = { proc, argp, resp, NULL };
+ return rpc_call_sync(clnt, &msg, flags);
+}
+
extern __inline__ void
rpc_set_timeout(struct rpc_clnt *clnt, unsigned int retr, unsigned long incr)
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index d43dfaf0c..279636434 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -21,6 +21,16 @@
#undef CONFIG_RPC_FASTSCHED
/*
+ * This is the actual RPC procedure call info.
+ */
+struct rpc_message {
+ __u32 rpc_proc; /* Procedure number */
+ void * rpc_argp; /* Arguments */
+ void * rpc_resp; /* Result */
+ struct rpc_cred * rpc_cred; /* Credentials */
+};
+
+/*
* This is the RPC task struct
*/
struct rpc_task {
@@ -33,17 +43,14 @@ struct rpc_task {
struct rpc_task * tk_prev_task; /* global list of tasks */
struct rpc_clnt * tk_client; /* RPC client */
struct rpc_rqst * tk_rqstp; /* RPC request */
- struct rpc_cred * tk_cred; /* RPC credentials */
int tk_status; /* result of last operation */
struct rpc_wait_queue * tk_rpcwait; /* RPC wait queue we're on */
/*
* RPC call state
*/
- __u32 tk_proc; /* procedure number */
+ struct rpc_message tk_msg; /* RPC call info */
__u32 * tk_buffer; /* XDR buffer */
- void * tk_argp; /* argument storage */
- void * tk_resp; /* result storage */
__u8 tk_garb_retry,
tk_cred_retry,
tk_suid_retry;
@@ -67,6 +74,10 @@ struct rpc_task {
wait_queue_head_t tk_wait; /* sync: sleep on this q */
unsigned long tk_timeout; /* timeout for rpc_sleep() */
unsigned short tk_flags; /* misc flags */
+ unsigned short tk_lock; /* Task lock counter */
+ unsigned int tk_wakeup : 1,/* Task waiting to wake up */
+ tk_sleeping : 1,/* Task is truly asleep */
+ tk_active : 1;/* Task has been activated */
#ifdef RPC_DEBUG
unsigned short tk_pid; /* debugging aid */
#endif
@@ -100,6 +111,8 @@ typedef void (*rpc_action)(struct rpc_task *);
#define RPC_DO_CALLBACK(t) ((t)->tk_flags & RPC_TASK_CALLBACK)
#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
+#define RPC_IS_SLEEPING(t) ((t)->tk_sleeping)
+#define RPC_IS_ACTIVATED(t) ((t)->tk_active)
/*
* RPC synchronization objects
@@ -126,29 +139,28 @@ void rpc_init_task(struct rpc_task *, struct rpc_clnt *,
rpc_action exitfunc, int flags);
void rpc_release_task(struct rpc_task *);
void rpc_killall_tasks(struct rpc_clnt *);
-void rpc_execute(struct rpc_task *);
+int rpc_execute(struct rpc_task *);
void rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
rpc_action action);
int rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
void rpc_remove_wait_queue(struct rpc_task *);
void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
rpc_action action, rpc_action timer);
-void rpc_cond_wait(struct rpc_wait_queue *, struct rpc_task *,
- unsigned char *,
- rpc_action action, rpc_action timer);
+void rpc_sleep_locked(struct rpc_wait_queue *, struct rpc_task *,
+ rpc_action action, rpc_action timer);
+void rpc_add_timer(struct rpc_task *, rpc_action);
void rpc_wake_up_task(struct rpc_task *);
void rpc_wake_up(struct rpc_wait_queue *);
struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
void rpc_wake_up_status(struct rpc_wait_queue *, int);
-void rpc_add_timer(struct rpc_task *, rpc_action);
-void rpc_del_timer(struct rpc_task *);
+int rpc_lock_task(struct rpc_task *);
+void rpc_unlock_task(struct rpc_task *);
void rpc_delay(struct rpc_task *, unsigned long);
void * rpc_allocate(unsigned int flags, unsigned int);
void rpc_free(void *);
int rpciod_up(void);
void rpciod_down(void);
void rpciod_wake_up(void);
-void rpciod_tcp_dispatcher(void);
#ifdef RPC_DEBUG
void rpc_show_tasks(void);
#endif
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 5e01407fc..e5e66c1de 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -47,7 +47,7 @@
((xprt)->cong >= (xprt)->cwnd)
/* Default timeout values */
-#define RPC_MAX_UDP_TIMEOUT (6*HZ)
+#define RPC_MAX_UDP_TIMEOUT (60*HZ)
#define RPC_MAX_TCP_TIMEOUT (600*HZ)
/* RPC call and reply header size as number of 32bit words (verifier
@@ -96,8 +96,7 @@ struct rpc_rqst {
struct rpc_task * rq_task; /* RPC task data */
__u32 rq_xid; /* request XID */
struct rpc_rqst * rq_next; /* free list */
- unsigned char rq_gotit; /* reply received */
- unsigned char rq_damaged; /* being received */
+ unsigned char rq_damaged; /* reply being received */
/*
* For authentication (e.g. auth_des)
@@ -122,12 +121,6 @@ struct rpc_rqst {
#define rq_rlen rq_rcv_buf.io_len
struct rpc_xprt {
- struct rpc_xprt * link; /* list of all clients */
- struct rpc_xprt * rx_pending; /* receive pending list */
-
- int rx_pending_flag;/* are we on the rcv pending list ? */
-
- struct file * file; /* VFS layer */
struct socket * sock; /* BSD socket layer */
struct sock * inet; /* INET layer */
@@ -145,9 +138,9 @@ struct rpc_xprt {
struct rpc_wait_queue reconn; /* waiting for reconnect */
struct rpc_rqst * free; /* free slots */
struct rpc_rqst slot[RPC_MAXREQS];
- unsigned char connected; /* TCP: connected */
- unsigned char write_space; /* TCP: can send */
- unsigned int shutdown : 1, /* being shut down */
+ unsigned int connected : 1, /* TCP: connected */
+ write_space: 1, /* TCP: can send */
+ shutdown : 1, /* being shut down */
nocong : 1, /* no congestion control */
stream : 1, /* TCP */
tcp_more : 1, /* more record fragments */
@@ -156,16 +149,12 @@ struct rpc_xprt {
/*
* State of TCP reply receive stuff
*/
- union { /* record marker & XID */
- u32 header[2];
- u8 data[8];
- } tcp_recm;
- struct rpc_rqst * tcp_rqstp;
- struct iovec tcp_iovec[MAX_IOVEC];
- u32 tcp_total; /* overall record length */
- u32 tcp_reclen; /* fragment length */
- u32 tcp_offset; /* fragment offset */
- u32 tcp_copied; /* copied to request */
+ u32 tcp_recm; /* Fragment header */
+ u32 tcp_xid; /* Current XID */
+ unsigned int tcp_reclen, /* fragment length */
+ tcp_offset, /* fragment offset */
+ tcp_copied; /* copied to request */
+ struct list_head rx_pending; /* receive pending list */
/*
* Send stuff
@@ -179,17 +168,13 @@ struct rpc_xprt {
wait_queue_head_t cong_wait;
};
-#define tcp_reclen tcp_recm.header[0]
-#define tcp_xid tcp_recm.header[1]
#ifdef __KERNEL__
-struct rpc_xprt * xprt_create(struct file *socket,
- struct sockaddr_in *addr,
- struct rpc_timeout *toparms);
struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr,
struct rpc_timeout *toparms);
int xprt_destroy(struct rpc_xprt *);
+void xprt_shutdown(struct rpc_xprt *);
void xprt_default_timeout(struct rpc_timeout *, int);
void xprt_set_timeout(struct rpc_timeout *, unsigned int,
unsigned long);
@@ -201,8 +186,22 @@ int xprt_adjust_timeout(struct rpc_timeout *);
void xprt_release(struct rpc_task *);
void xprt_reconnect(struct rpc_task *);
int xprt_clear_backlog(struct rpc_xprt *);
-
-int xprt_tcp_pending(void);
+void __rpciod_tcp_dispatcher(void);
+
+extern struct list_head rpc_xprt_pending;
+
+static inline
+int xprt_tcp_pending(void)
+{
+ return !list_empty(&rpc_xprt_pending);
+}
+
+static inline
+void rpciod_tcp_dispatcher(void)
+{
+ if (xprt_tcp_pending())
+ __rpciod_tcp_dispatcher();
+}
#endif /* __KERNEL__*/
diff --git a/include/linux/udf_fs.h b/include/linux/udf_fs.h
index 4f842ac30..47980eaaf 100644
--- a/include/linux/udf_fs.h
+++ b/include/linux/udf_fs.h
@@ -60,6 +60,7 @@
/*
* Function prototypes (all other prototypes included in udfdecl.h)
*/
+extern int init_udf_fs(void);
#endif /* __KERNEL__ */
diff --git a/include/linux/udf_fs_sb.h b/include/linux/udf_fs_sb.h
index 15696cf33..99cd246e9 100644
--- a/include/linux/udf_fs_sb.h
+++ b/include/linux/udf_fs_sb.h
@@ -49,7 +49,16 @@ struct udf_virtual_data
struct udf_part_map
{
- __u32 s_uspace_bitmap;
+ union
+ {
+ __u32 bitmap;
+ struct inode *table;
+ } s_uspace;
+ union
+ {
+ __u32 bitmap;
+ struct inode *table;
+ } s_fspace;
__u32 s_partition_root;
__u32 s_partition_len;
__u16 s_partition_type;
@@ -61,6 +70,7 @@ struct udf_part_map
} s_type_specific;
__u32 (*s_partition_func)(struct super_block *, __u32, __u16, __u32);
__u16 s_volumeseqnum;
+ __u16 s_partition_flags;
};
#pragma pack()
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 8326fb791..c011f8238 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -604,6 +604,7 @@ extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq,
extern int usb_terminate_bulk(struct usb_device *, void *);
extern void usb_init_root_hub(struct usb_device *dev);
+extern int usb_root_hub_string(int id, int serial, char *type, __u8 *data, int len);
extern void usb_connect(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **);
diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h
index 5d71dc6ef..d6733d60b 100644
--- a/include/net/irda/irda_device.h
+++ b/include/net/irda/irda_device.h
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Apr 14 12:41:42 1998
- * Modified at: Fri Jan 14 10:46:56 2000
+ * Modified at: Mon Mar 20 09:08:57 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
@@ -73,18 +73,18 @@ typedef enum {
IRDA_TASK_CHILD_INIT, /* Initializing child task */
IRDA_TASK_CHILD_WAIT, /* Waiting for child task to finish */
IRDA_TASK_CHILD_DONE /* Child task is finished */
-} TASK_STATE;
+} IRDA_TASK_STATE;
struct irda_task;
-typedef int (*TASK_CALLBACK) (struct irda_task *task);
+typedef int (*IRDA_TASK_CALLBACK) (struct irda_task *task);
struct irda_task {
queue_t q;
magic_t magic;
- TASK_STATE state;
- TASK_CALLBACK function;
- TASK_CALLBACK finished;
+ IRDA_TASK_STATE state;
+ IRDA_TASK_CALLBACK function;
+ IRDA_TASK_CALLBACK finished;
struct irda_task *parent;
struct timer_list timer;
@@ -180,10 +180,11 @@ void setup_dma(int channel, char *buffer, int count, int mode);
void irda_task_delete(struct irda_task *task);
int irda_task_kick(struct irda_task *task);
-struct irda_task *irda_task_execute(void *instance, TASK_CALLBACK function,
- TASK_CALLBACK finished,
+struct irda_task *irda_task_execute(void *instance,
+ IRDA_TASK_CALLBACK function,
+ IRDA_TASK_CALLBACK finished,
struct irda_task *parent, void *param);
-void irda_task_next_state(struct irda_task *task, TASK_STATE state);
+void irda_task_next_state(struct irda_task *task, IRDA_TASK_STATE state);
extern const char *infrared_mode[];
diff --git a/include/net/irda/parameters.h b/include/net/irda/parameters.h
index 0bb658942..20f8a23c1 100644
--- a/include/net/irda/parameters.h
+++ b/include/net/irda/parameters.h
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Jun 7 08:47:28 1999
- * Modified at: Mon Dec 13 11:51:59 1999
+ * Modified at: Sun Jan 30 14:05:14 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1999-2000 Dag Brattli, 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
@@ -61,15 +61,15 @@ typedef union {
__u8 *bp;
__u16 *sp;
__u32 *ip;
-} pv_t;
+} irda_pv_t;
typedef struct {
__u8 pi;
__u8 pl;
- pv_t pv;
-} param_t;
+ irda_pv_t pv;
+} irda_param_t;
-typedef int (*PI_HANDLER)(void *self, param_t *param, int get);
+typedef int (*PI_HANDLER)(void *self, irda_param_t *param, int get);
typedef int (*PV_HANDLER)(void *self, __u8 *buf, int len, __u8 pi,
PV_TYPE type, PI_HANDLER func);
diff --git a/ipc/shm.c b/ipc/shm.c
index 196460c6f..232feedad 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1047,12 +1047,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
*/
if ((shmid % SEQ_MULTIPLIER) == zero_id)
return -EINVAL;
- lock_kernel();
down(&shm_ids.sem);
shp = shm_lock(shmid);
if (shp == NULL) {
up(&shm_ids.sem);
- unlock_kernel();
return -EINVAL;
}
err = -EIDRM;
@@ -1061,14 +1059,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
int id=shp->id;
shm_unlock(shmid);
up(&shm_ids.sem);
- /* The kernel lock prevents new attaches from
- * being happening. We can't hold shm_lock here
- * else we will deadlock in shm_lookup when we
+ /*
+ * We can't hold shm_lock here else we
+ * will deadlock in shm_lookup when we
* try to recursively grab it.
*/
- err = shm_remove_name(id);
- unlock_kernel();
- return err;
+ return shm_remove_name(id);
}
/* Do not find me any more */
shp->shm_perm.mode |= SHM_DEST;
@@ -1078,7 +1074,6 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
/* Unlock */
shm_unlock(shmid);
up(&shm_ids.sem);
- unlock_kernel();
return err;
}
@@ -1140,8 +1135,8 @@ static inline void shm_inc (int id) {
static int shm_mmap(struct file * file, struct vm_area_struct * vma)
{
- if (!(vma->vm_flags & VM_SHARED))
- return -EINVAL; /* we cannot do private mappings */
+ if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
+ return -EINVAL; /* we cannot do private writable mappings */
UPDATE_ATIME(file->f_dentry->d_inode);
vma->vm_ops = &shm_vm_ops;
shm_inc(file->f_dentry->d_inode->i_ino);
@@ -1156,15 +1151,16 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
unsigned long addr;
struct file * file;
int err;
- int flags;
+ unsigned long flags;
+ unsigned long prot;
+ unsigned long o_flags;
char name[SHM_FMT_LEN+1];
if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
return -EINVAL;
- if ((addr = (ulong)shmaddr))
- {
- if(addr & (SHMLBA-1)) {
+ if ((addr = (ulong)shmaddr)) {
+ if (addr & (SHMLBA-1)) {
if (shmflg & SHM_RND)
addr &= ~(SHMLBA-1); /* round down */
else
@@ -1174,14 +1170,22 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
} else
flags = MAP_SHARED;
- sprintf (name, SHM_FMT, shmid);
+ if (shmflg & SHM_RDONLY) {
+ prot = PROT_READ;
+ o_flags = O_RDONLY;
+ } else {
+ prot = PROT_READ | PROT_WRITE;
+ o_flags = O_RDWR;
+ }
+
+ sprintf (name, SHM_FMT, shmid);
+
lock_kernel();
- file = filp_open(name, O_RDWR, 0, dget(shm_sb->s_root));
+ file = filp_open(name, o_flags, 0, dget(shm_sb->s_root));
if (IS_ERR (file))
goto bad_file;
*raddr = do_mmap (file, addr, file->f_dentry->d_inode->i_size,
- (shmflg & SHM_RDONLY ? PROT_READ :
- PROT_READ | PROT_WRITE), flags, 0);
+ prot, flags, 0);
unlock_kernel();
if (IS_ERR(*raddr))
err = PTR_ERR(*raddr);
@@ -1204,14 +1208,18 @@ static void shm_open (struct vm_area_struct *shmd)
}
/*
- * Remove a name. Must be called with lock_kernel
+ * Remove a name.
*/
static int shm_remove_name(int id)
{
+ int err;
char name[SHM_FMT_LEN+1];
sprintf (name, SHM_FMT, id);
- return do_unlink (name, dget(shm_sb->s_root));
+ lock_kernel();
+ err = do_unlink (name, dget(shm_sb->s_root));
+ unlock_kernel();
+ return err;
}
/*
@@ -1225,8 +1233,6 @@ static void shm_close (struct vm_area_struct *shmd)
int id = shmd->vm_file->f_dentry->d_inode->i_ino;
struct shmid_kernel *shp;
- lock_kernel();
-
/* remove from the list of attaches of the shm segment */
if(!(shp = shm_lock(id)))
BUG();
@@ -1244,14 +1250,12 @@ static void shm_close (struct vm_area_struct *shmd)
* try to recursively grab it.
*/
err = shm_remove_name(pid);
- if(err && err != -ENOENT)
+ if(err && err != -EINVAL && err != -ENOENT)
printk(KERN_ERR "Unlink of SHM id %d failed (%d).\n", pid, err);
} else {
shm_unlock(id);
}
-
- unlock_kernel();
}
/*
diff --git a/kernel/Makefile b/kernel/Makefile
index bec392fca..2a4f548af 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -7,9 +7,6 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-.S.s:
- $(CPP) $(CPPFLAGS) -traditional $< -o $*.s
-
O_TARGET := kernel.o
O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
@@ -29,7 +26,7 @@ ifeq ($(CONFIG_MODULES),y)
OX_OBJS += ksyms.o
endif
-ifdef CONFIG_PM
+ifeq ($(CONFIG_PM),y)
OX_OBJS += pm.o
endif
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index a6748e70c..ad11eafea 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -207,6 +207,7 @@ EXPORT_SYMBOL(posix_unblock_lock);
EXPORT_SYMBOL(locks_mandatory_area);
EXPORT_SYMBOL(dput);
EXPORT_SYMBOL(is_root_busy);
+EXPORT_SYMBOL(have_submounts);
EXPORT_SYMBOL(prune_dcache);
EXPORT_SYMBOL(shrink_dcache_sb);
EXPORT_SYMBOL(shrink_dcache_parent);
@@ -324,12 +325,20 @@ EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
EXPORT_SYMBOL(proc_doulongvec_minmax);
/* interrupt handling */
+EXPORT_SYMBOL(add_timer);
+EXPORT_SYMBOL(del_timer);
EXPORT_SYMBOL(request_irq);
EXPORT_SYMBOL(free_irq);
+
+/* The notion of irq probe/assignment is foreign to S/390 */
+
+#if !defined(CONFIG_ARCH_S390)
EXPORT_SYMBOL(probe_irq_on);
EXPORT_SYMBOL(probe_irq_off);
-EXPORT_SYMBOL(add_timer);
-EXPORT_SYMBOL(del_timer);
+EXPORT_SYMBOL(autoirq_setup);
+EXPORT_SYMBOL(autoirq_report);
+#endif
+
#ifdef __SMP__
EXPORT_SYMBOL(del_timer_sync);
#endif
@@ -366,10 +375,6 @@ EXPORT_SYMBOL(lock_kiovec);
EXPORT_SYMBOL(unlock_kiovec);
EXPORT_SYMBOL(brw_kiovec);
-/* autoirq from drivers/net/auto_irq.c */
-EXPORT_SYMBOL(autoirq_setup);
-EXPORT_SYMBOL(autoirq_report);
-
/* dma handling */
EXPORT_SYMBOL(request_dma);
EXPORT_SYMBOL(free_dma);
@@ -439,8 +444,8 @@ EXPORT_SYMBOL(setup_arg_pages);
EXPORT_SYMBOL(copy_strings_kernel);
EXPORT_SYMBOL(do_execve);
EXPORT_SYMBOL(flush_old_exec);
-EXPORT_SYMBOL(open_dentry);
-EXPORT_SYMBOL(read_exec);
+EXPORT_SYMBOL(kernel_read);
+EXPORT_SYMBOL(open_exec);
/* Miscellaneous access points */
EXPORT_SYMBOL(si_meminfo);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index c3f75124f..a87858804 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -44,9 +44,9 @@ repeat:
mapnr = pte_pagenr(*pgtable);
if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
goto fault_in_page;
- if (mapnr >= max_mapnr)
- return 0;
page = mem_map + mapnr;
+ if ((mapnr >= max_mapnr) || PageReserved(page))
+ return 0;
flush_cache_page(vma, addr);
if (write) {
diff --git a/kernel/sched.c b/kernel/sched.c
index e1dbc62ba..c0ac80395 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -618,6 +618,11 @@ handle_softirq:
goto handle_softirq_back;
handle_tq_scheduler:
+ /*
+ * do not run the task queue with disabled interrupts,
+ * cli() wouldn't work on SMP
+ */
+ sti();
run_task_queue(&tq_scheduler);
goto tq_scheduler_back;
@@ -630,7 +635,7 @@ move_rr_last:
scheduling_in_interrupt:
printk("Scheduling in interrupt\n");
- *(int *)0 = 0;
+ BUG();
return;
}
diff --git a/kernel/signal.c b/kernel/signal.c
index 55017e2f6..0958af05c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -90,7 +90,7 @@ flush_signal_handlers(struct task_struct *t)
* Dequeue a signal and return the element to the caller, which is
* expected to free it.
*
- * All callers of must be holding current->sigmask_lock.
+ * All callers must be holding current->sigmask_lock.
*/
int
@@ -149,19 +149,19 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
kmem_cache_free(signal_queue_cachep,q);
atomic_dec(&nr_queued_signals);
- /* then see if this signal is still pending. */
- q = *pp;
- while (q) {
- if (q->info.si_signo == sig) {
- reset = 0;
- break;
- }
- q = q->next;
- }
+ /* Then see if this signal is still pending.
+ (Non rt signals may not be queued twice.)
+ */
+ if (sig >= SIGRTMIN)
+ for (q = *pp; q; q = q->next)
+ if (q->info.si_signo == sig) {
+ reset = 0;
+ break;
+ }
+
} else {
- /* Ok, it wasn't in the queue. It must have
- been sent either by a non-rt mechanism and
- we ran out of queue space. So zero out the
+ /* Ok, it wasn't in the queue. We must have
+ been out of queue space. So zero out the
info. */
info->si_signo = sig;
info->si_errno = 0;
@@ -170,9 +170,10 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
info->si_uid = 0;
}
- if (reset)
+ if (reset) {
sigdelset(&current->signal, sig);
- recalc_sigpending(current);
+ recalc_sigpending(current);
+ }
/* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER,
we need to xchg out the timer overrun values. */
@@ -196,6 +197,43 @@ printk(" %d -> %d\n", signal_pending(current), sig);
}
/*
+ * Remove signal sig from queue and from t->signal.
+ * Returns 1 if sig was found in t->signal.
+ *
+ * All callers must be holding t->sigmask_lock.
+ */
+static int rm_sig_from_queue(int sig, struct task_struct *t)
+{
+ struct signal_queue *q, **pp;
+
+ if (sig >= SIGRTMIN) {
+ printk(KERN_CRIT "SIG: rm_sig_from_queue() doesn't support rt signals\n");
+ return 0;
+ }
+
+ if (!sigismember(&t->signal, sig))
+ return 0;
+
+ sigdelset(&t->signal, sig);
+
+ pp = &t->sigqueue;
+ q = t->sigqueue;
+
+ /* Find the one we're interested in ...
+ It may appear only once. */
+ for ( ; q ; pp = &q->next, q = q->next)
+ if (q->info.si_signo == sig)
+ break;
+ if (q) {
+ if ((*pp = q->next) == NULL)
+ t->sigqueue_tail = pp;
+ kmem_cache_free(signal_queue_cachep,q);
+ atomic_dec(&nr_queued_signals);
+ }
+ return 1;
+}
+
+/*
* Determine whether a signal should be posted or not.
*
* Signals with SIG_IGN can be ignored, except for the
@@ -273,18 +311,16 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
if (t->state == TASK_STOPPED)
wake_up_process(t);
t->exit_code = 0;
- sigdelsetmask(&t->signal, (sigmask(SIGSTOP)|sigmask(SIGTSTP)|
- sigmask(SIGTTOU)|sigmask(SIGTTIN)));
- /* Inflict this corner case with recalculations, not mainline */
- recalc_sigpending(t);
+ if (rm_sig_from_queue(SIGSTOP, t) || rm_sig_from_queue(SIGTSTP, t) ||
+ rm_sig_from_queue(SIGTTOU, t) || rm_sig_from_queue(SIGTTIN, t))
+ recalc_sigpending(t);
break;
case SIGSTOP: case SIGTSTP:
case SIGTTIN: case SIGTTOU:
/* If we're stopping again, cancel SIGCONT */
- sigdelset(&t->signal, SIGCONT);
- /* Inflict this corner case with recalculations, not mainline */
- recalc_sigpending(t);
+ if (rm_sig_from_queue(SIGCONT, t))
+ recalc_sigpending(t);
break;
}
@@ -338,8 +374,12 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
q->info = *info;
break;
}
- } else {
- /* Queue overflow, we have to abort. */
+ } else if (sig >= SIGRTMIN && info && (unsigned long)info != 1
+ && info->si_code < 0) {
+ /*
+ * Queue overflow, abort. We may abort if the signal was rt
+ * and sent by user using something other than kill().
+ */
ret = -EAGAIN;
goto out;
}
@@ -406,7 +446,7 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
}
/*
- * kill_pg() sends a signal to a process group: this is what the tty
+ * kill_pg_info() sends a signal to a process group: this is what the tty
* control characters do (^C, ^Z etc)
*/
@@ -437,7 +477,7 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
}
/*
- * kill_sl() sends a signal to the session leader: this is used
+ * kill_sl_info() sends a signal to the session leader: this is used
* to send SIGHUP to the controlling process of a terminal when
* the connection is lost.
*/
@@ -484,7 +524,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
}
/*
- * kill_something() interprets pid in interesting ways just like kill(2).
+ * kill_something_info() interprets pid in interesting ways just like kill(2).
*
* POSIX specifies that kill(-1,sig) is unspecified, but what we have
* is probably wrong. Should make it like BSD or SYSV.
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 4e654fa3a..35883ed4c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -14,6 +14,8 @@
* Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer.
* Changed linked lists to use list.h instead of lists.h, 02/24/00, Bill
* Wendling.
+ * The list_for_each() macro wasn't appropriate for the sysctl loop.
+ * Removed it and replaced it with older style, 03/23/00, Bill Wendling
*/
#include <linux/config.h>
@@ -84,9 +86,9 @@ static int parse_table(int *, int, void *, size_t *, void *, size_t,
static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp);
-
static ctl_table root_table[];
-static LIST_HEAD(root_table_header);
+static struct ctl_table_header root_table_header =
+ { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
static ctl_table kern_table[];
static ctl_table vm_table[];
@@ -99,7 +101,6 @@ static ctl_table debug_table[];
static ctl_table dev_table[];
extern ctl_table random_table[];
-
/* /proc declarations: */
#ifdef CONFIG_PROC_FS
@@ -108,14 +109,12 @@ static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
static int proc_sys_permission(struct inode *, int);
-struct file_operations proc_sys_file_operations =
-{
+struct file_operations proc_sys_file_operations = {
read: proc_readsys,
write: proc_writesys,
};
-static struct inode_operations proc_sys_inode_operations =
-{
+static struct inode_operations proc_sys_inode_operations = {
permission: proc_sys_permission,
};
@@ -124,6 +123,7 @@ extern struct proc_dir_entry *proc_sys_root;
static void register_proc_table(ctl_table *, struct proc_dir_entry *);
static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
#endif
+
extern int inodes_stat[];
extern int dentry_stat[];
@@ -294,39 +294,33 @@ void __init sysctl_init(void)
register_proc_table(root_table, proc_sys_root);
init_irq_proc();
#endif
-
}
-int do_sysctl (int *name, int nlen,
- void *oldval, size_t *oldlenp,
+int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
void *newval, size_t newlen)
{
- int error;
struct list_head *tmp;
- void *context;
-
+
if (nlen == 0 || nlen >= CTL_MAXNAME)
return -ENOTDIR;
-
- if (oldval)
- {
+ if (oldval) {
int old_len;
- if (!oldlenp)
- return -EFAULT;
- if(get_user(old_len, oldlenp))
+ if (!oldlenp || get_user(old_len, oldlenp))
return -EFAULT;
}
- list_for_each(tmp, &root_table_header) {
+ tmp = &root_table_header.ctl_entry;
+ do {
struct ctl_table_header *head =
list_entry(tmp, struct ctl_table_header, ctl_entry);
- context = NULL;
- error = parse_table(name, nlen, oldval, oldlenp,
- newval, newlen, head->ctl_table, &context);
+ void *context = NULL;
+ int error = parse_table(name, nlen, oldval, oldlenp,
+ newval, newlen, head->ctl_table,
+ &context);
if (context)
kfree(context);
if (error != -ENOTDIR)
return error;
- }
+ } while (tmp != &root_table_header.ctl_entry);
return -ENOTDIR;
}
@@ -335,7 +329,7 @@ extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
struct __sysctl_args tmp;
int error;
- if(copy_from_user(&tmp, args, sizeof(tmp)))
+ if (copy_from_user(&tmp, args, sizeof(tmp)))
return -EFAULT;
lock_kernel();
@@ -345,9 +339,10 @@ extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
return error;
}
-
-/* ctl_perm does NOT grant the superuser all rights automatically, because
- some sysctl variables are readonly even to root. */
+/*
+ * ctl_perm does NOT grant the superuser all rights automatically, because
+ * some sysctl variables are readonly even to root.
+ */
static int test_perm(int mode, int op)
{
@@ -370,17 +365,16 @@ static int parse_table(int *name, int nlen,
void *newval, size_t newlen,
ctl_table *table, void **context)
{
- int error;
repeat:
if (!nlen)
return -ENOTDIR;
for ( ; table->ctl_name; table++) {
int n;
- if(get_user(n,name))
+ if (get_user(n, name))
return -EFAULT;
- if (n == table->ctl_name ||
- table->ctl_name == CTL_ANY) {
+ if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
+ int error;
if (table->child) {
if (ctl_perm(table, 001))
return -EPERM;
@@ -389,8 +383,8 @@ repeat:
table, name, nlen,
oldval, oldlenp,
newval, newlen, context);
- if (error)
- return error;
+ if (error)
+ return error;
}
name++;
nlen--;
@@ -465,9 +459,9 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
tmp->ctl_table = table;
INIT_LIST_HEAD(&tmp->ctl_entry);
if (insert_at_head)
- list_add(&tmp->ctl_entry, &root_table_header);
+ list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
else
- list_add_tail(&tmp->ctl_entry, &root_table_header);
+ list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
#ifdef CONFIG_PROC_FS
register_proc_table(table, proc_sys_root);
#endif
@@ -694,6 +688,7 @@ static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
#define OP_OR 2
#define OP_MAX 3
#define OP_MIN 4
+
static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp, int conv, int op)
{
@@ -812,7 +807,6 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
(current->pid == 1) ? OP_SET : OP_AND);
}
-
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
@@ -911,7 +905,6 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
return 0;
}
-
/*
* an unsigned long function version
*/
diff --git a/mm/filemap.c b/mm/filemap.c
index 1b9f9ed6a..bccdc9bd2 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2465,7 +2465,7 @@ generic_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
PAGE_BUG(page);
}
- status = mapping->a_ops->prepare_write(page, offset, offset+bytes);
+ status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes);
if (status)
goto unlock;
kaddr = (char*)page_address(page);
diff --git a/mm/highmem.c b/mm/highmem.c
index 8b713b2ef..691e3df1f 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -234,11 +234,20 @@ static inline void copy_from_high_bh (struct buffer_head *to,
{
struct page *p_from;
unsigned long vfrom;
+ unsigned long flags;
p_from = from->b_page;
+
+ /*
+ * Since this can be executed from IRQ context, reentrance
+ * on the same CPU must be avoided:
+ */
+ __save_flags(flags);
+ __cli();
vfrom = kmap_atomic(p_from, KM_BOUNCE_WRITE);
memcpy(to->b_data, (char *)vfrom + bh_offset(from), to->b_size);
kunmap_atomic(vfrom, KM_BOUNCE_WRITE);
+ __restore_flags(flags);
}
static inline void copy_to_high_bh_irq (struct buffer_head *to,
@@ -246,11 +255,15 @@ static inline void copy_to_high_bh_irq (struct buffer_head *to,
{
struct page *p_to;
unsigned long vto;
+ unsigned long flags;
p_to = to->b_page;
+ __save_flags(flags);
+ __cli();
vto = kmap_atomic(p_to, KM_BOUNCE_READ);
memcpy((char *)vto + bh_offset(to), from->b_data, to->b_size);
kunmap_atomic(vto, KM_BOUNCE_READ);
+ __restore_flags(flags);
}
static inline void bounce_end_io (struct buffer_head *bh, int uptodate)
diff --git a/mm/memory.c b/mm/memory.c
index 9d1a131ff..1bb7433c0 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -428,6 +428,7 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
struct vm_area_struct * vma = 0;
struct page * map;
int i;
+ int datain = (rw == READ);
/* Make sure the iobuf is not already mapped somewhere. */
if (iobuf->nr_pages)
@@ -459,8 +460,19 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
vma = find_vma(current->mm, ptr);
if (!vma)
goto out_unlock;
+ if (vma->vm_start > ptr) {
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto out_unlock;
+ if (expand_stack(vma, ptr))
+ goto out_unlock;
+ }
+ if (((datain) && (!(vma->vm_flags & VM_WRITE))) ||
+ (!(vma->vm_flags & VM_READ))) {
+ err = -EACCES;
+ goto out_unlock;
+ }
}
- if (handle_mm_fault(current, vma, ptr, (rw==READ)) <= 0)
+ if (handle_mm_fault(current, vma, ptr, datain) <= 0)
goto out_unlock;
spin_lock(&mm->page_table_lock);
map = follow_page(ptr);
@@ -774,6 +786,15 @@ static inline void establish_pte(struct vm_area_struct * vma, unsigned long addr
update_mmu_cache(vma, address, entry);
}
+static inline void break_cow(struct vm_area_struct * vma, struct page * old_page, struct page * new_page, unsigned long address,
+ pte_t *page_table)
+{
+ copy_cow_page(old_page,new_page,address);
+ flush_page_to_ram(new_page);
+ flush_cache_page(vma, address);
+ establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
+}
+
/*
* This routine handles present pages, when users try to write
* to a shared page. It is done by copying the page to a new address
@@ -852,10 +873,7 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
if (pte_val(*page_table) == pte_val(pte)) {
if (PageReserved(old_page))
++vma->vm_mm->rss;
- copy_cow_page(old_page, new_page, address);
- flush_page_to_ram(new_page);
- flush_cache_page(vma, address);
- establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
+ break_cow(vma, old_page, new_page, address, page_table);
/* Free the old page.. */
new_page = old_page;
@@ -903,7 +921,7 @@ static void partial_clear(struct vm_area_struct *vma, unsigned long address)
return;
flush_cache_page(vma, address);
page = pte_page(pte);
- if (page-mem_map >= max_mapnr)
+ if ((page-mem_map >= max_mapnr) || PageReserved(page))
return;
offset = address & ~PAGE_MASK;
memclear_highpage_flush(page, offset, PAGE_SIZE - offset);
diff --git a/mm/mmap.c b/mm/mmap.c
index 7bc2cf910..604624168 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -200,11 +200,11 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
if (file != NULL) {
switch (flags & MAP_TYPE) {
case MAP_SHARED:
- if ((prot & PROT_WRITE) && !(file->f_mode & 2))
+ if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE))
return -EACCES;
/* Make sure we don't allow writing to an append-only file.. */
- if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & 2))
+ if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & FMODE_WRITE))
return -EACCES;
/* make sure there are no mandatory locks on the file. */
@@ -213,7 +213,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
/* fall through */
case MAP_PRIVATE:
- if (!(file->f_mode & 1))
+ if (!(file->f_mode & FMODE_READ))
return -EACCES;
break;
@@ -252,7 +252,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
VM_ClearReadHint(vma);
vma->vm_raend = 0;
- if (file->f_mode & 1)
+ if (file->f_mode & FMODE_READ)
vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
if (flags & MAP_SHARED) {
vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
@@ -266,7 +266,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
* We leave the VM_MAYSHARE bit on, just to get correct output
* from /proc/xxx/maps..
*/
- if (!(file->f_mode & 2))
+ if (!(file->f_mode & FMODE_WRITE))
vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
}
} else
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 1205ab835..a780c6a74 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -266,11 +266,19 @@ static int zone_balance_memory(zonelist_t *zonelist)
/*
* This is the 'heart' of the zoned buddy allocator:
*/
-struct page * __alloc_pages (zonelist_t *zonelist, unsigned long order)
+struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
{
zone_t **zone = zonelist->zones;
/*
+ * If this is a recursive call, we'd better
+ * do our best to just allocate things without
+ * further thought.
+ */
+ if (current->flags & PF_MEMALLOC)
+ goto allocate_ok;
+
+ /*
* (If anyone calls gfp from interrupts nonatomically then it
* will sooner or later tripped up by a schedule().)
*
@@ -283,32 +291,22 @@ struct page * __alloc_pages (zonelist_t *zonelist, unsigned long order)
break;
if (!z->size)
BUG();
- /*
- * If this is a recursive call, we'd better
- * do our best to just allocate things without
- * further thought.
- */
- if (!(current->flags & PF_MEMALLOC)) {
- /* Are we low on memory? */
- if (z->free_pages <= z->pages_low)
- continue;
- }
- /*
- * This is an optimization for the 'higher order zone
- * is empty' case - it can happen even in well-behaved
- * systems, think the page-cache filling up all RAM.
- * We skip over empty zones. (this is not exact because
- * we do not take the spinlock and it's not exact for
- * the higher order case, but will do it for most things.)
- */
- if (z->free_pages) {
+
+ /* Are we supposed to free memory? Don't make it worse.. */
+ if (!z->zone_wake_kswapd && z->free_pages > z->pages_low) {
struct page *page = rmqueue(z, order);
if (page)
return page;
}
}
+
+ /*
+ * Ok, no obvious zones were available, start
+ * balancing things a bit..
+ */
if (zone_balance_memory(zonelist)) {
zone = zonelist->zones;
+allocate_ok:
for (;;) {
zone_t *z = *(zone++);
if (!z)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 96cad2679..99510c53b 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -39,7 +39,8 @@ static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned lo
continue;
if (pte_present(page)) {
unsigned long map_nr = pte_pagenr(page);
- if (map_nr < max_mapnr)
+ if ((map_nr < max_mapnr) &&
+ (!PageReserved(mem_map + map_nr)))
__free_page(mem_map + map_nr);
continue;
}
@@ -206,7 +207,7 @@ void * vmalloc_prot(unsigned long size, pgprot_t prot)
struct vm_struct *area;
size = PAGE_ALIGN(size);
- if (!size || (size >> PAGE_SHIFT) > max_mapnr) {
+ if (!size || (size >> PAGE_SHIFT) > num_physpages) {
BUG();
return NULL;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index d3dfb8db6..f00e9c535 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -45,7 +45,7 @@ static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pt
if (!pte_present(pte))
goto out_failed;
page = pte_page(pte);
- if (page-mem_map >= max_mapnr)
+ if ((page-mem_map >= max_mapnr) || PageReserved(page))
goto out_failed;
/* Don't look at this pte if it's been accessed recently. */
@@ -59,7 +59,7 @@ static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pt
goto out_failed;
}
- if (PageReserved(page) || PageLocked(page))
+ if (PageLocked(page))
goto out_failed;
/*
diff --git a/net/802/tr.c b/net/802/tr.c
index 2d836d9c5..4133c2207 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -237,8 +237,9 @@ static void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_d
rif_cache entry;
unsigned char *olddata;
unsigned char mcast_func_addr[] = {0xC0,0x00,0x00,0x04,0x00,0x00};
+ unsigned long flags ;
- spin_lock_bh(&rif_lock);
+ spin_lock_irqsave(&rif_lock,flags);
/*
* Broadcasts are single route as stated in RFC 1042
@@ -308,7 +309,7 @@ printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0],
else
slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8);
olddata = skb->data;
- spin_unlock_bh(&rif_lock);
+ spin_unlock_irqrestore(&rif_lock,flags);
skb_pull(skb, slack);
memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack);
@@ -418,8 +419,9 @@ static void rif_check_expire(unsigned long dummy)
{
int i;
unsigned long now=jiffies;
+ unsigned long flags ;
- spin_lock(&rif_lock);
+ spin_lock_irqsave(&rif_lock,flags);
for(i=0; i < RIF_TABLE_SIZE;i++)
{
@@ -439,7 +441,7 @@ static void rif_check_expire(unsigned long dummy)
}
}
- spin_unlock(&rif_lock);
+ spin_unlock_irqrestore(&rif_lock,flags);
/*
* Reset the timer
diff --git a/net/atm/Makefile b/net/atm/Makefile
index 1c525f601..a43d790b1 100644
--- a/net/atm/Makefile
+++ b/net/atm/Makefile
@@ -16,10 +16,6 @@ ifeq ($(CONFIG_ATM),y)
O_OBJS = addr.o pvc.o signaling.o svc.o
OX_OBJS = common.o atm_misc.o raw.o resources.o
-ifeq ($(CONFIG_MMU_HACKS),y)
-O_OBJS += mmuio.o
-endif
-
ifeq ($(CONFIG_ATM_CLIP),y)
O_OBJS += clip.o
NEED_IPCOM = ipcommon.o
@@ -36,10 +32,11 @@ OX_OBJS += proc.o
endif
ifeq ($(CONFIG_ATM_LANE),y)
-O_OBJS += lec.o lane_mpoa_init.o
+O_OBJS += lec.o
+OX_OBJS += lane_mpoa_init.o
else
ifeq ($(CONFIG_ATM_LANE),m)
- O_OBJS += lane_mpoa_init.o
+ OX_OBJS += lane_mpoa_init.o
M_OBJS += lec.o
endif
endif
diff --git a/net/atm/addr.c b/net/atm/addr.c
index f7d52a824..8bca9d1c3 100644
--- a/net/atm/addr.c
+++ b/net/atm/addr.c
@@ -1,11 +1,11 @@
/* net/atm/addr.c - Local ATM address registry */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/atm.h>
#include <linux/atmdev.h>
-#include <linux/wait.h>
+#include <linux/sched.h>
#include <asm/uaccess.h>
#include "signaling.h"
@@ -41,23 +41,7 @@ static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b)
* (which may involve page faults and therefore rescheduling)
*/
-
-static volatile int local_lock = 0;
-static wait_queue_head_t local_wait;
-
-
-static void lock_local(void)
-{
- while (local_lock) sleep_on(&local_wait);
- local_lock = 1;
-}
-
-
-static void unlock_local(void)
-{
- local_lock = 0;
- wake_up(&local_wait);
-}
+static DECLARE_MUTEX(local_lock);
static void notify_sigd(struct atm_dev *dev)
@@ -73,13 +57,13 @@ void reset_addr(struct atm_dev *dev)
{
struct atm_dev_addr *this;
- lock_local();
+ down(&local_lock);
while (dev->local) {
this = dev->local;
dev->local = this->next;
kfree(this);
}
- unlock_local();
+ up(&local_lock);
notify_sigd(dev);
}
@@ -91,20 +75,20 @@ int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
error = check_addr(addr);
if (error) return error;
- lock_local();
+ down(&local_lock);
for (walk = &dev->local; *walk; walk = &(*walk)->next)
if (identical(&(*walk)->addr,addr)) {
- unlock_local();
+ up(&local_lock);
return -EEXIST;
}
*walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
if (!*walk) {
- unlock_local();
+ up(&local_lock);
return -ENOMEM;
}
(*walk)->addr = *addr;
(*walk)->next = NULL;
- unlock_local();
+ up(&local_lock);
notify_sigd(dev);
return 0;
}
@@ -117,17 +101,17 @@ int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
error = check_addr(addr);
if (error) return error;
- lock_local();
+ down(&local_lock);
for (walk = &dev->local; *walk; walk = &(*walk)->next)
if (identical(&(*walk)->addr,addr)) break;
if (!*walk) {
- unlock_local();
+ up(&local_lock);
return -ENOENT;
}
this = *walk;
*walk = this->next;
kfree(this);
- unlock_local();
+ up(&local_lock);
notify_sigd(dev);
return 0;
}
@@ -138,27 +122,21 @@ int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
struct atm_dev_addr *walk;
int total;
- lock_local();
+ down(&local_lock);
total = 0;
for (walk = dev->local; walk; walk = walk->next) {
total += sizeof(struct sockaddr_atmsvc);
if (total > size) {
- unlock_local();
+ up(&local_lock);
return -E2BIG;
}
if (copy_to_user(u_buf,&walk->addr,
sizeof(struct sockaddr_atmsvc))) {
- unlock_local();
+ up(&local_lock);
return -EFAULT;
}
u_buf++;
}
- unlock_local();
+ up(&local_lock);
return total;
}
-
-
-void init_addr(void)
-{
- init_waitqueue_head(&local_wait);
-}
diff --git a/net/atm/addr.h b/net/atm/addr.h
index fcd134023..84a98e7c0 100644
--- a/net/atm/addr.h
+++ b/net/atm/addr.h
@@ -1,6 +1,6 @@
/* net/atm/addr.h - Local ATM address registry */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef NET_ATM_ADDR_H
@@ -14,6 +14,5 @@ void reset_addr(struct atm_dev *dev);
int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size);
-void init_addr(void);
#endif
diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c
index 9e2785ed6..c8e19d2bc 100644
--- a/net/atm/atm_misc.c
+++ b/net/atm/atm_misc.c
@@ -1,12 +1,14 @@
/* net/atm/atm_misc.c - Various functions for use by ATM drivers */
-/* Written 1995-1999 by Werner Almesberger, EPFL ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL ICA */
#include <linux/module.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/skbuff.h>
+#include <linux/sonet.h>
+#include <linux/bitops.h>
#include <asm/atomic.h>
#include <asm/errno.h>
@@ -16,7 +18,7 @@ int atm_charge(struct atm_vcc *vcc,int truesize)
atm_force_charge(vcc,truesize);
if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) return 1;
atm_return(vcc,truesize);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
return 0;
}
@@ -36,7 +38,7 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
}
}
atm_return(vcc,guess);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
return NULL;
}
@@ -46,7 +48,7 @@ static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
struct atm_vcc *walk;
for (walk = vcc->dev->vccs; walk; walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
walk->vci == vci && ((walk->qos.txtp.traffic_class !=
ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
(walk->qos.rxtp.traffic_class != ATM_NONE &&
@@ -135,7 +137,25 @@ int atm_pcr_goal(struct atm_trafprm *tp)
}
+void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to)
+{
+#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
+}
+
+
+void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to)
+{
+#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
+}
+
+
EXPORT_SYMBOL(atm_charge);
EXPORT_SYMBOL(atm_alloc_charge);
EXPORT_SYMBOL(atm_find_ci);
EXPORT_SYMBOL(atm_pcr_goal);
+EXPORT_SYMBOL(sonet_copy_stats);
+EXPORT_SYMBOL(sonet_subtract_stats);
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 98d51c094..37610d6d6 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -21,6 +21,7 @@
#include <linux/in.h> /* for struct sockaddr_in */
#include <linux/if.h> /* for IFF_UP */
#include <linux/inetdevice.h>
+#include <linux/bitops.h>
#include <net/route.h> /* for struct rtable and routing */
#include <net/icmp.h> /* icmp_send */
#include <asm/param.h> /* for HZ */
@@ -196,6 +197,7 @@ void clip_push(struct atm_vcc *vcc,struct sk_buff *skb)
atm_return(vcc,skb->truesize);
skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
/* clip_vcc->entry == NULL if we don't have an IP address yet */
+ skb->rx_dev = NULL;
if (!skb->dev) {
kfree_skb(skb);
return;
@@ -431,7 +433,7 @@ return 0;
}
clip_priv->stats.tx_packets++;
clip_priv->stats.tx_bytes += skb->len;
- (void) vcc->dev->ops->send(vcc,skb);
+ (void) vcc->send(vcc,skb);
if (atm_may_send(vcc,0)) {
entry->vccs->xoff = 0;
return 0;
@@ -462,7 +464,6 @@ int clip_mkip(struct atm_vcc *vcc,int timeout)
struct clip_vcc *clip_vcc;
struct sk_buff_head copy;
struct sk_buff *skb;
- unsigned long flags;
if (!vcc->push) return -EBADFD;
clip_vcc = kmalloc(sizeof(struct clip_vcc),GFP_KERNEL);
@@ -477,12 +478,9 @@ int clip_mkip(struct atm_vcc *vcc,int timeout)
clip_vcc->idle_timeout = timeout*HZ;
clip_vcc->old_push = vcc->push;
clip_vcc->old_pop = vcc->pop;
- save_flags(flags);
- cli();
vcc->push = clip_push;
vcc->pop = clip_pop;
skb_migrate(&vcc->recvq,&copy);
- restore_flags(flags);
/* re-process everything received between connection setup and MKIP */
while ((skb = skb_dequeue(&copy)))
if (!clip_devs) {
@@ -710,7 +708,7 @@ static struct atm_dev atmarpd_dev = {
999, /* dummy device number */
NULL,NULL, /* pretend not to have any VCCs */
NULL,NULL, /* no data */
- 0, /* no flags */
+ { 0 }, /* no flags */
NULL, /* no local address */
{ 0 } /* no ESI, no statistics */
};
@@ -729,7 +727,8 @@ int atm_init_atmarp(struct atm_vcc *vcc)
add_timer(&idle_timer);
}
atmarpd = vcc;
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
/* allow replies and avoid getting closed if signaling dies */
bind_vcc(vcc,&atmarpd_dev);
vcc->push = NULL;
diff --git a/net/atm/common.c b/net/atm/common.c
index c4288203c..9625061eb 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -19,9 +19,11 @@
#include <linux/sched.h>
#include <linux/time.h> /* struct timeval */
#include <linux/skbuff.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* struct sock */
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include <asm/poll.h>
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
@@ -96,7 +98,7 @@ int atm_create(struct socket *sock,int protocol,int family)
if (sock->type == SOCK_STREAM) return -EINVAL;
if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
vcc = sk->protinfo.af_atm;
- vcc->flags = 0;
+ memset(&vcc->flags,0,sizeof(vcc->flags));
vcc->dev = NULL;
vcc->family = sock->ops->family;
vcc->alloc_tx = alloc_tx;
@@ -126,7 +128,7 @@ void atm_release_vcc_sk(struct sock *sk,int free_sk)
struct sk_buff *skb;
vcc = sk->protinfo.af_atm;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
if (vcc->dev) {
if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
@@ -156,9 +158,8 @@ int atm_release(struct socket *sock)
void atm_async_release_vcc(struct atm_vcc *vcc,int reply)
{
- vcc->flags |= ATM_VF_CLOSE;
+ set_bit(ATM_VF_CLOSE,&vcc->flags);
vcc->reply = reply;
- /*vcc->flags &= ~ATM_VF_READY;*/
wake_up(&vcc->sleep);
}
@@ -204,6 +205,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
return -EPERM;
error = 0;
+ bind_vcc(vcc,dev);
switch (vcc->qos.aal) {
case ATM_AAL0:
error = atm_init_aal0(vcc);
@@ -226,8 +228,10 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
}
if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
- if (error) return error;
- bind_vcc(vcc,dev);
+ if (error) {
+ bind_vcc(vcc,NULL);
+ return error;
+ }
DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class,
vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
@@ -257,8 +261,8 @@ static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
{
if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
- vcc->flags &= ~ATM_VF_PARTIAL;
- else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL;
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL;
printk(KERN_DEBUG "atm_connect (TX: cl %d,bw %d-%d,sdu %d; "
"RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
@@ -267,7 +271,7 @@ int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
" ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
return -EINVAL;
@@ -285,7 +289,7 @@ int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
if (!dev) return -ENODEV;
}
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_PARTIAL;
+ set_bit(ATM_VF_PARTIAL,&vcc->flags);
return 0;
}
@@ -300,7 +304,8 @@ int atm_connect(struct socket *sock,int itf,short vpi,int vci)
if (!(vpi || vci)) return -EINVAL;
error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci);
if (error) return error;
- if (ATM_SD(sock)->flags & ATM_VF_READY) sock->state = SS_CONNECTED;
+ if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags))
+ sock->state = SS_CONNECTED;
return 0;
}
@@ -308,11 +313,10 @@ int atm_connect(struct socket *sock,int itf,short vpi,int vci)
int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
int flags,struct scm_cookie *scm)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *vcc;
struct sk_buff *skb;
- unsigned long cpu_flags;
int eff_len,error;
-
void *buff;
int size;
@@ -322,28 +326,33 @@ int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
buff = m->msg_iov->iov_base;
size = m->msg_iov->iov_len;
vcc = ATM_SD(sock);
- save_flags(cpu_flags);
- cli();
+ add_wait_queue(&vcc->sleep,&wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ error = 1; /* <= 0 is error */
while (!(skb = skb_dequeue(&vcc->recvq))) {
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) {
- restore_flags(cpu_flags);
- return vcc->reply;
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags)) {
+ error = vcc->reply;
+ break;
}
- if (!(vcc->flags & ATM_VF_READY)) {
- restore_flags(cpu_flags);
- return 0;
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) {
+ error = 0;
+ break;
}
if (flags & MSG_DONTWAIT) {
- restore_flags(cpu_flags);
- return -EAGAIN;
+ error = -EAGAIN;
+ break;
}
- interruptible_sleep_on(&vcc->sleep);
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
- restore_flags(cpu_flags);
- return -ERESTARTSYS;
+ error = -ERESTARTSYS;
+ break;
}
}
- restore_flags(cpu_flags);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vcc->sleep,&wait);
+ if (error <= 0) return error;
vcc->timestamp = skb->stamp;
eff_len = skb->len > size ? size : skb->len;
if (vcc->dev->ops->feedback)
@@ -383,10 +392,10 @@ int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len,
struct scm_cookie *scm)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *vcc;
struct sk_buff *skb;
int eff,error;
-
const void *buff;
int size;
@@ -396,19 +405,40 @@ int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len,
buff = m->msg_iov->iov_base;
size = m->msg_iov->iov_len;
vcc = ATM_SD(sock);
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) return vcc->reply;
- if (!(vcc->flags & ATM_VF_READY)) return -EPIPE;
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags))
+ return vcc->reply;
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) return -EPIPE;
if (!size) return 0;
/* verify_area is done by net/socket.c */
eff = (size+3) & ~3; /* align to word boundary */
+ add_wait_queue(&vcc->wsleep,&wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ error = 0;
while (!(skb = vcc->alloc_tx(vcc,eff))) {
- if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN;
- interruptible_sleep_on(&vcc->wsleep);
- if (signal_pending(current)) return -ERESTARTSYS;
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE))
- return vcc->reply;
- if (!(vcc->flags & ATM_VF_READY)) return -EPIPE;
+ if (m->msg_flags & MSG_DONTWAIT) {
+ error = -EAGAIN;
+ break;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (signal_pending(current)) {
+ error = -ERESTARTSYS;
+ break;
+ }
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags)) {
+ error = vcc->reply;
+ break;
+ }
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) {
+ error = -EPIPE;
+ break;
+ }
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vcc->wsleep,&wait);
+ if (error) return error;
skb->dev = NULL; /* for paths shared with net_device interfaces */
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = vcc->atm_options;
@@ -433,7 +463,9 @@ unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait)
mask = 0;
if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq))
mask |= POLLIN | POLLRDNORM;
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) mask |= POLLHUP;
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags))
+ mask |= POLLHUP;
if (sock->state != SS_CONNECTING) {
if (vcc->qos.txtp.traffic_class != ATM_NONE &&
vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+
@@ -448,20 +480,38 @@ unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait)
}
-static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero)
+static void copy_aal_stats(struct k_atm_aal_stats *from,
+ struct atm_aal_stats *to)
{
- unsigned long flags;
- int error;
+#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
+}
- error = 0;
- save_flags(flags);
- cli();
- if (arg)
- error = copy_to_user(arg,&dev->stats,
- sizeof(struct atm_dev_stats));
- if (zero && !error)
- memset(&dev->stats,0,sizeof(struct atm_dev_stats));
- restore_flags(flags);
+
+static void subtract_aal_stats(struct k_atm_aal_stats *from,
+ struct atm_aal_stats *to)
+{
+#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
+}
+
+
+static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero)
+{
+ struct atm_dev_stats tmp;
+ int error = 0;
+
+ copy_aal_stats(&dev->stats.aal0,&tmp.aal0);
+ copy_aal_stats(&dev->stats.aal34,&tmp.aal34);
+ copy_aal_stats(&dev->stats.aal5,&tmp.aal5);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
+ if (zero && !error) {
+ subtract_aal_stats(&dev->stats.aal0,&tmp.aal0);
+ subtract_aal_stats(&dev->stats.aal34,&tmp.aal34);
+ subtract_aal_stats(&dev->stats.aal5,&tmp.aal5);
+ }
return error ? -EFAULT : 0;
}
@@ -478,7 +528,8 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
switch (cmd) {
case SIOCOUTQ:
if (sock->state != SS_CONNECTED ||
- !(vcc->flags & ATM_VF_READY)) return -EINVAL;
+ !test_bit(ATM_VF_READY,&vcc->flags))
+ return -EINVAL;
return put_user(vcc->sk->sndbuf-
atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
(int *) arg) ? -EFAULT : 0;
@@ -522,6 +573,14 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
return 0;
case ATMSIGD_CTRL:
if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ /*
+ * The user/kernel protocol for exchanging signalling
+ * info uses kernel pointers as opaque references,
+ * so the holder of the file descriptor can scribble
+ * on the kernel... so we should make sure that we
+ * have the same privledges that /proc/kcore needs
+ */
+ if (!capable(CAP_SYS_RAWIO)) return -EPERM;
error = sigd_attach(vcc);
if (!error) sock->state = SS_CONNECTED;
return error;
@@ -668,6 +727,12 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
write the length" */
return put_user(size,
&((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+ case ATM_SETLOOP:
+ if (__ATM_LM_XTRMT((int) (long) buf) &&
+ __ATM_LM_XTLOC((int) (long) buf) >
+ __ATM_LM_XTRMT((int) (long) buf))
+ return -EINVAL;
+ /* fall through */
case ATM_SETCIRANGE:
case SONET_GETSTATZ:
case SONET_SETDIAG:
@@ -689,6 +754,14 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{
+ /*
+ * Don't let the QoS change the already connected AAL type nor the
+ * traffic class.
+ */
+ if (qos->aal != vcc->qos.aal ||
+ qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
+ qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
+ return -EINVAL;
if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
if (vcc->family == AF_ATMPVC)
return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
@@ -751,7 +824,7 @@ static int atm_do_setsockopt(struct socket *sock,int level,int optname,
if (sock->state != SS_UNCONNECTED)
return -EBADFD;
vcc->qos = qos;
- vcc->flags |= ATM_VF_HASQOS;
+ set_bit(ATM_VF_HASQOS,&vcc->flags);
return 0;
}
case SO_SETCLP:
@@ -777,7 +850,8 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname,
vcc = ATM_SD(sock);
switch (optname) {
case SO_ATMQOS:
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags))
+ return -EINVAL;
return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ?
-EFAULT : 0;
case SO_SETCLP:
@@ -787,7 +861,8 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname,
{
struct sockaddr_atmpvc pvc;
- if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR))
+ if (!vcc->dev ||
+ !test_bit(ATM_VF_ADDR,&vcc->flags))
return -ENOTCONN;
pvc.sap_family = AF_ATMPVC;
pvc.sap_addr.itf = vcc->dev->number;
diff --git a/net/atm/ipcommon.c b/net/atm/ipcommon.c
index 4bf7a1918..d7c4a4d3a 100644
--- a/net/atm/ipcommon.c
+++ b/net/atm/ipcommon.c
@@ -1,6 +1,6 @@
/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */
-/* Written 1996,1997 by Werner Almesberger, EPFL LRC */
+/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/string.h>
@@ -32,20 +32,26 @@ const unsigned char llc_oui[] = {
/*
* skb_migrate moves the list at FROM to TO, emptying FROM in the process.
- * This function should live in skbuff.c or skbuff.h. Note that skb_migrate
- * is not atomic, so turn off interrupts when using it.
+ * This function should live in skbuff.c or skbuff.h.
*/
void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to)
{
- struct sk_buff *skb,*prev;
+ struct sk_buff *skb;
+ unsigned long flags;
- for (skb = ((struct sk_buff *) from)->next;
- skb != (struct sk_buff *) from; skb = skb->next) skb->list = to;
- prev = from->prev;
- from->next->prev = (struct sk_buff *) to;
- prev->next = (struct sk_buff *) to;
+ spin_lock_irqsave(&from->lock,flags);
*to = *from;
- skb_queue_head_init(from);
+ from->prev = (struct sk_buff *) from;
+ from->next = (struct sk_buff *) from;
+ from->qlen = 0;
+ spin_unlock_irqrestore(&from->lock,flags);
+ spin_lock_init(&to->lock);
+ for (skb = ((struct sk_buff *) to)->next;
+ skb != (struct sk_buff *) from; skb = skb->next) skb->list = to;
+ if (to->next == (struct sk_buff *) from)
+ to->next = (struct sk_buff *) to;
+ to->next->prev = (struct sk_buff *) to;
+ to->prev->next = (struct sk_buff *) to;
}
diff --git a/net/atm/ipcommon.h b/net/atm/ipcommon.h
index 105e090d7..30a5583b0 100644
--- a/net/atm/ipcommon.h
+++ b/net/atm/ipcommon.h
@@ -1,6 +1,6 @@
/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */
-/* Written 1996-1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef NET_ATM_IPCOMMON_H
@@ -15,6 +15,10 @@
extern struct net_device *clip_devs;
+/*
+ * Moves all skbs from "from" to "to". The operation is atomic for "from", but
+ * not for "to". "to" may only be accessed after skb_migrate finishes.
+ */
void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to);
diff --git a/net/atm/lane_mpoa_init.c b/net/atm/lane_mpoa_init.c
index d1938c187..469685703 100644
--- a/net/atm/lane_mpoa_init.c
+++ b/net/atm/lane_mpoa_init.c
@@ -37,6 +37,18 @@ void atm_mpoa_init(void)
#endif
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+rwlock_t lane_bridge_hook_lock = RW_LOCK_UNLOCKED;
+struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+ unsigned char *addr) = NULL;
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) = NULL;
+#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE)
+EXPORT_SYMBOL(lane_bridge_hook_lock);
+EXPORT_SYMBOL(br_fdb_get_hook);
+EXPORT_SYMBOL(br_fdb_put_hook);
+#endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
+
void atm_lane_init(void)
{
#ifndef CONFIG_ATM_LANE_MODULE /* not module */
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 8c6d8d4af..701ece763 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -6,6 +6,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/bitops.h>
/* We are ethernet device */
#include <linux/if_ether.h>
@@ -29,9 +30,11 @@
#include <linux/atmdev.h>
#include <linux/atmlec.h>
-/* Bridge */
-#ifdef CONFIG_BRIDGE
-#include <net/br.h>
+/* Proxy LEC knows about bridging */
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+#include <linux/if_bridge.h>
+#include "../bridge/br_private.h"
+unsigned char bridge_ula[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
#endif
/* Modular too */
@@ -88,23 +91,19 @@ struct net_device **get_dev_lec (void) {
return &dev_lec[0];
}
-#ifdef CONFIG_BRIDGE
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
static void handle_bridge(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
char *buff;
struct lec_priv *priv;
- unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
/* Check if this is a BPDU. If so, ask zeppelin to send
- * LE_TOPOLOGY_REQUEST with the value of Topology Change bit
- * in the Config BPDU*/
+ * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
+ * as the Config BPDU has */
eth = (struct ethhdr *)skb->data;
buff = skb->data + skb->dev->hard_header_len;
- if ((memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) &&
- *buff++ == BRIDGE_LLC1_DSAP &&
- *buff++ == BRIDGE_LLC1_SSAP &&
- *buff++ == BRIDGE_LLC1_CTRL) {
+ if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
struct sk_buff *skb2;
struct atmlec_msg *mesg;
@@ -113,7 +112,8 @@ static void handle_bridge(struct sk_buff *skb, struct net_device *dev)
skb2->len = sizeof(struct atmlec_msg);
mesg = (struct atmlec_msg *)skb2->data;
mesg->type = l_topology_change;
- mesg->content.normal.flag = *(skb->nh.raw + BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) & TOPOLOGY_CHANGE;
+ buff += 4;
+ mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */
priv = (struct lec_priv *)dev->priv;
atm_force_charge(priv->lecd, skb2->truesize);
@@ -123,7 +123,7 @@ static void handle_bridge(struct sk_buff *skb, struct net_device *dev)
return;
}
-#endif /* CONFIG_BRIDGE */
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
/*
* Modelled after tr_type_trans
@@ -219,10 +219,10 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
(long)skb->head, (long)skb->data, (long)skb->tail,
(long)skb->end);
-#ifdef CONFIG_BRIDGE
- if (skb->pkt_bridged == IS_BRIDGED)
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ if (memcmp(skb->data, bridge_ula, sizeof(bridge_ula)) == 0)
handle_bridge(skb, dev);
-#endif /* CONFIG_BRIDGE */
+#endif
/* Make sure we have room for lec_id */
if (skb_headroom(skb) < 2) {
@@ -303,7 +303,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
send_vcc, send_vcc?send_vcc->flags:0, entry);
- if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) {
+ if (!send_vcc || !test_bit(ATM_VF_READY,&send_vcc->flags)) {
if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name);
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -339,7 +339,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
send_vcc->vpi, send_vcc->vci);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb2->len;
- send_vcc->dev->ops->send(send_vcc, skb2);
+ send_vcc->send(send_vcc, skb2);
}
ATM_SKB(skb)->vcc = send_vcc;
@@ -348,7 +348,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
ATM_SKB(skb)->atm_options = send_vcc->atm_options;
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
- send_vcc->dev->ops->send(send_vcc, skb);
+ send_vcc->send(send_vcc, skb);
#if 0
/* Should we wait for card's device driver to notify us? */
@@ -463,32 +463,44 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag);
break;
case l_should_bridge: {
-#ifdef CONFIG_BRIDGE
- struct fdb *f;
- extern Port_data port_info[];
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ struct net_bridge_fdb_entry *f;
DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
dev->name,
mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1],
mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3],
mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]);
- f = br_avl_find_addr(mesg->content.proxy.mac_addr); /* bridge/br.c */
+
+ read_lock(&lane_bridge_hook_lock);
+ if (br_fdb_get_hook == NULL || dev->br_port == NULL) {
+ read_unlock(&lane_bridge_hook_lock);
+ break;
+ }
+
+ f = br_fdb_get_hook(dev->br_port->br, mesg->content.proxy.mac_addr);
if (f != NULL &&
- port_info[f->port].dev != dev &&
- port_info[f->port].state == Forwarding) {
+ f->dst->dev != dev &&
+ f->dst->state == BR_STATE_FORWARDING) {
/* hit from bridge table, send LE_ARP_RESPONSE */
struct sk_buff *skb2;
DPRINTK("%s: entry found, responding to zeppelin\n", dev->name);
skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
- if (skb2 == NULL) break;
+ if (skb2 == NULL) {
+ br_fdb_put_hook(f);
+ read_unlock(&lane_bridge_hook_lock);
+ break;
+ }
skb2->len = sizeof(struct atmlec_msg);
memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
atm_force_charge(priv->lecd, skb2->truesize);
skb_queue_tail(&priv->lecd->recvq, skb2);
wake_up(&priv->lecd->sleep);
}
-#endif /* CONFIG_BRIDGE */
+ if (f != NULL) br_fdb_put_hook(f);
+ read_unlock(&lane_bridge_hook_lock);
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
}
break;
default:
@@ -537,7 +549,7 @@ static struct atm_dev lecatm_dev = {
999, /*dummy device number*/
NULL,NULL, /*no VCCs*/
NULL,NULL, /*no data*/
- 0, /*no flags*/
+ { 0 }, /*no flags*/
NULL, /* no local address*/
{ 0 } /*no ESI or rest of the atm_dev struct things*/
};
@@ -684,6 +696,7 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
lec_arp_check_empties(priv, vcc, skb);
}
skb->dev = dev;
+ skb->rx_dev = NULL;
skb->data += 2; /* skip lec_id */
#ifdef CONFIG_TR
if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
@@ -777,7 +790,8 @@ lecd_attach(struct atm_vcc *vcc, int arg)
bind_vcc(vcc, &lecatm_dev);
vcc->proto_data = dev_lec[i];
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
/* Set default values to these variables */
priv->maximum_unknown_frame_count = 1;
@@ -1055,8 +1069,8 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
if (entry->vcc) {
entry->vcc->push = entry->old_push;
#if 0 /* August 6, 1998 */
- entry->vcc->flags |= ATM_VF_RELEASED;
- entry->vcc->flags &= ~ATM_VF_READY;
+ set_bit(ATM_VF_RELEASED,&entry->vcc->flags);
+ clear_bit(ATM_VF_READY,&entry->vcc->flags);
entry->vcc->push(entry->vcc, NULL);
#endif
atm_async_release_vcc(entry->vcc, -EPIPE);
@@ -1065,8 +1079,8 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
if (entry->recv_vcc) {
entry->recv_vcc->push = entry->old_recv_push;
#if 0
- entry->recv_vcc->flags |= ATM_VF_RELEASED;
- entry->recv_vcc->flags &= ~ATM_VF_READY;
+ set_bit(ATM_VF_RELEASED,&entry->vcc->flags);
+ clear_bit(ATM_VF_READY,&entry->vcc->flags);
entry->recv_vcc->push(entry->recv_vcc, NULL);
#endif
atm_async_release_vcc(entry->recv_vcc, -EPIPE);
diff --git a/net/atm/lec.h b/net/atm/lec.h
index 4a94c2b6d..df08e6803 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -9,10 +9,19 @@
#ifndef _LEC_H_
#define _LEC_H_
+#include <linux/config.h>
#include <linux/atmdev.h>
#include <linux/netdevice.h>
#include <linux/atmlec.h>
+#if defined (CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+#include <linux/if_bridge.h>
+extern rwlock_t lane_bridge_hook_lock;
+struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+ unsigned char *addr);
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
+
#define LEC_HEADER_LEN 16
struct lecdatahdr_8023 {
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index b9247334f..deeb737f5 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -2,6 +2,7 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/bitops.h>
/* We are an ethernet device */
#include <linux/if_ether.h>
@@ -522,7 +523,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
atomic_add(skb->truesize, &entry->shortcut->tx_inuse);
ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */
ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
- entry->shortcut->dev->ops->send(entry->shortcut, skb);
+ entry->shortcut->send(entry->shortcut, skb);
entry->packets_fwded++;
return 0;
@@ -739,7 +740,7 @@ static struct atm_dev mpc_dev = {
NULL, /* last VCC */
NULL, /* per-device data */
NULL, /* private PHY data */
- 0, /* device flags */
+ { 0 }, /* device flags */
NULL, /* local ATM address */
{ 0 } /* no ESI */
/* rest of the members will be 0 */
@@ -780,7 +781,8 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
mpc->mpoad_vcc = vcc;
bind_vcc(vcc, &mpc_dev);
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
if (mpc->dev) {
char empty[ATM_ESA_LEN];
diff --git a/net/atm/proc.c b/net/atm/proc.c
index 904dc43ba..79ab6e045 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -33,6 +33,7 @@
#include <linux/if_arp.h>
#include <linux/init.h> /* for __init */
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include <asm/param.h> /* for HZ */
#include "resources.h"
#include "common.h" /* atm_proc_init prototype */
@@ -64,10 +65,12 @@ static struct file_operations proc_spec_atm_operations = {
};
static void add_stats(char *buf,const char *aal,
- const struct atm_aal_stats *stats)
+ const struct k_atm_aal_stats *stats)
{
- sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,stats->tx,
- stats->tx_err,stats->rx,stats->rx_err,stats->rx_drop);
+ sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,
+ atomic_read(&stats->tx),atomic_read(&stats->tx_err),
+ atomic_read(&stats->rx),atomic_read(&stats->rx_err),
+ atomic_read(&stats->rx_drop));
}
@@ -217,7 +220,7 @@ static void vc_info(struct atm_vcc *vcc,char *buf)
default:
here += sprintf(here,"%3d",vcc->family);
}
- here += sprintf(here," %04x %5d %7d/%7d %7d/%7d\n",vcc->flags,
+ here += sprintf(here," %04x %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
vcc->reply,
atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
@@ -583,7 +586,7 @@ int __init atm_proc_init(void)
struct proc_dir_entry *devices = NULL,*pvc = NULL,*svc = NULL;
struct proc_dir_entry *arp = NULL,*lec = NULL,*vc = NULL;
- atm_proc_root = proc_mkdir("atm", &proc_root);
+ atm_proc_root = proc_mkdir("net/atm",NULL);
if (!atm_proc_root)
return -ENOMEM;
CREATE_ENTRY(devices);
@@ -605,6 +608,6 @@ cleanup:
if (arp) remove_proc_entry("arp",atm_proc_root);
if (lec) remove_proc_entry("lec",atm_proc_root);
if (vc) remove_proc_entry("vc",atm_proc_root);
- remove_proc_entry("atm",&proc_root);
+ remove_proc_entry("net/atm",NULL);
return -ENOMEM;
}
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index 4b6817eb9..2493f04aa 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -1,6 +1,6 @@
/* net/atm/pvc.c - ATM PVC sockets */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/config.h>
@@ -13,6 +13,7 @@
#include <linux/kernel.h> /* printk */
#include <linux/init.h>
#include <linux/skbuff.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* for sock_no_* */
#ifdef CONFIG_ATM_CLIP
#include <net/atmclip.h>
@@ -42,8 +43,8 @@ static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr,
addr = (struct sockaddr_atmpvc *) sockaddr;
if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT;
vcc = ATM_SD(sock);
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
- if (vcc->flags & ATM_VF_PARTIAL) {
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
+ if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi;
if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci;
}
@@ -65,7 +66,7 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
struct sockaddr_atmpvc *addr;
struct atm_vcc *vcc = ATM_SD(sock);
- if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR)) return -ENOTCONN;
+ if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN;
*sockaddr_len = sizeof(struct sockaddr_atmpvc);
addr = (struct sockaddr_atmpvc *) sockaddr;
addr->sap_family = AF_ATMPVC;
diff --git a/net/atm/raw.c b/net/atm/raw.c
index 355382502..0899c9f93 100644
--- a/net/atm/raw.c
+++ b/net/atm/raw.c
@@ -38,16 +38,34 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
{
DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb_any(skb);
wake_up(&vcc->wsleep);
}
+static int atm_send_aal0(struct atm_vcc *vcc,struct sk_buff *skb)
+{
+ /*
+ * Note that if vpi/vci are _ANY or _UNSPEC the below will
+ * still work
+ */
+ if (!capable(CAP_NET_ADMIN) &&
+ (((u32 *) skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) !=
+ ((vcc->vpi << ATM_HDR_VPI_SHIFT) | (vcc->vci << ATM_HDR_VCI_SHIFT)))
+ {
+ kfree_skb(skb);
+ return -EADDRNOTAVAIL;
+ }
+ return vcc->dev->ops->send(vcc,skb);
+}
+
+
int atm_init_aal0(struct atm_vcc *vcc)
{
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
+ vcc->send = atm_send_aal0;
return 0;
}
@@ -57,6 +75,7 @@ int atm_init_aal34(struct atm_vcc *vcc)
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
+ vcc->send = vcc->dev->ops->send;
return 0;
}
@@ -66,6 +85,7 @@ int atm_init_aal5(struct atm_vcc *vcc)
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
+ vcc->send = vcc->dev->ops->send;
return 0;
}
diff --git a/net/atm/resources.c b/net/atm/resources.c
index 116682f5b..9502367ef 100644
--- a/net/atm/resources.c
+++ b/net/atm/resources.c
@@ -1,6 +1,6 @@
/* net/atm/resources.c - Staticly allocated resources */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/config.h>
@@ -9,6 +9,7 @@
#include <linux/atmdev.h>
#include <linux/kernel.h> /* for barrier */
#include <linux/module.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* for struct sock */
#include <asm/segment.h> /* for get_fs_long and put_fs_long */
@@ -66,7 +67,7 @@ struct atm_dev *atm_find_dev(int number)
struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
- int number,unsigned long flags)
+ int number,atm_dev_flags_t *flags)
{
struct atm_dev *dev;
@@ -91,8 +92,9 @@ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
dev->dev_data = NULL;
barrier();
dev->ops = ops;
- dev->flags = flags;
- memset((void *) &dev->stats,0,sizeof(struct atm_dev_stats));
+ if (flags) dev->flags = *flags;
+ else memset(&dev->flags,0,sizeof(dev->flags));
+ memset((void *) &dev->stats,0,sizeof(dev->stats));
#ifdef CONFIG_PROC_FS
if (ops->proc_read)
if (atm_proc_dev_register(dev) < 0) {
@@ -118,7 +120,7 @@ void atm_dev_deregister(struct atm_dev *dev)
void shutdown_atm_dev(struct atm_dev *dev)
{
if (dev->vccs) {
- dev->flags |= ATM_DF_CLOSE;
+ set_bit(ATM_DF_CLOSE,&dev->flags);
return;
}
if (dev->ops->dev_close) dev->ops->dev_close(dev);
@@ -165,7 +167,7 @@ static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
if (vcc->next) vcc->next->prev = vcc->prev;
else if (vcc->dev) vcc->dev->last = vcc->prev;
if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
- (vcc->dev->flags & ATM_DF_CLOSE))
+ test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
shutdown_atm_dev(vcc->dev);
}
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
index 46e22d50c..0240aa874 100644
--- a/net/atm/signaling.c
+++ b/net/atm/signaling.c
@@ -12,6 +12,7 @@
#include <linux/atmsap.h>
#include <linux/atmsvc.h>
#include <linux/atmdev.h>
+#include <linux/bitops.h>
#include "resources.h"
#include "signaling.h"
@@ -30,29 +31,33 @@
struct atm_vcc *sigd = NULL;
-static wait_queue_head_t sigd_sleep;
+static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
static void sigd_put_skb(struct sk_buff *skb)
{
#ifdef WAIT_FOR_DEMON
static unsigned long silence = 0;
-#endif
+ DECLARE_WAITQUEUE(wait,current);
+ add_wait_queue(&sigd_sleep,&wait);
while (!sigd) {
-#ifdef WAIT_FOR_DEMON
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (time_after(jiffies, silence) || silence == 0) {
printk(KERN_INFO "atmsvc: waiting for signaling demon "
"...\n");
silence = (jiffies+30*HZ)|1;
}
- sleep_on(&sigd_sleep);
+ schedule();
+ }
+ remove_wait_queue(&sigd_sleep,&wait);
#else
+ if (!sigd) {
printk(KERN_WARNING "atmsvc: no signaling demon\n");
kfree_skb(skb);
return;
-#endif
}
+#endif
atm_force_charge(sigd,skb->truesize);
skb_queue_tail(&sigd->recvq,skb);
wake_up(&sigd->sleep);
@@ -63,7 +68,8 @@ static void modify_qos(struct atm_vcc *vcc,struct atmsvc_msg *msg)
{
struct sk_buff *skb;
- if ((vcc->flags & ATM_VF_RELEASED) || !(vcc->flags & ATM_VF_READY))
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ !test_bit(ATM_VF_READY,&vcc->flags))
return;
msg->type = as_error;
if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP;
@@ -114,7 +120,8 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
session_vcc->qos = msg->qos;
break;
case as_error:
- vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_READY);
+ clear_bit(ATM_VF_REGIS,&vcc->flags);
+ clear_bit(ATM_VF_READY,&vcc->flags);
vcc->reply = msg->reply;
break;
case as_indicate:
@@ -133,8 +140,8 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
}
return 0;
case as_close:
- vcc->flags |= ATM_VF_RELEASED;
- vcc->flags &= ~ATM_VF_READY;
+ set_bit(ATM_VF_RELEASED,&vcc->flags);
+ clear_bit(ATM_VF_READY,&vcc->flags);
vcc->reply = msg->reply;
break;
case as_modify:
@@ -177,7 +184,7 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
if (!pvc) memset(&msg->pvc,0,sizeof(msg->pvc));
else msg->pvc = *pvc;
sigd_put_skb(skb);
- if (vcc) vcc->flags |= ATM_VF_REGIS;
+ if (vcc) set_bit(ATM_VF_REGIS,&vcc->flags);
}
@@ -185,8 +192,8 @@ static void purge_vccs(struct atm_vcc *vcc)
{
while (vcc) {
if (vcc->family == PF_ATMSVC &&
- !(vcc->flags & ATM_VF_META)) {
- vcc->flags |= ATM_VF_RELEASED;
+ !test_bit(ATM_VF_META,&vcc->flags)) {
+ set_bit(ATM_VF_RELEASED,&vcc->flags);
vcc->reply = -EUNATCH;
wake_up(&vcc->sleep);
}
@@ -223,7 +230,7 @@ static struct atm_dev sigd_dev = {
999, /* dummy device number */
NULL,NULL, /* pretend not to have any VCCs */
NULL,NULL, /* no data */
- 0, /* no flags */
+ { 0 }, /* no flags */
NULL, /* no local address */
{ 0 } /* no ESI, no statistics */
};
@@ -235,13 +242,8 @@ int sigd_attach(struct atm_vcc *vcc)
DPRINTK("sigd_attach\n");
sigd = vcc;
bind_vcc(vcc,&sigd_dev);
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
wake_up(&sigd_sleep);
return 0;
}
-
-
-void signaling_init(void)
-{
- init_waitqueue_head(&sigd_sleep);
-}
diff --git a/net/atm/signaling.h b/net/atm/signaling.h
index dbb8c21e1..30d5d51d4 100644
--- a/net/atm/signaling.h
+++ b/net/atm/signaling.h
@@ -21,6 +21,5 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
const struct sockaddr_atmsvc *svc);
int sigd_attach(struct atm_vcc *vcc);
-void signaling_init(void);
#endif
diff --git a/net/atm/svc.c b/net/atm/svc.c
index 82ea22072..47b991557 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -17,6 +17,7 @@
#include <linux/atmsap.h>
#include <linux/atmsvc.h>
#include <linux/atmdev.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* for sock_no_* */
#include <asm/uaccess.h>
@@ -59,13 +60,18 @@ static int svc_shutdown(struct socket *sock,int how)
static void svc_disconnect(struct atm_vcc *vcc)
{
+ DECLARE_WAITQUEUE(wait,current);
struct sk_buff *skb;
DPRINTK("svc_disconnect %p\n",vcc);
- if (vcc->flags & ATM_VF_REGIS) {
+ if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
sigd_enq(vcc,as_close,NULL,NULL,NULL);
- while (!(vcc->flags & ATM_VF_RELEASED) && sigd)
- sleep_on(&vcc->sleep);
+ add_wait_queue(&vcc->sleep,&wait);
+ while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
}
/* beware - socket is still in use by atmsigd until the last
as_indicate has been answered */
@@ -75,8 +81,10 @@ static void svc_disconnect(struct atm_vcc *vcc)
the reason */
dev_kfree_skb(skb);
}
- vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED | ATM_VF_CLOSE);
- /* may retry later */
+ clear_bit(ATM_VF_REGIS,&vcc->flags);
+ clear_bit(ATM_VF_RELEASED,&vcc->flags);
+ clear_bit(ATM_VF_CLOSE,&vcc->flags);
+ /* ... may retry later */
}
@@ -87,7 +95,7 @@ static int svc_release(struct socket *sock)
if (!sock->sk) return 0;
vcc = ATM_SD(sock);
DPRINTK("svc_release %p\n",vcc);
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
atm_release_vcc_sk(sock->sk,0);
svc_disconnect(vcc);
/* VCC pointer is used as a reference, so we must not free it
@@ -101,6 +109,7 @@ static int svc_release(struct socket *sock)
static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
int sockaddr_len)
{
+ DECLARE_WAITQUEUE(wait,current);
struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc;
@@ -108,19 +117,25 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
if (sock->state == SS_CONNECTED) return -EISCONN;
if (sock->state != SS_UNCONNECTED) return -EINVAL;
vcc = ATM_SD(sock);
- if (vcc->flags & ATM_VF_SESSION) return -EINVAL;
+ if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
- vcc->flags &= ~ATM_VF_BOUND; /* failing rebind will kill old binding */
+ clear_bit(ATM_VF_BOUND,&vcc->flags);
+ /* failing rebind will kill old binding */
/* @@@ check memory (de)allocation on rebind */
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
vcc->local = *addr;
vcc->reply = WAITING;
sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
- while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep);
- vcc->flags &= ~ATM_VF_REGIS; /* doesn't count */
+ add_wait_queue(&vcc->sleep,&wait);
+ while (vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
+ clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */
if (!sigd) return -EUNATCH;
- if (!vcc->reply) vcc->flags |= ATM_VF_BOUND;
+ if (!vcc->reply) set_bit(ATM_VF_BOUND,&vcc->flags);
return vcc->reply;
}
@@ -128,6 +143,7 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
int sockaddr_len,int flags)
{
+ DECLARE_WAITQUEUE(wait,current);
struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc = ATM_SD(sock);
int error;
@@ -141,11 +157,13 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
if (vcc->reply) return vcc->reply;
}
else {
+ int error;
+
if (sock->state != SS_UNCONNECTED) return -EINVAL;
- if (vcc->flags & ATM_VF_SESSION) return -EINVAL;
+ if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
return -EINVAL;
@@ -158,34 +176,46 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
sock->state = SS_CONNECTING;
return -EINPROGRESS;
}
+ add_wait_queue(&vcc->sleep,&wait);
+ error = 0;
while (vcc->reply == WAITING && sigd) {
- interruptible_sleep_on(&vcc->sleep);
- if (signal_pending(current)) {
- DPRINTK("*ABORT*\n");
- /*
- * This is tricky:
- * Kernel ---close--> Demon
- * Kernel <--close--- Demon
- * or
- * Kernel ---close--> Demon
- * Kernel <--error--- Demon
- * or
- * Kernel ---close--> Demon
- * Kernel <--okay---- Demon
- * Kernel <--close--- Demon
- */
- sigd_enq(vcc,as_close,NULL,NULL,NULL);
- while (vcc->reply == WAITING && sigd)
- sleep_on(&vcc->sleep);
- if (!vcc->reply)
- while (!(vcc->flags & ATM_VF_RELEASED)
- && sigd) sleep_on(&vcc->sleep);
- vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED
- | ATM_VF_CLOSE);
- /* we're gone now but may connect later */
- return -EINTR;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (!signal_pending(current)) continue;
+ DPRINTK("*ABORT*\n");
+ /*
+ * This is tricky:
+ * Kernel ---close--> Demon
+ * Kernel <--close--- Demon
+ * or
+ * Kernel ---close--> Demon
+ * Kernel <--error--- Demon
+ * or
+ * Kernel ---close--> Demon
+ * Kernel <--okay---- Demon
+ * Kernel <--close--- Demon
+ */
+ sigd_enq(vcc,as_close,NULL,NULL,NULL);
+ while (vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
}
+ if (!vcc->reply)
+ while (!test_bit(ATM_VF_RELEASED,&vcc->flags)
+ && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
+ clear_bit(ATM_VF_REGIS,&vcc->flags);
+ clear_bit(ATM_VF_RELEASED,&vcc->flags);
+ clear_bit(ATM_VF_CLOSE,&vcc->flags);
+ /* we're gone now but may connect later */
+ error = -EINTR;
+ break;
}
+ remove_wait_queue(&vcc->sleep,&wait);
+ if (error) return error;
if (!sigd) return -EUNATCH;
if (vcc->reply) return vcc->reply;
}
@@ -209,16 +239,22 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
static int svc_listen(struct socket *sock,int backlog)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *vcc = ATM_SD(sock);
DPRINTK("svc_listen %p\n",vcc);
/* let server handle listen on unbound sockets */
- if (vcc->flags & ATM_VF_SESSION) return -EINVAL;
+ if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
vcc->reply = WAITING;
sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
- while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep);
+ add_wait_queue(&vcc->sleep,&wait);
+ while (vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
- vcc->flags |= ATM_VF_LISTEN;
+ set_bit(ATM_VF_LISTEN,&vcc->flags);
vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
return vcc->reply;
}
@@ -240,18 +276,32 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc);
while (1) {
+ DECLARE_WAITQUEUE(wait,current);
+
+ add_wait_queue(&old_vcc->sleep,&wait);
while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) {
- if (old_vcc->flags & ATM_VF_RELEASED) break;
- if (old_vcc->flags & ATM_VF_CLOSE)
- return old_vcc->reply;
- if (flags & O_NONBLOCK) return -EAGAIN;
- interruptible_sleep_on(&old_vcc->sleep);
- if (signal_pending(current)) return -ERESTARTSYS;
+ if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
+ if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
+ error = old_vcc->reply;
+ break;
+ }
+ if (flags & O_NONBLOCK) {
+ error = -EAGAIN;
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (signal_pending(current)) {
+ error = -ERESTARTSYS;
+ break;
+ }
}
+ remove_wait_queue(&old_vcc->sleep,&wait);
+ if (error) return error;
if (!skb) return -EUNATCH;
msg = (struct atmsvc_msg *) skb->data;
new_vcc->qos = msg->qos;
- new_vcc->flags |= ATM_VF_HASQOS;
+ set_bit(ATM_VF_HASQOS,&new_vcc->flags);
new_vcc->remote = msg->svc;
new_vcc->local = msg->local;
new_vcc->sap = msg->sap;
@@ -267,8 +317,12 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
/* wait should be short, so we ignore the non-blocking flag */
new_vcc->reply = WAITING;
sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
- while (new_vcc->reply == WAITING && sigd)
- sleep_on(&new_vcc->sleep);
+ add_wait_queue(&new_vcc->sleep,&wait);
+ while (new_vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&new_vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
if (!new_vcc->reply) break;
if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply;
@@ -293,6 +347,7 @@ static int svc_getname(struct socket *sock,struct sockaddr *sockaddr,
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_qos save_qos;
vcc->reply = WAITING;
@@ -300,8 +355,13 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
vcc->qos = *qos;
sigd_enq(vcc,as_modify,NULL,NULL,&vcc->local);
vcc->qos = save_qos;
- while (vcc->reply == WAITING && !(vcc->flags & ATM_VF_RELEASED) &&
- sigd) sleep_on(&vcc->sleep);
+ add_wait_queue(&vcc->sleep,&wait);
+ while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
+ && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
return vcc->reply;
}
@@ -317,7 +377,7 @@ static int svc_setsockopt(struct socket *sock,int level,int optname,
return atm_setsockopt(sock,level,optname,optval,optlen);
vcc = ATM_SD(sock);
if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT;
- vcc->flags |= ATM_VF_HASSAP;
+ set_bit(ATM_VF_HASSAP,&vcc->flags);
return 0;
}
@@ -393,6 +453,4 @@ void __init atmsvc_proto_init(struct net_proto *pro)
printk(KERN_ERR "ATMSVC: can't register");
return;
}
- signaling_init();
- init_addr();
}
diff --git a/net/bridge/br.c b/net/bridge/br.c
index ec59ff622..89ee1e0d5 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br.c,v 1.39 2000/02/18 16:47:11 davem Exp $
+ * $Id: br.c,v 1.40 2000/03/21 21:08:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -13,6 +13,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
@@ -23,6 +24,10 @@
#include <asm/uaccess.h>
#include "br_private.h"
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+#include "../atm/lec.h"
+#endif
+
void br_dec_use_count()
{
MOD_DEC_USE_COUNT;
@@ -39,6 +44,12 @@ static int __init br_init(void)
br_handle_frame_hook = br_handle_frame;
br_ioctl_hook = br_ioctl_deviceless_stub;
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ write_lock(&lane_bridge_hook_lock);
+ br_fdb_get_hook = br_fdb_get;
+ br_fdb_put_hook = br_fdb_put;
+ write_unlock(&lane_bridge_hook_lock);
+#endif
register_netdevice_notifier(&br_device_notifier);
return 0;
@@ -59,6 +70,12 @@ static void __exit br_deinit(void)
unregister_netdevice_notifier(&br_device_notifier);
br_call_ioctl_atomic(__br_clear_ioctl_hook);
net_call_rx_atomic(__br_clear_frame_hook);
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ write_lock(&lane_bridge_hook_lock);
+ br_fdb_get_hook = NULL;
+ br_fdb_put_hook = NULL;
+ write_unlock(&lane_bridge_hook_lock);
+#endif
}
EXPORT_NO_SYMBOLS;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index e6fa6b379..fc549d76a 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_input.c,v 1.3 2000/02/24 19:48:06 davem Exp $
+ * $Id: br_input.c,v 1.4 2000/03/21 21:08:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,7 +19,7 @@
#include <linux/if_bridge.h>
#include "br_private.h"
-unsigned char bridge_ula[5] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
+unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
@@ -53,6 +53,8 @@ static void __br_handle_frame(struct sk_buff *skb)
p->state == BR_STATE_DISABLED)
goto freeandout;
+ skb_push(skb, skb->data - skb->mac.raw);
+
if (br->dev.flags & IFF_PROMISC) {
struct sk_buff *skb2;
@@ -81,8 +83,6 @@ static void __br_handle_frame(struct sk_buff *skb)
if (!memcmp(dest, bridge_ula, 5) && !(dest[5] & 0xF0))
goto handle_special_frame;
- skb_push(skb, skb->data - skb->mac.raw);
-
if (p->state == BR_STATE_LEARNING ||
p->state == BR_STATE_FORWARDING)
br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 084e81b4b..76c14be9c 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -4,7 +4,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_private.h,v 1.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_private.h,v 1.2 2000/03/21 21:08:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -114,7 +114,7 @@ struct net_bridge
};
struct notifier_block br_device_notifier;
-unsigned char bridge_ula[5];
+unsigned char bridge_ula[6];
/* br.c */
void br_dec_use_count(void);
diff --git a/net/core/dev.c b/net/core/dev.c
index b09b3b9a4..f14753618 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -651,7 +651,7 @@ int dev_queue_xmit(struct sk_buff *skb)
qdisc_run(dev);
spin_unlock_bh(&dev->queue_lock);
- return ret;
+ return ret == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : ret;
}
/* The device has no queue. Common case for software devices:
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 2823c2c7e..c3f3b29f7 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -1,7 +1,7 @@
/*
* Linux NET3: IP/IP protocol decoder.
*
- * Version: $Id: ipip.c,v 1.31 2000/03/17 14:41:51 davem Exp $
+ * Version: $Id: ipip.c,v 1.32 2000/03/21 06:13:54 davem Exp $
*
* Authors:
* Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 41a61e010..c507acc31 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -21,6 +21,8 @@ OX_OBJS += ip_conntrack_standalone.o
O_OBJS += $(IP_NF_CONNTRACK_OBJ)
else
ifeq ($(CONFIG_IP_NF_CONNTRACK),m)
+ MI_OBJS += $(IP_NF_CONNTRACK_OBJ)
+ MIX_OBJS += ip_conntrack_standalone.o
M_OBJS += ip_conntrack.o
endif
endif
@@ -37,7 +39,7 @@ ifeq ($(CONFIG_IP_NF_FTP),y)
OX_OBJS += ip_conntrack_ftp.o
else
ifeq ($(CONFIG_IP_NF_FTP),m)
- M_OBJS += ip_conntrack_ftp.o
+ MX_OBJS += ip_conntrack_ftp.o
endif
endif
@@ -129,6 +131,8 @@ O_OBJS += ip_nat_rule.o $(IP_NF_NAT_OBJ)
endif
else
ifeq ($(CONFIG_IP_NF_NAT),m)
+ MI_OBJS += ip_nat_rule.o $(IP_NF_NAT_OBJ)
+ MIX_OBJS += ip_nat_standalone.o
M_OBJS += iptable_nat.o
ifeq ($(CONFIG_IP_NF_FTP),m)
M_OBJS += ip_nat_ftp.o
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 9137d13ea..23ccf74cf 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -1,7 +1,4 @@
/* FTP extension for IP connection tracking. */
-#ifdef MODULE
-#define EXPORT_SYMTAB
-#endif
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index ce79c3263..a69be542d 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -7,9 +7,6 @@
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
Public Licence. */
-#ifdef MODULE
-#define EXPORT_SYMTAB
-#endif
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index bf278d6f9..603111063 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -7,9 +7,6 @@
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
Public Licence. */
-#ifdef MODULE
-#define EXPORT_SYMTAB
-#endif
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index d5ca01aa6..532538321 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -491,7 +491,7 @@ netlink_send_peer(ipq_queue_element_t *e)
skb = netlink_build_message(e, &status);
if (skb == NULL)
return status;
- return netlink_unicast(nfnl, skb, nlq->peer.pid, 0);
+ return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
}
static struct sk_buff *
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index c683f2f23..afab828fb 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -5,7 +5,7 @@
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.82 2000/03/17 14:41:52 davem Exp $
+ * Version: $Id: route.c,v 1.83 2000/03/23 05:34:13 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -205,9 +205,6 @@ static __inline__ unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos)
return (hash^(hash>>8)) & rt_hash_mask;
}
-#ifndef CONFIG_PROC_FS
-static int rt_cache_get_info(char *buffer, char **start, off_t offset, int length) { return 0; }
-#else
static int rt_cache_get_info(char *buffer, char **start, off_t offset, int length)
{
int len=0;
@@ -267,7 +264,6 @@ done:
len = length;
return len;
}
-#endif
static __inline__ void rt_free(struct rtable *rt)
{
@@ -2204,7 +2200,6 @@ ctl_table ipv4_route_table[] = {
#ifdef CONFIG_NET_CLS_ROUTE
struct ip_rt_acct *ip_rt_acct;
-#ifdef CONFIG_PROC_FS
static int ip_rt_acct_read(char *buffer, char **start, off_t offset,
int length, int *eof, void *data)
{
@@ -2243,7 +2238,6 @@ static int ip_rt_acct_read(char *buffer, char **start, off_t offset,
return 0;
}
#endif
-#endif
void __init ip_rt_init(void)
{
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 7d3e49bed..471eb9e70 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.164 2000/03/08 19:36:40 davem Exp $
+ * Version: $Id: tcp.c,v 1.165 2000/03/23 05:30:32 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1337,20 +1337,21 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
break;
}
- if (sk->done) {
- copied = -ENOTCONN;
+ if (sk->shutdown & RCV_SHUTDOWN) {
+ if (!(flags&MSG_PEEK))
+ sk->done = 1;
break;
}
if (sk->state == TCP_CLOSE) {
- if (!(flags&MSG_PEEK))
+ if (sk->done) {
+ copied = -ENOTCONN;
+ break;
+ } else if (!(flags&MSG_PEEK))
sk->done = 1;
break;
}
- if (sk->shutdown & RCV_SHUTDOWN)
- break;
-
if (!timeo) {
copied = -EAGAIN;
break;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index d431c682c..575ec3036 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.189 2000/02/27 19:52:55 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.190 2000/03/21 19:34:23 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1944,10 +1944,8 @@ queue_and_out:
if (eaten) {
kfree_skb(skb);
- } else if (!sk->dead) {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket,1, POLL_IN);
- }
+ } else
+ sk->data_ready(sk, 0);
return;
}
@@ -2531,8 +2529,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
/* FIN bit check is not done since if FIN is set in
* this frame, the pred_flags won't match up. -DaveM
*/
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket,1, POLL_IN);
+ sk->data_ready(sk, 0);
}
tcp_event_data_recv(tp, skb);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1edee9f51..456f12968 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.202 2000/03/17 14:41:53 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.203 2000/03/22 17:55:03 davem Exp $
*
* IPv4 specific functions
*
@@ -2015,7 +2015,7 @@ static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i)
timer_expires = jiffies;
sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p %u %u %u %u",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u",
i, src, srcp, dest, destp, sp->state,
tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
timer_active, timer_expires-jiffies,
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index c52797d70..8b8db60d8 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.36 2000/03/17 14:42:08 davem Exp $
+ * $Id: sit.c,v 1.37 2000/03/21 06:14:00 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
index 3c9ff35da..1cef4d5d8 100644
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Jun 7 10:25:11 1999
- * Modified at: Tue Dec 14 15:26:30 1999
+ * Modified at: Sun Jan 30 14:32:03 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1999-2000 Dag Brattli, 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
@@ -40,19 +40,27 @@
#include <net/irda/ircomm_param.h>
-static int ircomm_param_service_type(void *instance, param_t *param, int get);
-static int ircomm_param_port_type(void *instance, param_t *param, int get);
-static int ircomm_param_port_name(void *instance, param_t *param, int get);
-static int ircomm_param_service_type(void *instance, param_t *param, int get);
-static int ircomm_param_data_rate(void *instance, param_t *param, int get);
-static int ircomm_param_data_format(void *instance, param_t *param, int get);
-static int ircomm_param_flow_control(void *instance, param_t *param, int get);
-static int ircomm_param_xon_xoff(void *instance, param_t *param, int get);
-static int ircomm_param_enq_ack(void *instance, param_t *param, int get);
-static int ircomm_param_line_status(void *instance, param_t *param, int get);
-static int ircomm_param_dte(void *instance, param_t *param, int get);
-static int ircomm_param_dce(void *instance, param_t *param, int get);
-static int ircomm_param_poll(void *instance, param_t *param, int get);
+static int ircomm_param_service_type(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_port_type(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_port_name(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_service_type(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_data_rate(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_data_format(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_flow_control(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get);
+static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get);
+static int ircomm_param_line_status(void *instance, irda_param_t *param,
+ int get);
+static int ircomm_param_dte(void *instance, irda_param_t *param, int get);
+static int ircomm_param_dce(void *instance, irda_param_t *param, int get);
+static int ircomm_param_poll(void *instance, irda_param_t *param, int get);
static pi_minor_info_t pi_minor_call_table_common[] = {
{ ircomm_param_service_type, PV_INT_8_BITS },
@@ -170,7 +178,8 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
* query and then the remote device sends its initial paramters
*
*/
-static int ircomm_param_service_type(void *instance, param_t *param, int get)
+static int ircomm_param_service_type(void *instance, irda_param_t *param,
+ int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
__u8 service_type = param->pv.b; /* We know it's a one byte integer */
@@ -229,7 +238,7 @@ static int ircomm_param_service_type(void *instance, param_t *param, int get)
* Since we only advertise serial service, this parameter should only
* be equal to IRCOMM_SERIAL.
*/
-static int ircomm_param_port_type(void *instance, param_t *param, int get)
+static int ircomm_param_port_type(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
@@ -253,7 +262,7 @@ static int ircomm_param_port_type(void *instance, param_t *param, int get)
* Exchange port name
*
*/
-static int ircomm_param_port_name(void *instance, param_t *param, int get)
+static int ircomm_param_port_name(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
@@ -276,7 +285,7 @@ static int ircomm_param_port_name(void *instance, param_t *param, int get)
* Exchange data rate to be used in this settings
*
*/
-static int ircomm_param_data_rate(void *instance, param_t *param, int get)
+static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
@@ -299,7 +308,8 @@ static int ircomm_param_data_rate(void *instance, param_t *param, int get)
* Exchange data format to be used in this settings
*
*/
-static int ircomm_param_data_format(void *instance, param_t *param, int get)
+static int ircomm_param_data_format(void *instance, irda_param_t *param,
+ int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
@@ -320,7 +330,8 @@ static int ircomm_param_data_format(void *instance, param_t *param, int get)
* Exchange flow control settings to be used in this settings
*
*/
-static int ircomm_param_flow_control(void *instance, param_t *param, int get)
+static int ircomm_param_flow_control(void *instance, irda_param_t *param,
+ int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
@@ -343,7 +354,7 @@ static int ircomm_param_flow_control(void *instance, param_t *param, int get)
* Exchange XON/XOFF characters
*
*/
-static int ircomm_param_xon_xoff(void *instance, param_t *param, int get)
+static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
@@ -370,7 +381,7 @@ static int ircomm_param_xon_xoff(void *instance, param_t *param, int get)
* Exchange ENQ/ACK characters
*
*/
-static int ircomm_param_enq_ack(void *instance, param_t *param, int get)
+static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
@@ -397,7 +408,8 @@ static int ircomm_param_enq_ack(void *instance, param_t *param, int get)
*
*
*/
-static int ircomm_param_line_status(void *instance, param_t *param, int get)
+static int ircomm_param_line_status(void *instance, irda_param_t *param,
+ int get)
{
IRDA_DEBUG(2, __FUNCTION__ "(), not impl.\n");
@@ -410,7 +422,7 @@ static int ircomm_param_line_status(void *instance, param_t *param, int get)
* If we get here, there must be some sort of null-modem connection, and
* we are probably working in server mode as well.
*/
-static int ircomm_param_dte(void *instance, param_t *param, int get)
+static int ircomm_param_dte(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
__u8 dte;
@@ -453,7 +465,7 @@ static int ircomm_param_dte(void *instance, param_t *param, int get)
*
*
*/
-static int ircomm_param_dce(void *instance, param_t *param, int get)
+static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
__u8 dce;
@@ -485,7 +497,7 @@ static int ircomm_param_dce(void *instance, param_t *param, int get)
* Called when the peer device is polling for the line settings
*
*/
-static int ircomm_param_poll(void *instance, param_t *param, int get)
+static int ircomm_param_poll(void *instance, irda_param_t *param, int get)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index 9968e0e95..ca2903316 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -254,7 +254,7 @@ int irda_device_is_receiving(struct net_device *dev)
return req.ifr_receiving;
}
-void irda_task_next_state(struct irda_task *task, TASK_STATE state)
+void irda_task_next_state(struct irda_task *task, IRDA_TASK_STATE state)
{
IRDA_DEBUG(2, __FUNCTION__ "(), state = %s\n", task_state[state]);
@@ -354,8 +354,9 @@ int irda_task_kick(struct irda_task *task)
* called from interrupt context, so it's not possible to use
* schedule_timeout()
*/
-struct irda_task *irda_task_execute(void *instance, TASK_CALLBACK function,
- TASK_CALLBACK finished,
+struct irda_task *irda_task_execute(void *instance,
+ IRDA_TASK_CALLBACK function,
+ IRDA_TASK_CALLBACK finished,
struct irda_task *parent, void *param)
{
struct irda_task *task;
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 5ee81ec03..32b09e25d 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -6,13 +6,13 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Oct 15 08:37:58 1998
- * Modified at: Thu Nov 4 14:50:52 1999
+ * Modified at: Tue Mar 21 09:06:41 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
* slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
- * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1998-2000 Dag Brattli, 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
@@ -25,6 +25,7 @@
*
********************************************************************/
+#include <linux/config.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/inetdevice.h>
@@ -331,6 +332,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
* is useful if we have changed access points on the same
* subnet.
*/
+#ifdef CONFIG_INET
IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
in_dev = in_dev_get(dev);
if (in_dev == NULL)
@@ -345,6 +347,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
NULL, dev->dev_addr, NULL);
read_unlock(&in_dev->lock);
in_dev_put(in_dev);
+#endif /* CONFIG_INET */
}
/*
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 46c2ae85e..e9d120efb 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -60,7 +60,8 @@ static void irttp_flush_queues(struct tsap_cb *self);
static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
-static int irttp_param_max_sdu_size(void *instance, param_t *param, int get);
+static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,
+ int get);
/* Information for parsing parameters in IrTTP */
static pi_minor_info_t pi_minor_call_table[] = {
@@ -1405,7 +1406,8 @@ static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
* will be called both when this parameter needs to be inserted into, and
* extracted from the connect frames
*/
-static int irttp_param_max_sdu_size(void *instance, param_t *param, int get)
+static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,
+ int get)
{
struct tsap_cb *self;
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
index 263c2e2a4..b43bbd70e 100644
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Jun 7 10:25:11 1999
- * Modified at: Tue Dec 14 16:03:57 1999
+ * Modified at: Sun Jan 30 14:08:39 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1999-2000 Dag Brattli, 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
@@ -78,7 +78,7 @@ static PV_HANDLER pv_insert_table[] = {
static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi,
PV_TYPE type, PI_HANDLER func)
{
- param_t p;
+ irda_param_t p;
int ret;
p.pi = pi;
@@ -105,7 +105,7 @@ static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi,
static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi,
PV_TYPE type, PI_HANDLER func)
{
- param_t p;
+ irda_param_t p;
int ret;
/* Extract values anyway, since handler may need them */
@@ -129,7 +129,7 @@ static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi,
static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
PV_TYPE type, PI_HANDLER func)
{
- param_t p;
+ irda_param_t p;
int n = 0;
int err;
@@ -202,7 +202,7 @@ static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
PV_TYPE type, PI_HANDLER func)
{
- param_t p;
+ irda_param_t p;
int n = 0;
int err;
@@ -273,7 +273,7 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
PV_TYPE type, PI_HANDLER func)
{
char str[33];
- param_t p;
+ irda_param_t p;
int err;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -319,7 +319,7 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
PV_TYPE type, PI_HANDLER func)
{
- param_t p;
+ irda_param_t p;
p.pi = pi; /* In case handler needs to know */
p.pl = buf[1]; /* Extract lenght of value */
@@ -346,10 +346,10 @@ static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
*/
int irda_param_pack(__u8 *buf, char *fmt, ...)
{
+ irda_pv_t arg;
va_list args;
char *p;
int n = 0;
- pv_t arg;
va_start(args, fmt);
@@ -392,10 +392,10 @@ int irda_param_pack(__u8 *buf, char *fmt, ...)
*/
int irda_param_unpack(__u8 *buf, char *fmt, ...)
{
+ irda_pv_t arg;
va_list args;
char *p;
int n = 0;
- pv_t arg;
va_start(args, fmt);
diff --git a/net/irda/qos.c b/net/irda/qos.c
index 2c2c39b85..10a7765cb 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -6,10 +6,10 @@
* Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Sep 9 00:00:26 1997
- * Modified at: Sun Dec 12 13:47:09 1999
+ * Modified at: Sun Jan 30 14:29:16 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
+ * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -43,13 +43,18 @@
#define CI_BZIP2 27 /* Random pick */
#endif
-static int irlap_param_baud_rate(void *instance, param_t *param, int get);
-static int irlap_param_link_disconnect(void *instance, param_t *parm, int get);
-static int irlap_param_max_turn_time(void *instance, param_t *param, int get);
-static int irlap_param_data_size(void *instance, param_t *param, int get);
-static int irlap_param_window_size(void *instance, param_t *param, int get);
-static int irlap_param_additional_bofs(void *instance, param_t *parm, int get);
-static int irlap_param_min_turn_time(void *instance, param_t *param, int get);
+static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
+static int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
+ int get);
+static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
+ int get);
+static int irlap_param_data_size(void *instance, irda_param_t *param, int get);
+static int irlap_param_window_size(void *instance, irda_param_t *param,
+ int get);
+static int irlap_param_additional_bofs(void *instance, irda_param_t *parm,
+ int get);
+static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
+ int get);
__u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
__u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
@@ -345,7 +350,7 @@ int irlap_insert_qos_negotiation_params(struct irlap_cb *self,
* Negotiate data-rate
*
*/
-static int irlap_param_baud_rate(void *instance, param_t *param, int get)
+static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get)
{
__u16 final;
@@ -380,7 +385,8 @@ static int irlap_param_baud_rate(void *instance, param_t *param, int get)
* Negotiate link disconnect/threshold time.
*
*/
-static int irlap_param_link_disconnect(void *instance, param_t *param, int get)
+static int irlap_param_link_disconnect(void *instance, irda_param_t *param,
+ int get)
{
__u16 final;
@@ -413,7 +419,8 @@ static int irlap_param_link_disconnect(void *instance, param_t *param, int get)
* will be negotiated independently for each station
*
*/
-static int irlap_param_max_turn_time(void *instance, param_t *param, int get)
+static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
+ int get)
{
struct irlap_cb *self = (struct irlap_cb *) instance;
@@ -435,7 +442,7 @@ static int irlap_param_max_turn_time(void *instance, param_t *param, int get)
* will be negotiated independently for each station
*
*/
-static int irlap_param_data_size(void *instance, param_t *param, int get)
+static int irlap_param_data_size(void *instance, irda_param_t *param, int get)
{
struct irlap_cb *self = (struct irlap_cb *) instance;
@@ -457,7 +464,8 @@ static int irlap_param_data_size(void *instance, param_t *param, int get)
* will be negotiated independently for each station
*
*/
-static int irlap_param_window_size(void *instance, param_t *param, int get)
+static int irlap_param_window_size(void *instance, irda_param_t *param,
+ int get)
{
struct irlap_cb *self = (struct irlap_cb *) instance;
@@ -478,7 +486,7 @@ static int irlap_param_window_size(void *instance, param_t *param, int get)
* Negotiate additional BOF characters. This is a type 1 parameter and
* will be negotiated independently for each station.
*/
-static int irlap_param_additional_bofs(void *instance, param_t *param, int get)
+static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get)
{
struct irlap_cb *self = (struct irlap_cb *) instance;
@@ -499,7 +507,8 @@ static int irlap_param_additional_bofs(void *instance, param_t *param, int get)
* Negotiate the minimum turn around time. This is a type 1 parameter and
* will be negotiated independently for each station
*/
-static int irlap_param_min_turn_time(void *instance, param_t *param, int get)
+static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
+ int get)
{
struct irlap_cb *self = (struct irlap_cb *) instance;
diff --git a/net/khttpd/main.c b/net/khttpd/main.c
index 418037907..a9568ef0d 100644
--- a/net/khttpd/main.c
+++ b/net/khttpd/main.c
@@ -198,7 +198,6 @@ static int ManagementDaemon(void *unused)
DECLARE_WAIT_QUEUE_HEAD(WQ);
- MOD_INC_USE_COUNT;
sprintf(current->comm,"khttpd manager");
lock_kernel(); /* This seems to be required for exit_mm */
@@ -347,6 +346,8 @@ static int ManagementDaemon(void *unused)
int __init khttpd_init(void)
{
int I;
+
+ MOD_INC_USE_COUNT;
I=0;
while (I<CONFIG_KHTTPD_NUMCPU)
diff --git a/net/khttpd/security.c b/net/khttpd/security.c
index bd578941d..7e0780a26 100644
--- a/net/khttpd/security.c
+++ b/net/khttpd/security.c
@@ -113,10 +113,11 @@ struct file *OpenFileForSecurity(char *Filename)
#endif
/* Rule no. 3 -- Does the file exist ? */
-
+ lock_kernel();
filp = filp_open(Filename, 0, O_RDONLY, NULL);
+ unlock_kernel();
if ((IS_ERR(filp))||(filp==NULL)||(filp->f_dentry==NULL))
{
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index a3b25f2a7..021d7d658 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -276,7 +276,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
goto err_out;
}
/* @@@ should check if the socket is really operational or we'll crash
- on vcc->dev->ops->send */
+ on vcc->send */
if (classid) {
if (TC_H_MAJ(classid ^ sch->handle)) {
DPRINTK("atm_tc_change: classid mismatch\n");
@@ -449,8 +449,21 @@ static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch)
sch->stats.packets++;
flow->stats.bytes += skb->len;
flow->stats.packets++;
- sch->q.qlen++;
- return 0;
+ /*
+ * Okay, this may seem weird. We pretend we've dropped the packet if
+ * it goes via ATM. The reason for this is that the outer qdisc
+ * expects to be able to q->dequeue the packet later on if we return
+ * success at this place. Also, sch->q.qdisc needs to reflect whether
+ * there is a packet egligible for dequeuing or not. Note that the
+ * statistics of the outer qdisc are necessarily wrong because of all
+ * this. There's currently no correct solution for this.
+ */
+ if (flow == &p->link) {
+ sch->q.qlen++;
+ return 0;
+ }
+ tasklet_schedule(&p->task);
+ return NET_XMIT_BYPASS;
}
@@ -477,11 +490,9 @@ static void sch_atm_dequeue(unsigned long data)
*/
while ((skb = flow->q->dequeue(flow->q))) {
if (!atm_may_send(flow->vcc,skb->truesize)) {
- if (flow->q->ops->requeue(skb,flow->q))
- sch->q.qlen--;
+ (void) flow->q->ops->requeue(skb,flow->q);
break;
}
- sch->q.qlen--;
D2PRINTK("atm_tc_deqeueue: sending on class %p\n",flow);
/* remove any LL header somebody else has attached */
skb_pull(skb,(char *) skb->nh.iph-(char *) skb->data);
@@ -501,7 +512,7 @@ static void sch_atm_dequeue(unsigned long data)
atomic_add(skb->truesize,&flow->vcc->tx_inuse);
ATM_SKB(skb)->iovcnt = 0;
/* atm.atm_options are already set by atm_tc_enqueue */
- (void) flow->vcc->dev->ops->send(flow->vcc,skb);
+ (void) flow->vcc->send(flow->vcc,skb);
}
}
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index af9923ec8..b8c0a7be8 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -4,12 +4,9 @@
* Generic RPC authentication API.
*
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
- *
- * Modified May 1999, Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
*/
#include <linux/types.h>
-#include <linux/string.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/errno.h>
@@ -84,6 +81,15 @@ rpcauth_init_credcache(struct rpc_auth *auth)
auth->au_nextgc = jiffies + (auth->au_expire >> 1);
}
+static inline void
+rpcauth_crdestroy(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+ if (auth->au_ops->crdestroy)
+ auth->au_ops->crdestroy(cred);
+ else
+ rpc_free(cred);
+}
+
/*
* Clear the RPC credential cache
*/
@@ -115,18 +121,15 @@ static void
rpcauth_gc_credcache(struct rpc_auth *auth)
{
struct rpc_cred **q, *cred, *free = NULL;
- int i, safe = 0;
+ int i;
dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
spin_lock(&rpc_credcache_lock);
for (i = 0; i < RPC_CREDCACHE_NR; i++) {
q = &auth->au_credcache[i];
while ((cred = *q) != NULL) {
- if (++safe > 500) {
- printk("RPC: rpcauth_gc_credcache looping!\n");
- break;
- }
- if (!cred->cr_count && time_before(cred->cr_expire, jiffies)) {
+ if (!cred->cr_count &&
+ time_before(cred->cr_expire, jiffies)) {
*q = cred->cr_next;
cred->cr_next = free;
free = cred;
@@ -138,7 +141,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth)
spin_unlock(&rpc_credcache_lock);
while ((cred = free) != NULL) {
free = cred->cr_next;
- rpc_free(cred);
+ rpcauth_crdestroy(auth, cred);
}
auth->au_nextgc = jiffies + auth->au_expire;
}
@@ -146,7 +149,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth)
/*
* Insert credential into cache
*/
-inline void
+void
rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
{
int nr;
@@ -155,8 +158,8 @@ rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
spin_lock(&rpc_credcache_lock);
cred->cr_next = auth->au_credcache[nr];
auth->au_credcache[nr] = cred;
- cred->cr_expire = jiffies + auth->au_expire;
cred->cr_count++;
+ cred->cr_expire = jiffies + auth->au_expire;
spin_unlock(&rpc_credcache_lock);
}
@@ -164,13 +167,13 @@ rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
* Look up a process' credentials in the authentication cache
*/
static struct rpc_cred *
-rpcauth_lookup_credcache(struct rpc_task *task)
+rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
{
- struct rpc_auth *auth = task->tk_auth;
struct rpc_cred **q, *cred = NULL;
- int nr;
+ int nr = 0;
- nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR);
+ if (!(taskflags & RPC_TASK_ROOTCREDS))
+ nr = current->uid % RPC_CREDCACHE_NR;
if (time_before(auth->au_nextgc, jiffies))
rpcauth_gc_credcache(auth);
@@ -178,7 +181,8 @@ rpcauth_lookup_credcache(struct rpc_task *task)
spin_lock(&rpc_credcache_lock);
q = &auth->au_credcache[nr];
while ((cred = *q) != NULL) {
- if (auth->au_ops->crmatch(task, cred)) {
+ if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) &&
+ auth->au_ops->crmatch(cred, taskflags)) {
*q = cred->cr_next;
break;
}
@@ -187,7 +191,7 @@ rpcauth_lookup_credcache(struct rpc_task *task)
spin_unlock(&rpc_credcache_lock);
if (!cred)
- cred = auth->au_ops->crcreate(task);
+ cred = auth->au_ops->crcreate(taskflags);
if (cred)
rpcauth_insert_credcache(auth, cred);
@@ -198,7 +202,7 @@ rpcauth_lookup_credcache(struct rpc_task *task)
/*
* Remove cred handle from cache
*/
-static inline void
+static void
rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
{
struct rpc_cred **q, *cr;
@@ -210,7 +214,8 @@ rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
while ((cr = *q) != NULL) {
if (cred == cr) {
*q = cred->cr_next;
- return;
+ cred->cr_next = NULL;
+ break;
}
q = &cred->cr_next;
}
@@ -218,58 +223,78 @@ rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
}
struct rpc_cred *
-rpcauth_lookupcred(struct rpc_task *task)
+rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
+{
+ dprintk("RPC: looking up %s cred\n",
+ auth->au_ops->au_name);
+ return rpcauth_lookup_credcache(auth, taskflags);
+}
+
+struct rpc_cred *
+rpcauth_bindcred(struct rpc_task *task)
{
+ struct rpc_auth *auth = task->tk_auth;
+
dprintk("RPC: %4d looking up %s cred\n",
task->tk_pid, task->tk_auth->au_ops->au_name);
- return task->tk_cred = rpcauth_lookup_credcache(task);
+ task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, task->tk_flags);
+ if (task->tk_msg.rpc_cred == 0)
+ task->tk_status = -ENOMEM;
+ return task->tk_msg.rpc_cred;
}
int
-rpcauth_matchcred(struct rpc_task *task, struct rpc_cred *cred)
+rpcauth_matchcred(struct rpc_auth *auth, struct rpc_cred *cred, int taskflags)
{
- struct rpc_auth *auth = task->tk_auth;
-
- dprintk("RPC: %4d matching %s cred %p\n",
- task->tk_pid, auth->au_ops->au_name, task->tk_cred);
- return auth->au_ops->crmatch(task, cred);
+ dprintk("RPC: matching %s cred %d\n",
+ auth->au_ops->au_name, taskflags);
+ return auth->au_ops->crmatch(cred, taskflags);
}
void
rpcauth_holdcred(struct rpc_task *task)
{
dprintk("RPC: %4d holding %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred);
- if (task->tk_cred)
- task->tk_cred->cr_count++;
+ task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
+ if (task->tk_msg.rpc_cred) {
+ task->tk_msg.rpc_cred->cr_count++;
+ task->tk_msg.rpc_cred->cr_expire = jiffies + task->tk_auth->au_expire;
+ }
}
void
-rpcauth_releasecred(struct rpc_task *task)
+rpcauth_releasecred(struct rpc_auth *auth, struct rpc_cred *cred)
{
- struct rpc_auth *auth = task->tk_auth;
- struct rpc_cred *cred;
-
- dprintk("RPC: %4d releasing %s cred %p\n",
- task->tk_pid, auth->au_ops->au_name, task->tk_cred);
- if ((cred = task->tk_cred) != NULL) {
+ if (cred != NULL && cred->cr_count > 0) {
cred->cr_count--;
if (cred->cr_flags & RPCAUTH_CRED_DEAD) {
rpcauth_remove_credcache(auth, cred);
if (!cred->cr_count)
- auth->au_ops->crdestroy(cred);
+ rpcauth_crdestroy(auth, cred);
}
- task->tk_cred = NULL;
}
}
+void
+rpcauth_unbindcred(struct rpc_task *task)
+{
+ struct rpc_auth *auth = task->tk_auth;
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+
+ dprintk("RPC: %4d releasing %s cred %p\n",
+ task->tk_pid, auth->au_ops->au_name, cred);
+
+ rpcauth_releasecred(auth, cred);
+ task->tk_msg.rpc_cred = NULL;
+}
+
u32 *
rpcauth_marshcred(struct rpc_task *task, u32 *p)
{
struct rpc_auth *auth = task->tk_auth;
dprintk("RPC: %4d marshaling %s cred %p\n",
- task->tk_pid, auth->au_ops->au_name, task->tk_cred);
+ task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
return auth->au_ops->crmarshal(task, p,
task->tk_flags & RPC_CALL_REALUID);
}
@@ -280,7 +305,7 @@ rpcauth_checkverf(struct rpc_task *task, u32 *p)
struct rpc_auth *auth = task->tk_auth;
dprintk("RPC: %4d validating %s cred %p\n",
- task->tk_pid, auth->au_ops->au_name, task->tk_cred);
+ task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
return auth->au_ops->crvalidate(task, p);
}
@@ -290,7 +315,7 @@ rpcauth_refreshcred(struct rpc_task *task)
struct rpc_auth *auth = task->tk_auth;
dprintk("RPC: %4d refreshing %s cred %p\n",
- task->tk_pid, auth->au_ops->au_name, task->tk_cred);
+ task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
task->tk_status = auth->au_ops->crrefresh(task);
return task->tk_status;
}
@@ -299,14 +324,14 @@ void
rpcauth_invalcred(struct rpc_task *task)
{
dprintk("RPC: %4d invalidating %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred);
- if (task->tk_cred)
- task->tk_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+ task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
+ if (task->tk_msg.rpc_cred)
+ task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
}
int
rpcauth_uptodatecred(struct rpc_task *task)
{
- return !(task->tk_cred) ||
- (task->tk_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
+ return !(task->tk_msg.rpc_cred) ||
+ (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
}
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index be6d19637..d2e645acd 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -38,6 +38,7 @@ static void
nul_destroy(struct rpc_auth *auth)
{
dprintk("RPC: destroying NULL authenticator %p\n", auth);
+ rpcauth_free_credcache(auth);
rpc_free(auth);
}
@@ -45,15 +46,12 @@ nul_destroy(struct rpc_auth *auth)
* Create NULL creds for current process
*/
static struct rpc_cred *
-nul_create_cred(struct rpc_task *task)
+nul_create_cred(int flags)
{
struct rpc_cred *cred;
- if (!(cred = (struct rpc_cred *) rpc_malloc(task, sizeof(*cred)))) {
- task->tk_status = -ENOMEM;
+ if (!(cred = (struct rpc_cred *) rpc_allocate(flags, sizeof(*cred))))
return NULL;
- }
-
cred->cr_count = 0;
cred->cr_flags = RPCAUTH_CRED_UPTODATE;
@@ -73,7 +71,7 @@ nul_destroy_cred(struct rpc_cred *cred)
* Match cred handle against current process
*/
static int
-nul_match(struct rpc_task *task, struct rpc_cred *cred)
+nul_match(struct rpc_cred *cred, int taskflags)
{
return 1;
}
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 6596085b3..8033ed6c1 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -4,12 +4,9 @@
* UNIX-style authentication; no AUTH_SHORT support
*
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
- *
- * Modified May 1999 Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
*/
#include <linux/types.h>
-#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/socket.h>
#include <linux/in.h>
@@ -63,7 +60,7 @@ unx_destroy(struct rpc_auth *auth)
}
static struct rpc_cred *
-unx_create_cred(struct rpc_task *task)
+unx_create_cred(int flags)
{
struct unx_cred *cred;
int i;
@@ -71,14 +68,12 @@ unx_create_cred(struct rpc_task *task)
dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
current->uid, current->gid);
- if (!(cred = (struct unx_cred *) rpc_malloc(task, sizeof(*cred)))) {
- task->tk_status = -ENOMEM;
+ if (!(cred = (struct unx_cred *) rpc_allocate(flags, sizeof(*cred))))
return NULL;
- }
cred->uc_count = 0;
cred->uc_flags = RPCAUTH_CRED_UPTODATE;
- if (RPC_DO_ROOTOVERRIDE(task)) {
+ if (flags & RPC_TASK_ROOTCREDS) {
cred->uc_uid = cred->uc_fsuid = 0;
cred->uc_gid = cred->uc_fsgid = 0;
cred->uc_gids[0] = NOGROUP;
@@ -119,7 +114,7 @@ authunix_fake_cred(struct rpc_task *task, uid_t uid, gid_t gid)
cred->uc_fsgid = gid;
cred->uc_gids[0] = (gid_t) NOGROUP;
- return task->tk_cred = (struct rpc_cred *) cred;
+ return task->tk_msg.rpc_cred = (struct rpc_cred *) cred;
}
static void
@@ -134,12 +129,12 @@ unx_destroy_cred(struct rpc_cred *cred)
* request root creds (e.g. for NFS swapping).
*/
static int
-unx_match(struct rpc_task * task, struct rpc_cred *rcred)
+unx_match(struct rpc_cred *rcred, int taskflags)
{
struct unx_cred *cred = (struct unx_cred *) rcred;
int i;
- if (!RPC_DO_ROOTOVERRIDE(task)) {
+ if (!(taskflags & RPC_TASK_ROOTCREDS)) {
int groups;
if (cred->uc_uid != current->uid
@@ -169,7 +164,7 @@ static u32 *
unx_marshal(struct rpc_task *task, u32 *p, int ruid)
{
struct rpc_clnt *clnt = task->tk_client;
- struct unx_cred *cred = (struct unx_cred *) task->tk_cred;
+ struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred;
u32 *base, *hold;
int i, n;
@@ -210,7 +205,7 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid)
static int
unx_refresh(struct rpc_task *task)
{
- task->tk_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+ task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
return task->tk_status = -EACCES;
}
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index b4d6bd81a..806e14bce 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -42,14 +42,13 @@
static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
-static void call_bind(struct rpc_task *task);
static void call_reserve(struct rpc_task *task);
static void call_reserveresult(struct rpc_task *task);
static void call_allocate(struct rpc_task *task);
static void call_encode(struct rpc_task *task);
static void call_decode(struct rpc_task *task);
+static void call_bind(struct rpc_task *task);
static void call_transmit(struct rpc_task *task);
-static void call_receive(struct rpc_task *task);
static void call_status(struct rpc_task *task);
static void call_refresh(struct rpc_task *task);
static void call_refreshresult(struct rpc_task *task);
@@ -98,7 +97,7 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
clnt->cl_port = xprt->addr.sin_port;
clnt->cl_prog = program->number;
clnt->cl_vers = version->number;
- clnt->cl_prot = IPPROTO_UDP;
+ clnt->cl_prot = xprt->prot;
clnt->cl_stats = program->stats;
clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait");
@@ -117,10 +116,10 @@ out:
return clnt;
out_no_clnt:
- printk("RPC: out of memory in rpc_create_client\n");
+ printk(KERN_INFO "RPC: out of memory in rpc_create_client\n");
goto out;
out_no_auth:
- printk("RPC: Couldn't create auth handle (flavor %d)\n",
+ printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %d)\n",
flavor);
rpc_free(clnt);
clnt = NULL;
@@ -140,7 +139,7 @@ rpc_shutdown_client(struct rpc_clnt *clnt)
clnt->cl_protname, clnt->cl_server);
while (clnt->cl_users) {
#ifdef RPC_DEBUG
- printk("rpc_shutdown_client: client %s, tasks=%d\n",
+ dprintk("RPC: rpc_shutdown_client: client %s, tasks=%d\n",
clnt->cl_protname, clnt->cl_users);
#endif
/* Don't let rpc_release_client destroy us */
@@ -240,42 +239,72 @@ void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
/*
* New rpc_call implementation
*/
-int
-rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
- int flags, rpc_action func, void *data)
+int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
{
struct rpc_task my_task, *task = &my_task;
sigset_t oldset;
- int async, status;
+ int status;
/* If this client is slain all further I/O fails */
if (clnt->cl_dead)
return -EIO;
+ if (flags & RPC_TASK_ASYNC) {
+ printk("rpc_call_sync: Illegal flag combination for synchronous task\n");
+ flags &= ~RPC_TASK_ASYNC;
+ }
+
rpc_clnt_sigmask(clnt, &oldset);
/* Create/initialize a new RPC task */
- if ((async = (flags & RPC_TASK_ASYNC)) != 0) {
- if (!func)
- func = rpc_default_callback;
- status = -ENOMEM;
- if (!(task = rpc_new_task(clnt, func, flags)))
- goto out;
- task->tk_calldata = data;
- } else {
- rpc_init_task(task, clnt, NULL, flags);
- }
+ rpc_init_task(task, clnt, NULL, flags);
+ rpc_call_setup(task, msg, 0);
- /* Bind the user cred, set up the call info struct and
- * execute the task */
- if (rpcauth_lookupcred(task) != NULL) {
- rpc_call_setup(task, proc, argp, resp, 0);
- rpc_execute(task);
- } else
- async = 0;
+ /* Set up the call info struct and execute the task */
+ if (task->tk_status == 0)
+ status = rpc_execute(task);
+ else
+ status = task->tk_status;
+ rpc_release_task(task);
+
+ rpc_clnt_sigunmask(clnt, &oldset);
+
+ return status;
+}
- status = 0;
- if (!async) {
+/*
+ * New rpc_call implementation
+ */
+int
+rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
+ rpc_action callback, void *data)
+{
+ struct rpc_task *task;
+ sigset_t oldset;
+ int status;
+
+ /* If this client is slain all further I/O fails */
+ if (clnt->cl_dead)
+ return -EIO;
+
+ flags |= RPC_TASK_ASYNC;
+
+ rpc_clnt_sigmask(clnt, &oldset);
+
+ /* Create/initialize a new RPC task */
+ if (!callback)
+ callback = rpc_default_callback;
+ status = -ENOMEM;
+ if (!(task = rpc_new_task(clnt, callback, flags)))
+ goto out;
+ task->tk_calldata = data;
+
+ rpc_call_setup(task, msg, 0);
+
+ /* Set up the call info struct and execute the task */
+ if (task->tk_status == 0)
+ status = rpc_execute(task);
+ else {
status = task->tk_status;
rpc_release_task(task);
}
@@ -288,18 +317,24 @@ out:
void
-rpc_call_setup(struct rpc_task *task, u32 proc,
- void *argp, void *resp, int flags)
+rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
{
- task->tk_action = call_bind;
- task->tk_proc = proc;
- task->tk_argp = argp;
- task->tk_resp = resp;
+ task->tk_msg = *msg;
task->tk_flags |= flags;
+ /* Bind the user cred */
+ if (task->tk_msg.rpc_cred != NULL) {
+ rpcauth_holdcred(task);
+ } else
+ rpcauth_bindcred(task);
+
+ if (task->tk_status == 0)
+ task->tk_action = call_reserve;
+ else
+ task->tk_action = NULL;
/* Increment call count */
- if (task->tk_proc < task->tk_client->cl_maxproc)
- rpcproc_count(task->tk_client, proc)++;
+ if (task->tk_msg.rpc_proc < task->tk_client->cl_maxproc)
+ rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
}
/*
@@ -313,27 +348,8 @@ rpc_restart_call(struct rpc_task *task)
rpc_release_task(task);
return;
}
- task->tk_action = call_bind;
- rpcproc_count(task->tk_client, task->tk_proc)++;
-}
-
-/*
- * 0. Get the server port number if not yet set
- */
-static void
-call_bind(struct rpc_task *task)
-{
- struct rpc_clnt *clnt = task->tk_client;
- struct rpc_xprt *xprt = clnt->cl_xprt;
-
- if (xprt->stream && !xprt->connected)
- task->tk_action = call_reconnect;
- else
- task->tk_action = call_reserve;
- task->tk_status = 0;
-
- if (!clnt->cl_port)
- rpc_getport(task, clnt);
+ task->tk_action = call_reserve;
+ rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
}
/*
@@ -344,26 +360,22 @@ call_reserve(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
- dprintk("RPC: %4d call_reserve\n", task->tk_pid);
- if (!clnt->cl_port) {
- printk(KERN_NOTICE "%s: couldn't bind to server %s - %s.\n",
- clnt->cl_protname, clnt->cl_server,
- clnt->cl_softrtry? "giving up" : "retrying");
- if (!clnt->cl_softrtry) {
- task->tk_action = call_bind;
- rpc_delay(task, 5*HZ);
- return;
- }
+ if (task->tk_msg.rpc_proc > clnt->cl_maxproc) {
+ printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
+ clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc);
rpc_exit(task, -EIO);
return;
}
+
+ dprintk("RPC: %4d call_reserve\n", task->tk_pid);
if (!rpcauth_uptodatecred(task)) {
task->tk_action = call_refresh;
return;
}
+
+ task->tk_status = 0;
task->tk_action = call_reserveresult;
task->tk_timeout = clnt->cl_timeout.to_resrvval;
- task->tk_status = 0;
clnt->cl_stats->rpccnt++;
xprt_reserve(task);
}
@@ -374,6 +386,8 @@ call_reserve(struct rpc_task *task)
static void
call_reserveresult(struct rpc_task *task)
{
+ int status = task->tk_status;
+
dprintk("RPC: %4d call_reserveresult (status %d)\n",
task->tk_pid, task->tk_status);
/*
@@ -382,7 +396,7 @@ call_reserveresult(struct rpc_task *task)
*/
if ((task->tk_status >= 0 && !task->tk_rqstp) ||
(task->tk_status < 0 && task->tk_rqstp))
- printk("call_reserveresult: status=%d, request=%p??\n",
+ printk(KERN_ERR "call_reserveresult: status=%d, request=%p??\n",
task->tk_status, task->tk_rqstp);
if (task->tk_status >= 0) {
@@ -390,11 +404,11 @@ call_reserveresult(struct rpc_task *task)
return;
}
- switch (task->tk_status) {
+ task->tk_status = 0;
+ switch (status) {
case -EAGAIN:
case -ENOBUFS:
task->tk_timeout = task->tk_client->cl_timeout.to_resrvval;
- task->tk_status = 0;
task->tk_action = call_reserve;
break;
case -ETIMEDOUT:
@@ -402,11 +416,11 @@ call_reserveresult(struct rpc_task *task)
task->tk_action = call_timeout;
break;
default:
- task->tk_action = NULL;
if (!task->tk_rqstp) {
- printk("RPC: task has no request, exit EIO\n");
+ printk(KERN_INFO "RPC: task has no request, exit EIO\n");
rpc_exit(task, -EIO);
- }
+ } else
+ rpc_exit(task, status);
}
}
@@ -428,13 +442,13 @@ call_allocate(struct rpc_task *task)
/* FIXME: compute buffer requirements more exactly using
* auth->au_wslack */
- bufsiz = rpcproc_bufsiz(clnt, task->tk_proc) + RPC_SLACK_SPACE;
+ bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc) + RPC_SLACK_SPACE;
if ((task->tk_buffer = rpc_malloc(task, bufsiz)) != NULL)
return;
- printk("RPC: buffer allocation failed for task %p\n", task);
+ printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task);
- if (!signalled()) {
+ if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) {
xprt_release(task);
task->tk_action = call_reserve;
rpc_delay(task, HZ>>4);
@@ -460,10 +474,10 @@ call_encode(struct rpc_task *task)
dprintk("RPC: %4d call_encode (status %d)\n",
task->tk_pid, task->tk_status);
- task->tk_action = call_transmit;
+ task->tk_action = call_bind;
/* Default buffer setup */
- bufsiz = rpcproc_bufsiz(clnt, task->tk_proc)+RPC_SLACK_SPACE;
+ bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc)+RPC_SLACK_SPACE;
req->rq_svec[0].iov_base = task->tk_buffer;
req->rq_svec[0].iov_len = bufsiz;
req->rq_slen = 0;
@@ -474,23 +488,16 @@ call_encode(struct rpc_task *task)
req->rq_rnr = 1;
req->rq_damaged = 0;
- if (task->tk_proc > clnt->cl_maxproc) {
- printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
- clnt->cl_protname, clnt->cl_vers, task->tk_proc);
- rpc_exit(task, -EIO);
- return;
- }
-
/* Zero buffer so we have automatic zero-padding of opaque & string */
memset(task->tk_buffer, 0, bufsiz);
/* Encode header and provided arguments */
- encode = rpcproc_encode(clnt, task->tk_proc);
+ encode = rpcproc_encode(clnt, task->tk_msg.rpc_proc);
if (!(p = call_header(task))) {
- printk("RPC: call_header failed, exit EIO\n");
+ printk(KERN_INFO "RPC: call_header failed, exit EIO\n");
rpc_exit(task, -EIO);
} else
- if (encode && (status = encode(req, p, task->tk_argp)) < 0) {
+ if (encode && (status = encode(req, p, task->tk_msg.rpc_argp)) < 0) {
printk(KERN_WARNING "%s: can't encode arguments: %d\n",
clnt->cl_protname, -status);
rpc_exit(task, status);
@@ -498,38 +505,59 @@ call_encode(struct rpc_task *task)
}
/*
- * 4. Transmit the RPC request
+ * 4. Get the server port number if not yet set
*/
static void
-call_transmit(struct rpc_task *task)
+call_bind(struct rpc_task *task)
{
- dprintk("RPC: %4d call_transmit (status %d)\n",
- task->tk_pid, task->tk_status);
+ struct rpc_clnt *clnt = task->tk_client;
+ struct rpc_xprt *xprt = clnt->cl_xprt;
- task->tk_action = call_receive;
- task->tk_status = 0;
- xprt_transmit(task);
+ task->tk_action = (xprt->connected) ? call_transmit : call_reconnect;
+
+ if (!clnt->cl_port) {
+ task->tk_action = call_reconnect;
+ task->tk_timeout = clnt->cl_timeout.to_maxval;
+ rpc_getport(task, clnt);
+ }
}
/*
- * 5. Wait for the RPC reply
+ * 4a. Reconnect to the RPC server (TCP case)
*/
static void
-call_receive(struct rpc_task *task)
+call_reconnect(struct rpc_task *task)
{
- dprintk("RPC: %4d call_receive (status %d)\n",
- task->tk_pid, task->tk_status);
+ struct rpc_clnt *clnt = task->tk_client;
- task->tk_action = call_status;
+ dprintk("RPC: %4d call_reconnect status %d\n",
+ task->tk_pid, task->tk_status);
- /* Need to ensure cleanups are performed by xprt_receive_status() */
- xprt_receive(task);
+ task->tk_action = call_transmit;
+ if (task->tk_status < 0 || !clnt->cl_xprt->stream)
+ return;
+ clnt->cl_stats->netreconn++;
+ xprt_reconnect(task);
+}
- /* If we have no decode function, this means we're performing
- * a void call (a la lockd message passing). */
- if (!rpcproc_decode(task->tk_client, task->tk_proc)) {
- task->tk_action = NULL;
+/*
+ * 5. Transmit the RPC request, and wait for reply
+ */
+static void
+call_transmit(struct rpc_task *task)
+{
+ struct rpc_clnt *clnt = task->tk_client;
+
+ dprintk("RPC: %4d call_transmit (status %d)\n",
+ task->tk_pid, task->tk_status);
+
+ task->tk_action = call_status;
+ if (task->tk_status < 0)
return;
+ xprt_transmit(task);
+ if (!rpcproc_decode(clnt, task->tk_msg.rpc_proc)) {
+ task->tk_action = NULL;
+ rpc_wake_up_task(task);
}
}
@@ -558,34 +586,30 @@ call_status(struct rpc_task *task)
case -ETIMEDOUT:
task->tk_action = call_timeout;
break;
- case -EAGAIN:
- if (!req)
- task->tk_action = call_reserve;
- else if (!task->tk_buffer)
- task->tk_action = call_allocate;
- else if (req->rq_damaged) {
- task->tk_action = call_encode;
- clnt->cl_stats->rpcretrans++;
- } else {
- task->tk_action = call_transmit;
- clnt->cl_stats->rpcretrans++;
- }
- break;
case -ECONNREFUSED:
case -ENOTCONN:
+ req->rq_bytes_sent = 0;
if (clnt->cl_autobind || !clnt->cl_port) {
clnt->cl_port = 0;
task->tk_action = call_bind;
- } else if (xprt->stream)
+ break;
+ }
+ if (xprt->stream) {
task->tk_action = call_reconnect;
- else {
- rpc_delay(task, 5*HZ); /* Hope it all wears off */
- if (req->rq_damaged)
- task->tk_action = call_encode;
- else
- task->tk_action = call_transmit;
- clnt->cl_stats->rpcretrans++;
+ break;
}
+ /*
+ * Sleep and dream of an open connection
+ */
+ task->tk_timeout = 5 * HZ;
+ rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+ case -ENOMEM:
+ case -EAGAIN:
+ if (req->rq_damaged)
+ task->tk_action = call_encode;
+ else
+ task->tk_action = call_transmit;
+ clnt->cl_stats->rpcretrans++;
break;
default:
if (clnt->cl_chatty)
@@ -614,15 +638,13 @@ call_timeout(struct rpc_task *task)
task->tk_pid);
goto minor_timeout;
}
- to->to_initval <<= 1;
- if (to->to_initval > to->to_maxval)
- to->to_initval = to->to_maxval;
+ to->to_retries = clnt->cl_timeout.to_retries;
}
dprintk("RPC: %4d call_timeout (major timeo)\n", task->tk_pid);
if (clnt->cl_softrtry) {
if (clnt->cl_chatty && !task->tk_exit)
- printk("%s: server %s not responding, timed out\n",
+ printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
clnt->cl_protname, clnt->cl_server);
rpc_exit(task, -EIO);
return;
@@ -630,24 +652,26 @@ call_timeout(struct rpc_task *task)
if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
task->tk_flags |= RPC_CALL_MAJORSEEN;
if (req)
- printk("%s: server %s not responding, still trying\n",
+ printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
clnt->cl_protname, clnt->cl_server);
else
- printk("%s: task %d can't get a request slot\n",
+ printk(KERN_NOTICE "%s: task %d can't get a request slot\n",
clnt->cl_protname, task->tk_pid);
}
if (clnt->cl_autobind)
clnt->cl_port = 0;
minor_timeout:
- if (!clnt->cl_port) {
+ if (!req)
+ task->tk_action = call_reserve;
+ else if (req->rq_damaged) {
+ task->tk_action = call_encode;
+ clnt->cl_stats->rpcretrans++;
+ } else if (!clnt->cl_port) {
task->tk_action = call_bind;
+ clnt->cl_stats->rpcretrans++;
} else if (clnt->cl_xprt->stream && !clnt->cl_xprt->connected) {
task->tk_action = call_reconnect;
- } else if (!req) {
- task->tk_action = call_reserve;
- } else if (req->rq_damaged) {
- task->tk_action = call_encode;
clnt->cl_stats->rpcretrans++;
} else {
task->tk_action = call_transmit;
@@ -657,21 +681,6 @@ minor_timeout:
}
/*
- * 6b. Reconnect to the RPC server (TCP case)
- */
-static void
-call_reconnect(struct rpc_task *task)
-{
- struct rpc_clnt *clnt = task->tk_client;
- dprintk("RPC: %4d call_reconnect status %d\n",
- task->tk_pid, task->tk_status);
- task->tk_action = call_reserve;
- task->tk_status = 0;
- clnt->cl_stats->netreconn++;
- xprt_reconnect(task);
-}
-
-/*
* 7. Decode the RPC reply
*/
static void
@@ -679,20 +688,20 @@ call_decode(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
struct rpc_rqst *req = task->tk_rqstp;
- kxdrproc_t decode = rpcproc_decode(clnt, task->tk_proc);
+ kxdrproc_t decode = rpcproc_decode(clnt, task->tk_msg.rpc_proc);
u32 *p;
dprintk("RPC: %4d call_decode (status %d)\n",
task->tk_pid, task->tk_status);
if (clnt->cl_chatty && (task->tk_flags & RPC_CALL_MAJORSEEN)) {
- printk("%s: server %s OK\n",
+ printk(KERN_NOTICE "%s: server %s OK\n",
clnt->cl_protname, clnt->cl_server);
task->tk_flags &= ~RPC_CALL_MAJORSEEN;
}
if (task->tk_status < 12) {
- printk("%s: too small RPC reply size (%d bytes)\n",
+ printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
clnt->cl_protname, task->tk_status);
rpc_exit(task, -EIO);
return;
@@ -708,10 +717,11 @@ call_decode(struct rpc_task *task)
*/
if (task->tk_client->cl_prog == 100003 &&
(ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {
- if (RPC_IS_SETUID(task) && (task->tk_suid_retry)--) {
+ if (RPC_IS_SETUID(task) && task->tk_suid_retry) {
dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);
task->tk_flags ^= RPC_CALL_REALUID;
task->tk_action = call_encode;
+ task->tk_suid_retry--;
return;
}
}
@@ -719,7 +729,7 @@ call_decode(struct rpc_task *task)
task->tk_action = NULL;
if (decode)
- task->tk_status = decode(req, p, task->tk_resp);
+ task->tk_status = decode(req, p, task->tk_msg.rpc_resp);
dprintk("RPC: %4d call_decode result %d\n", task->tk_pid,
task->tk_status);
}
@@ -751,7 +761,7 @@ call_refreshresult(struct rpc_task *task)
if (task->tk_status < 0)
rpc_exit(task, -EACCES);
else
- task->tk_action = call_bind;
+ task->tk_action = call_reserve;
}
/*
@@ -772,7 +782,7 @@ call_header(struct rpc_task *task)
*p++ = htonl(RPC_VERSION); /* RPC version */
*p++ = htonl(clnt->cl_prog); /* program number */
*p++ = htonl(clnt->cl_vers); /* program version */
- *p++ = htonl(task->tk_proc); /* procedure */
+ *p++ = htonl(task->tk_msg.rpc_proc); /* procedure */
return rpcauth_marshcred(task, p);
}
@@ -787,20 +797,21 @@ call_verify(struct rpc_task *task)
p += 1; /* skip XID */
if ((n = ntohl(*p++)) != RPC_REPLY) {
- printk("call_verify: not an RPC reply: %x\n", n);
+ printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n);
goto garbage;
}
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
int error = -EACCES;
if ((n = ntohl(*p++)) != RPC_AUTH_ERROR) {
- printk("call_verify: RPC call rejected: %x\n", n);
+ printk(KERN_WARNING "call_verify: RPC call rejected: %x\n", n);
} else
switch ((n = ntohl(*p++))) {
case RPC_AUTH_REJECTEDCRED:
case RPC_AUTH_REJECTEDVERF:
- if (!task->tk_cred_retry--)
+ if (!task->tk_cred_retry)
break;
+ task->tk_cred_retry--;
dprintk("RPC: %4d call_verify: retry stale creds\n",
task->tk_pid);
rpcauth_invalcred(task);
@@ -809,17 +820,18 @@ call_verify(struct rpc_task *task)
case RPC_AUTH_BADCRED:
case RPC_AUTH_BADVERF:
/* possibly garbled cred/verf? */
- if (!task->tk_garb_retry--)
+ if (!task->tk_garb_retry)
break;
+ task->tk_garb_retry--;
dprintk("RPC: %4d call_verify: retry garbled creds\n",
task->tk_pid);
task->tk_action = call_encode;
return NULL;
case RPC_AUTH_TOOWEAK:
- printk("call_verify: server requires stronger "
+ printk(KERN_NOTICE "call_verify: server requires stronger "
"authentication.\n");
default:
- printk("call_verify: unknown auth error: %x\n", n);
+ printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n);
error = -EIO;
}
dprintk("RPC: %4d call_verify: call rejected %d\n",
@@ -828,7 +840,7 @@ call_verify(struct rpc_task *task)
return NULL;
}
if (!(p = rpcauth_checkverf(task, p))) {
- printk("call_verify: auth check failed\n");
+ printk(KERN_WARNING "call_verify: auth check failed\n");
goto garbage; /* bad verifier, retry */
}
switch ((n = ntohl(*p++))) {
@@ -837,19 +849,20 @@ call_verify(struct rpc_task *task)
case RPC_GARBAGE_ARGS:
break; /* retry */
default:
- printk("call_verify: server accept status: %x\n", n);
+ printk(KERN_WARNING "call_verify: server accept status: %x\n", n);
/* Also retry */
}
garbage:
dprintk("RPC: %4d call_verify: server saw garbage\n", task->tk_pid);
task->tk_client->cl_stats->rpcgarbage++;
- if (task->tk_garb_retry--) {
- printk("RPC: garbage, retrying %4d\n", task->tk_pid);
+ if (task->tk_garb_retry) {
+ task->tk_garb_retry--;
+ printk(KERN_WARNING "RPC: garbage, retrying %4d\n", task->tk_pid);
task->tk_action = call_encode;
return NULL;
}
- printk("RPC: garbage, exit EIO\n");
+ printk(KERN_WARNING "RPC: garbage, exit EIO\n");
rpc_exit(task, -EIO);
return NULL;
}
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index 2bbe9d50a..6afb28e88 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -41,6 +41,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
{
struct rpc_portmap *map = &clnt->cl_pmap;
struct sockaddr_in *sap = &clnt->cl_xprt->addr;
+ struct rpc_message msg = { PMAP_GETPORT, map, &clnt->cl_port, NULL };
struct rpc_clnt *pmap_clnt;
struct rpc_task *child;
@@ -66,7 +67,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
goto bailout;
/* Setup the call info struct */
- rpc_call_setup(child, PMAP_GETPORT, map, &clnt->cl_port, 0);
+ rpc_call_setup(child, &msg, 0);
/* ... and run the child task */
rpc_run_child(task, child, pmap_getport_done);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index ffd4c18ad..bfbfc1580 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -69,6 +69,16 @@ static pid_t rpciod_pid = 0;
static int rpc_inhibit = 0;
/*
+ * Spinlock for wait queues. Access to the latter also has to be
+ * interrupt-safe in order to allow timers to wake up sleeping tasks.
+ */
+spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
+/*
+ * Spinlock for other critical sections of code.
+ */
+spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED;
+
+/*
* This is the last-ditch buffer for NFS swap requests
*/
static u32 swap_buffer[PAGE_SIZE >> 2];
@@ -87,14 +97,52 @@ static __inline__ void rpc_unlock_swapbuf(void)
}
/*
- * Spinlock for wait queues. Access to the latter also has to be
- * interrupt-safe in order to allow timers to wake up sleeping tasks.
+ * Set up a timer for the current task.
*/
-spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
+static inline void
+__rpc_add_timer(struct rpc_task *task, rpc_action timer)
+{
+ if (!task->tk_timeout)
+ return;
+
+ dprintk("RPC: %4d setting alarm for %lu ms\n",
+ task->tk_pid, task->tk_timeout * 1000 / HZ);
+
+ if (timer_pending(&task->tk_timer)) {
+ printk(KERN_ERR "RPC: Bug! Overwriting active timer\n");
+ del_timer(&task->tk_timer);
+ }
+ if (!timer)
+ timer = __rpc_default_timer;
+ init_timer(&task->tk_timer);
+ task->tk_timer.expires = jiffies + task->tk_timeout;
+ task->tk_timer.data = (unsigned long) task;
+ task->tk_timer.function = (void (*)(unsigned long)) timer;
+ add_timer(&task->tk_timer);
+}
+
/*
- * Spinlock for other critical sections of code.
+ * Set up a timer for an already sleeping task.
*/
-spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED;
+void rpc_add_timer(struct rpc_task *task, rpc_action timer)
+{
+ spin_lock_bh(&rpc_queue_lock);
+ if (!(RPC_IS_RUNNING(task) || task->tk_wakeup))
+ __rpc_add_timer(task, timer);
+ spin_unlock_bh(&rpc_queue_lock);
+}
+
+/*
+ * Delete any timer for the current task.
+ */
+static inline void
+__rpc_del_timer(struct rpc_task *task)
+{
+ dprintk("RPC: %4d deleting timer\n", task->tk_pid);
+ if (timer_pending(&task->tk_timer))
+ del_timer(&task->tk_timer);
+ task->tk_timeout = 0;
+}
/*
* Add new request to wait queue.
@@ -104,16 +152,15 @@ spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED;
* improve overall performance.
* Everyone else gets appended to the queue to ensure proper FIFO behavior.
*/
-static int
+static inline int
__rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
{
- if (task->tk_rpcwait) {
- if (task->tk_rpcwait != queue)
- {
- printk(KERN_WARNING "RPC: doubly enqueued task!\n");
- return -EWOULDBLOCK;
- }
+ if (task->tk_rpcwait == queue)
return 0;
+
+ if (task->tk_rpcwait) {
+ printk(KERN_WARNING "RPC: doubly enqueued task!\n");
+ return -EWOULDBLOCK;
}
if (RPC_IS_SWAPPER(task))
rpc_insert_list(&queue->task, task);
@@ -130,7 +177,7 @@ __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
int
rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
{
- int result;
+ int result;
spin_lock_bh(&rpc_queue_lock);
result = __rpc_add_wait_queue(q, task);
@@ -142,13 +189,14 @@ rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
* Remove request from queue.
* Note: must be called with spin lock held.
*/
-static void
+static inline void
__rpc_remove_wait_queue(struct rpc_task *task)
{
- struct rpc_wait_queue *queue;
+ struct rpc_wait_queue *queue = task->tk_rpcwait;
- if (!(queue = task->tk_rpcwait))
+ if (!queue)
return;
+
rpc_remove_list(&queue->task, task);
task->tk_rpcwait = NULL;
@@ -159,51 +207,14 @@ __rpc_remove_wait_queue(struct rpc_task *task)
void
rpc_remove_wait_queue(struct rpc_task *task)
{
+ if (!task->tk_rpcwait)
+ return;
spin_lock_bh(&rpc_queue_lock);
__rpc_remove_wait_queue(task);
spin_unlock_bh(&rpc_queue_lock);
}
/*
- * Set up a timer for the current task.
- */
-inline void
-rpc_add_timer(struct rpc_task *task, rpc_action timer)
-{
- unsigned long expires = jiffies + task->tk_timeout;
-
- dprintk("RPC: %4d setting alarm for %lu ms\n",
- task->tk_pid, task->tk_timeout * 1000 / HZ);
- if (!timer)
- timer = __rpc_default_timer;
- if (time_before(expires, jiffies)) {
- printk(KERN_ERR "RPC: bad timeout value %ld - setting to 10 sec!\n",
- task->tk_timeout);
- expires = jiffies + 10 * HZ;
- }
- task->tk_timer.expires = expires;
- task->tk_timer.data = (unsigned long) task;
- task->tk_timer.function = (void (*)(unsigned long)) timer;
- task->tk_timer.prev = NULL;
- task->tk_timer.next = NULL;
- add_timer(&task->tk_timer);
-}
-
-/*
- * Delete any timer for the current task.
- * Must be called with interrupts off.
- */
-inline void
-rpc_del_timer(struct rpc_task *task)
-{
- if (task->tk_timeout) {
- dprintk("RPC: %4d deleting timer\n", task->tk_pid);
- del_timer(&task->tk_timer);
- task->tk_timeout = 0;
- }
-}
-
-/*
* Make an RPC task runnable.
*
* Note: If the task is ASYNC, this must be called with
@@ -218,31 +229,44 @@ rpc_make_runnable(struct rpc_task *task)
}
task->tk_flags |= RPC_TASK_RUNNING;
if (RPC_IS_ASYNC(task)) {
- int status;
- status = __rpc_add_wait_queue(&schedq, task);
- if (status)
- {
- printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
- task->tk_status = status;
+ if (RPC_IS_SLEEPING(task)) {
+ int status;
+ status = __rpc_add_wait_queue(&schedq, task);
+ if (status < 0) {
+ printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+ task->tk_status = status;
+ } else
+ task->tk_sleeping = 0;
}
wake_up(&rpciod_idle);
} else {
+ task->tk_sleeping = 0;
wake_up(&task->tk_wait);
}
}
+/*
+ * Place a newly initialized task on the schedq.
+ */
+static inline void
+rpc_schedule_run(struct rpc_task *task)
+{
+ /* Don't run a child twice! */
+ if (RPC_IS_ACTIVATED(task))
+ return;
+ task->tk_active = 1;
+ task->tk_sleeping = 1;
+ rpc_make_runnable(task);
+}
/*
* For other people who may need to wake the I/O daemon
* but should (for now) know nothing about its innards
*/
-
void rpciod_wake_up(void)
{
if(rpciod_pid==0)
- {
printk(KERN_ERR "rpciod: wot no daemon?\n");
- }
wake_up(&rpciod_idle);
}
@@ -261,19 +285,25 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid,
rpc_qname(q), jiffies);
+ if (!RPC_IS_ASYNC(task) && !RPC_IS_ACTIVATED(task)) {
+ printk(KERN_ERR "RPC: Inactive synchronous task put to sleep!\n");
+ return;
+ }
+
+ /* Mark the task as being activated if so needed */
+ if (!RPC_IS_ACTIVATED(task)) {
+ task->tk_active = 1;
+ task->tk_sleeping = 1;
+ }
+
status = __rpc_add_wait_queue(q, task);
- if (status)
- {
+ if (status) {
printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
task->tk_status = status;
- task->tk_flags |= RPC_TASK_RUNNING;
- }
- else
- {
- task->tk_callback = action;
- if (task->tk_timeout)
- rpc_add_timer(task, timer);
+ } else {
task->tk_flags &= ~RPC_TASK_RUNNING;
+ task->tk_callback = action;
+ __rpc_add_timer(task, timer);
}
return;
@@ -291,6 +321,19 @@ rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
spin_unlock_bh(&rpc_queue_lock);
}
+void
+rpc_sleep_locked(struct rpc_wait_queue *q, struct rpc_task *task,
+ rpc_action action, rpc_action timer)
+{
+ /*
+ * Protect the queue operations.
+ */
+ spin_lock_bh(&rpc_queue_lock);
+ __rpc_sleep_on(q, task, action, timer);
+ rpc_lock_task(task);
+ spin_unlock_bh(&rpc_queue_lock);
+}
+
/*
* Wake up a single task -- must be invoked with spin lock held.
*
@@ -307,16 +350,33 @@ __rpc_wake_up(struct rpc_task *task)
if (task->tk_magic != 0xf00baa) {
printk(KERN_ERR "RPC: attempt to wake up non-existing task!\n");
rpc_debug = ~0;
+ rpc_show_tasks();
return;
}
#endif
- rpc_del_timer(task);
+ /* Has the task been executed yet? If not, we cannot wake it up! */
+ if (!RPC_IS_ACTIVATED(task)) {
+ printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task);
+ return;
+ }
+ if (RPC_IS_RUNNING(task))
+ return;
+
+ __rpc_del_timer(task);
+
+ /* If the task has been locked, then set tk_wakeup so that
+ * rpc_unlock_task() wakes us up... */
+ if (task->tk_lock) {
+ task->tk_wakeup = 1;
+ return;
+ } else
+ task->tk_wakeup = 0;
+
if (task->tk_rpcwait != &schedq)
__rpc_remove_wait_queue(task);
- if (!RPC_IS_RUNNING(task)) {
- task->tk_flags |= RPC_TASK_CALLBACK;
- rpc_make_runnable(task);
- }
+ task->tk_flags |= RPC_TASK_CALLBACK;
+ rpc_make_runnable(task);
+
dprintk("RPC: __rpc_wake_up done\n");
}
@@ -338,6 +398,8 @@ __rpc_default_timer(struct rpc_task *task)
void
rpc_wake_up_task(struct rpc_task *task)
{
+ if (RPC_IS_RUNNING(task))
+ return;
spin_lock_bh(&rpc_queue_lock);
__rpc_wake_up(task);
spin_unlock_bh(&rpc_queue_lock);
@@ -389,6 +451,30 @@ rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
}
/*
+ * Lock down a sleeping task to prevent it from waking up
+ * and disappearing from beneath us.
+ *
+ * This function should always be called with the
+ * rpc_queue_lock held.
+ */
+int
+rpc_lock_task(struct rpc_task *task)
+{
+ if (!RPC_IS_RUNNING(task))
+ return ++task->tk_lock;
+ return 0;
+}
+
+void
+rpc_unlock_task(struct rpc_task *task)
+{
+ spin_lock_bh(&rpc_queue_lock);
+ if (task->tk_lock && !--task->tk_lock && task->tk_wakeup)
+ __rpc_wake_up(task);
+ spin_unlock_bh(&rpc_queue_lock);
+}
+
+/*
* Run a task at a later time
*/
static void __rpc_atrun(struct rpc_task *);
@@ -426,7 +512,7 @@ __rpc_execute(struct rpc_task *task)
/*
* Execute any pending callback.
*/
- if (task->tk_flags & RPC_TASK_CALLBACK) {
+ if (RPC_DO_CALLBACK(task)) {
/* Define a callback save pointer */
void (*save_callback)(struct rpc_task *);
@@ -446,101 +532,89 @@ __rpc_execute(struct rpc_task *task)
}
/*
- * No handler for next step means exit.
- */
- if (!task->tk_action)
- break;
-
- /*
* Perform the next FSM step.
* tk_action may be NULL when the task has been killed
* by someone else.
*/
- if (RPC_IS_RUNNING(task) && task->tk_action)
+ if (RPC_IS_RUNNING(task)) {
+ if (!task->tk_action)
+ break;
task->tk_action(task);
+ }
/*
* Check whether task is sleeping.
- * Note that if the task may go to sleep in tk_action,
+ * Note that if the task goes to sleep in tk_action,
* and the RPC reply arrives before we get here, it will
* have state RUNNING, but will still be on schedq.
+ * 27/9/99: The above has been attempted fixed by
+ * introduction of task->tk_sleeping.
*/
spin_lock_bh(&rpc_queue_lock);
- if (RPC_IS_RUNNING(task)) {
- if (task->tk_rpcwait == &schedq)
- __rpc_remove_wait_queue(task);
- } else while (!RPC_IS_RUNNING(task)) {
+ if (!RPC_IS_RUNNING(task)) {
+ task->tk_sleeping = 1;
if (RPC_IS_ASYNC(task)) {
spin_unlock_bh(&rpc_queue_lock);
return 0;
}
+ } else
+ task->tk_sleeping = 0;
+ spin_unlock_bh(&rpc_queue_lock);
+ while (RPC_IS_SLEEPING(task)) {
/* sync task: sleep here */
dprintk("RPC: %4d sync task going to sleep\n",
task->tk_pid);
if (current->pid == rpciod_pid)
printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
- spin_unlock_bh(&rpc_queue_lock);
- __wait_event(task->tk_wait, RPC_IS_RUNNING(task));
- spin_lock_bh(&rpc_queue_lock);
+ __wait_event(task->tk_wait, !RPC_IS_SLEEPING(task));
+ dprintk("RPC: %4d sync task resuming\n", task->tk_pid);
/*
- * When the task received a signal, remove from
- * any queues etc, and make runnable again.
+ * When a sync task receives a signal, it exits with
+ * -ERESTARTSYS. In order to catch any callbacks that
+ * clean up after sleeping on some queue, we don't
+ * break the loop here, but go around once more.
*/
- if (signalled())
- __rpc_wake_up(task);
-
- dprintk("RPC: %4d sync task resuming\n",
- task->tk_pid);
- }
- spin_unlock_bh(&rpc_queue_lock);
-
- /*
- * When a sync task receives a signal, it exits with
- * -ERESTARTSYS. In order to catch any callbacks that
- * clean up after sleeping on some queue, we don't
- * break the loop here, but go around once more.
- */
- if (!RPC_IS_ASYNC(task) && signalled()) {
- dprintk("RPC: %4d got signal\n", task->tk_pid);
- rpc_exit(task, -ERESTARTSYS);
+ if (task->tk_client->cl_intr && signalled()) {
+ dprintk("RPC: %4d got signal\n", task->tk_pid);
+ task->tk_flags |= RPC_TASK_KILLED;
+ rpc_exit(task, -ERESTARTSYS);
+ rpc_wake_up_task(task);
+ }
}
}
dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);
- if (task->tk_exit) {
- status = task->tk_status;
+ status = task->tk_status;
+ if (task->tk_exit)
task->tk_exit(task);
- }
return status;
}
/*
* User-visible entry point to the scheduler.
- * The recursion protection is for debugging. It should go away once
- * the code has stabilized.
+ *
+ * This may be called recursively if e.g. an async NFS task updates
+ * the attributes and finds that dirty pages must be flushed.
*/
-void
+int
rpc_execute(struct rpc_task *task)
{
- static int executing = 0;
- int incr = RPC_IS_ASYNC(task)? 1 : 0;
-
- if (incr) {
- if (rpc_inhibit) {
- printk(KERN_INFO "RPC: execution inhibited!\n");
- return;
- }
- if (executing)
- printk(KERN_WARNING "RPC: %d tasks executed\n", executing);
+ if (rpc_inhibit) {
+ printk(KERN_INFO "RPC: execution inhibited!\n");
+ return -EIO;
}
+ task->tk_flags |= RPC_TASK_RUNNING;
+ if (task->tk_active) {
+ printk(KERN_ERR "RPC: active task was run twice!\n");
+ return -EWOULDBLOCK;
+ }
+ task->tk_active = 1;
- executing += incr;
- __rpc_execute(task);
- executing -= incr;
+ return __rpc_execute(task);
}
/*
@@ -551,28 +625,33 @@ __rpc_schedule(void)
{
struct rpc_task *task;
int count = 0;
- int need_resched = current->need_resched;
dprintk("RPC: rpc_schedule enter\n");
while (1) {
+ /* Ensure equal rights for tcp tasks... */
+ rpciod_tcp_dispatcher();
+
spin_lock_bh(&rpc_queue_lock);
if (!(task = schedq.task)) {
spin_unlock_bh(&rpc_queue_lock);
break;
}
- rpc_del_timer(task);
+ if (task->tk_lock) {
+ spin_unlock_bh(&rpc_queue_lock);
+ printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
+ rpc_debug = ~0;
+ rpc_show_tasks();
+ break;
+ }
__rpc_remove_wait_queue(task);
- task->tk_flags |= RPC_TASK_RUNNING;
spin_unlock_bh(&rpc_queue_lock);
__rpc_execute(task);
- if (++count >= 200) {
+ if (++count >= 200 || current->need_resched) {
count = 0;
- need_resched = 1;
- }
- if (need_resched)
schedule();
+ }
}
dprintk("RPC: rpc_schedule leave\n");
}
@@ -646,8 +725,9 @@ rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
rpc_action callback, int flags)
{
memset(task, 0, sizeof(*task));
+ init_timer(&task->tk_timer);
task->tk_client = clnt;
- task->tk_flags = RPC_TASK_RUNNING | flags;
+ task->tk_flags = flags;
task->tk_exit = callback;
init_waitqueue_head(&task->tk_wait);
if (current->uid != current->fsuid || current->gid != current->fsgid)
@@ -717,6 +797,15 @@ rpc_release_task(struct rpc_task *task)
dprintk("RPC: %4d release task\n", task->tk_pid);
+#ifdef RPC_DEBUG
+ if (task->tk_magic != 0xf00baa) {
+ printk(KERN_ERR "RPC: attempt to release a non-existing task!\n");
+ rpc_debug = ~0;
+ rpc_show_tasks();
+ return;
+ }
+#endif
+
/* Remove from global task list */
spin_lock(&rpc_sched_lock);
prev = task->tk_prev_task;
@@ -734,18 +823,20 @@ rpc_release_task(struct rpc_task *task)
spin_lock_bh(&rpc_queue_lock);
/* Delete any running timer */
- rpc_del_timer(task);
+ __rpc_del_timer(task);
/* Remove from any wait queue we're still on */
__rpc_remove_wait_queue(task);
+ task->tk_active = 0;
+
spin_unlock_bh(&rpc_queue_lock);
/* Release resources */
if (task->tk_rqstp)
xprt_release(task);
- if (task->tk_cred)
- rpcauth_releasecred(task);
+ if (task->tk_msg.rpc_cred)
+ rpcauth_unbindcred(task);
if (task->tk_buffer) {
rpc_free(task->tk_buffer);
task->tk_buffer = NULL;
@@ -824,7 +915,7 @@ rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func)
spin_lock_bh(&rpc_queue_lock);
/* N.B. Is it possible for the child to have already finished? */
__rpc_sleep_on(&childq, task, func, NULL);
- rpc_make_runnable(child);
+ rpc_schedule_run(child);
spin_unlock_bh(&rpc_queue_lock);
}
@@ -903,8 +994,6 @@ rpciod(void *ptr)
schedule();
rounds = 0;
}
- dprintk("RPC: rpciod running checking dispatch\n");
- rpciod_tcp_dispatcher();
if (!rpciod_task_pending()) {
dprintk("RPC: rpciod back to sleep\n");
@@ -1032,11 +1121,9 @@ out:
}
#ifdef RPC_DEBUG
-#include <linux/nfs_fs.h>
void rpc_show_tasks(void)
{
struct rpc_task *t = all_tasks, *next;
- struct nfs_wreq *wreq;
spin_lock(&rpc_sched_lock);
t = all_tasks;
@@ -1049,22 +1136,11 @@ void rpc_show_tasks(void)
for (; t; t = next) {
next = t->tk_next_task;
printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n",
- t->tk_pid, t->tk_proc, t->tk_flags, t->tk_status,
+ t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status,
t->tk_client, t->tk_client->cl_prog,
t->tk_rqstp, t->tk_timeout,
t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " <NULL> ",
t->tk_action, t->tk_exit);
-
- if (!(t->tk_flags & RPC_TASK_NFSWRITE))
- continue;
- /* NFS write requests */
- wreq = (struct nfs_wreq *) t->tk_calldata;
- printk(" NFS: flgs=%08x, pid=%d, pg=%p, off=(%d, %d)\n",
- wreq->wb_flags, wreq->wb_pid, wreq->wb_page,
- wreq->wb_offset, wreq->wb_bytes);
- printk(" name=%s/%s\n",
- wreq->wb_file->f_dentry->d_parent->d_name.name,
- wreq->wb_file->f_dentry->d_name.name);
}
spin_unlock(&rpc_sched_lock);
}
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 9a1861041..92559fa65 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -35,13 +35,16 @@ EXPORT_SYMBOL(rpc_new_child);
EXPORT_SYMBOL(rpc_run_child);
EXPORT_SYMBOL(rpciod_down);
EXPORT_SYMBOL(rpciod_up);
+EXPORT_SYMBOL(rpc_new_task);
+EXPORT_SYMBOL(rpc_wake_up_status);
/* RPC client functions */
EXPORT_SYMBOL(rpc_create_client);
EXPORT_SYMBOL(rpc_destroy_client);
EXPORT_SYMBOL(rpc_shutdown_client);
EXPORT_SYMBOL(rpc_killall_tasks);
-EXPORT_SYMBOL(rpc_do_call);
+EXPORT_SYMBOL(rpc_call_sync);
+EXPORT_SYMBOL(rpc_call_async);
EXPORT_SYMBOL(rpc_call_setup);
EXPORT_SYMBOL(rpc_clnt_sigmask);
EXPORT_SYMBOL(rpc_clnt_sigunmask);
@@ -60,6 +63,7 @@ EXPORT_SYMBOL(rpcauth_init_credcache);
EXPORT_SYMBOL(rpcauth_free_credcache);
EXPORT_SYMBOL(rpcauth_insert_credcache);
EXPORT_SYMBOL(rpcauth_lookupcred);
+EXPORT_SYMBOL(rpcauth_bindcred);
EXPORT_SYMBOL(rpcauth_matchcred);
EXPORT_SYMBOL(rpcauth_releasecred);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 48dd5623d..06d682223 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -68,7 +68,14 @@
/* Following value should be > 32k + RPC overhead */
#define XPRT_MIN_WRITE_SPACE 35000
+extern spinlock_t rpc_queue_lock;
+
+/*
+ * Local variables
+ */
+
/* Spinlock for critical sections in the code. */
+spinlock_t xprt_sock_lock = SPIN_LOCK_UNLOCKED;
spinlock_t xprt_lock = SPIN_LOCK_UNLOCKED;
#ifdef RPC_DEBUG
@@ -86,14 +93,12 @@ spinlock_t xprt_lock = SPIN_LOCK_UNLOCKED;
*/
static void xprt_request_init(struct rpc_task *, struct rpc_xprt *);
static void do_xprt_transmit(struct rpc_task *);
-static void xprt_transmit_status(struct rpc_task *task);
-static void xprt_transmit_timeout(struct rpc_task *task);
-static void xprt_receive_status(struct rpc_task *task);
static void xprt_reserve_status(struct rpc_task *task);
static void xprt_disconnect(struct rpc_xprt *);
-static void xprt_reconn_timeout(struct rpc_task *task);
-static struct socket *xprt_create_socket(int, struct sockaddr_in *,
- struct rpc_timeout *);
+static void xprt_reconn_status(struct rpc_task *task);
+static struct socket *xprt_create_socket(int, struct rpc_timeout *);
+static int xprt_bind_socket(struct rpc_xprt *, struct socket *);
+static void xprt_remove_pending(struct rpc_xprt *);
#ifdef RPC_DEBUG_DATA
/*
@@ -140,7 +145,7 @@ xprt_from_sock(struct sock *sk)
*/
extern inline void
-xprt_move_iov(struct msghdr *msg, struct iovec *niv, int amount)
+xprt_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
{
struct iovec *iv=msg->msg_iov;
int i;
@@ -148,7 +153,7 @@ xprt_move_iov(struct msghdr *msg, struct iovec *niv, int amount)
/*
* Eat any sent iovecs
*/
- while(iv->iov_len <= amount) {
+ while (iv->iov_len <= amount) {
amount -= iv->iov_len;
iv++;
msg->msg_iovlen--;
@@ -184,14 +189,17 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req)
int slen = req->rq_slen - req->rq_bytes_sent;
struct iovec niv[MAX_IOVEC];
- if (slen == 0)
+ if (slen <= 0)
return 0;
+ if (!sock)
+ return -ENOTCONN;
+
xprt_pktdump("packet data:",
req->rq_svec->iov_base,
req->rq_svec->iov_len);
- msg.msg_flags = MSG_DONTWAIT;
+ msg.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL;
msg.msg_iov = req->rq_svec;
msg.msg_iovlen = req->rq_snr;
msg.msg_name = (struct sockaddr *) &xprt->addr;
@@ -238,23 +246,30 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req)
/*
* Read data from socket
*/
-static inline int
-xprt_recvmsg(struct rpc_xprt *xprt, struct iovec *iov, int nr, int len)
+static int
+xprt_recvmsg(struct rpc_xprt *xprt, struct iovec *iov, int nr, unsigned len, unsigned shift)
{
struct socket *sock = xprt->sock;
- struct sockaddr_in sin;
struct msghdr msg;
mm_segment_t oldfs;
+ struct iovec niv[MAX_IOVEC];
int result;
- msg.msg_flags = MSG_DONTWAIT;
+ if (!sock)
+ return -ENOTCONN;
+
+ msg.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL;
msg.msg_iov = iov;
msg.msg_iovlen = nr;
- msg.msg_name = &sin;
- msg.msg_namelen = sizeof(sin);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
+ /* Adjust the iovec if we've already filled it */
+ if (shift)
+ xprt_move_iov(&msg, niv, shift);
+
oldfs = get_fs(); set_fs(get_ds());
result = sock_recvmsg(sock, &msg, len, MSG_DONTWAIT);
set_fs(oldfs);
@@ -309,21 +324,30 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result)
int
xprt_adjust_timeout(struct rpc_timeout *to)
{
- if (to->to_exponential)
- to->to_current <<= 1;
- else
- to->to_current += to->to_increment;
- if (to->to_maxval && to->to_current >= to->to_maxval) {
- to->to_current = to->to_maxval;
- to->to_retries = 0;
+ if (to->to_retries > 0) {
+ if (to->to_exponential)
+ to->to_current <<= 1;
+ else
+ to->to_current += to->to_increment;
+ if (to->to_maxval && to->to_current >= to->to_maxval)
+ to->to_current = to->to_maxval;
+ } else {
+ if (to->to_exponential)
+ to->to_initval <<= 1;
+ else
+ to->to_initval += to->to_increment;
+ if (to->to_maxval && to->to_initval >= to->to_maxval)
+ to->to_initval = to->to_maxval;
+ to->to_current = to->to_initval;
}
+
if (!to->to_current) {
printk(KERN_WARNING "xprt_adjust_timeout: to_current = 0!\n");
to->to_current = 5 * HZ;
}
pprintk("RPC: %lu %s\n", jiffies,
to->to_retries? "retrans" : "timeout");
- return (to->to_retries)--;
+ return to->to_retries-- > 0;
}
/*
@@ -332,22 +356,29 @@ xprt_adjust_timeout(struct rpc_timeout *to)
static void
xprt_close(struct rpc_xprt *xprt)
{
+ struct socket *sock = xprt->sock;
struct sock *sk = xprt->inet;
- xprt_disconnect(xprt);
+ if (!sk)
+ return;
+
+ xprt->inet = NULL;
+ xprt->sock = NULL;
sk->user_data = NULL;
sk->data_ready = xprt->old_data_ready;
sk->state_change = xprt->old_state_change;
sk->write_space = xprt->old_write_space;
+
+ xprt_disconnect(xprt);
sk->no_check = 0;
- sock_release(xprt->sock);
+ sock_release(sock);
/*
* TCP doesnt require the rpciod now - other things may
* but rpciod handles that not us.
*/
- if(xprt->stream && !xprt->connecting)
+ if(xprt->stream)
rpciod_down();
}
@@ -360,14 +391,10 @@ xprt_disconnect(struct rpc_xprt *xprt)
dprintk("RPC: disconnected transport %p\n", xprt);
xprt->connected = 0;
xprt->tcp_offset = 0;
- xprt->tcp_more = 0;
- xprt->tcp_total = 0;
- xprt->tcp_reclen = 0;
xprt->tcp_copied = 0;
- xprt->tcp_rqstp = NULL;
- xprt->rx_pending_flag = 0;
+ xprt->tcp_more = 0;
+ xprt_remove_pending(xprt);
rpc_wake_up_status(&xprt->pending, -ENOTCONN);
- rpc_wake_up_status(&xprt->sending, -ENOTCONN);
}
/*
@@ -377,85 +404,87 @@ void
xprt_reconnect(struct rpc_task *task)
{
struct rpc_xprt *xprt = task->tk_xprt;
- struct socket *sock;
- struct sock *inet;
+ struct socket *sock = xprt->sock;
+ struct sock *inet = xprt->inet;
int status;
dprintk("RPC: %4d xprt_reconnect %p connected %d\n",
task->tk_pid, xprt, xprt->connected);
- task->tk_status = 0;
-
if (xprt->shutdown)
return;
if (!xprt->stream)
return;
- spin_lock_bh(&xprt_lock);
- if (xprt->connected) {
- spin_unlock_bh(&xprt_lock);
+ if (!xprt->addr.sin_port) {
+ task->tk_status = -EIO;
return;
}
+
+ spin_lock(&xprt_lock);
if (xprt->connecting) {
- task->tk_timeout = xprt->timeout.to_maxval;
+ task->tk_timeout = 0;
rpc_sleep_on(&xprt->reconn, task, NULL, NULL);
- spin_unlock_bh(&xprt_lock);
+ spin_unlock(&xprt_lock);
return;
}
xprt->connecting = 1;
- spin_unlock_bh(&xprt_lock);
+ spin_unlock(&xprt_lock);
- /* Create an unconnected socket */
- if (!(sock = xprt_create_socket(xprt->prot, NULL, &xprt->timeout))) {
- xprt->connecting = 0;
- goto defer;
+ status = -ENOTCONN;
+ if (!inet) {
+ /* Create an unconnected socket */
+ if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout)))
+ goto defer;
+ xprt_bind_socket(xprt, sock);
+ inet = sock->sk;
}
- inet = sock->sk;
- inet->data_ready = xprt->inet->data_ready;
- inet->state_change = xprt->inet->state_change;
- inet->write_space = xprt->inet->write_space;
- inet->user_data = xprt;
-
- dprintk("RPC: %4d closing old socket\n", task->tk_pid);
- xprt_close(xprt);
-
- /* Reset to new socket */
- xprt->sock = sock;
- xprt->inet = inet;
+ xprt_disconnect(xprt);
/* Now connect it asynchronously. */
dprintk("RPC: %4d connecting new socket\n", task->tk_pid);
status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
sizeof(xprt->addr), O_NONBLOCK);
- xprt->connecting = 0;
if (status < 0) {
- if (status != -EINPROGRESS && status != -EALREADY) {
+ switch (status) {
+ case -EALREADY:
+ case -EINPROGRESS:
+ status = 0;
+ break;
+ case -EISCONN:
+ case -EPIPE:
+ status = 0;
+ xprt_close(xprt);
+ goto defer;
+ default:
printk("RPC: TCP connect error %d!\n", -status);
+ xprt_close(xprt);
goto defer;
}
dprintk("RPC: %4d connect status %d connected %d\n",
task->tk_pid, status, xprt->connected);
- task->tk_timeout = 60 * HZ;
- spin_lock_bh(&xprt_lock);
+ spin_lock_bh(&xprt_sock_lock);
if (!xprt->connected) {
- rpc_sleep_on(&xprt->reconn, task,
- NULL, xprt_reconn_timeout);
- spin_unlock_bh(&xprt_lock);
+ task->tk_timeout = xprt->timeout.to_maxval;
+ rpc_sleep_on(&xprt->reconn, task, xprt_reconn_status, NULL);
+ spin_unlock_bh(&xprt_sock_lock);
return;
}
- spin_unlock_bh(&xprt_lock);
+ spin_unlock_bh(&xprt_sock_lock);
}
-
-
defer:
- spin_lock_bh(&xprt_lock);
- if (!xprt->connected)
- rpc_wake_up_next(&xprt->reconn);
- spin_unlock_bh(&xprt_lock);
+ spin_lock(&xprt_lock);
+ xprt->connecting = 0;
+ if (status < 0) {
+ rpc_delay(task, 5*HZ);
+ task->tk_status = -ENOTCONN;
+ }
+ rpc_wake_up(&xprt->reconn);
+ spin_unlock(&xprt_lock);
}
/*
@@ -463,29 +492,21 @@ defer:
* process of reconnecting, and leave the rest to the upper layers.
*/
static void
-xprt_reconn_timeout(struct rpc_task *task)
+xprt_reconn_status(struct rpc_task *task)
{
- spin_lock_bh(&xprt_lock);
+ struct rpc_xprt *xprt = task->tk_xprt;
+
dprintk("RPC: %4d xprt_reconn_timeout %d\n",
task->tk_pid, task->tk_status);
- task->tk_status = -ENOTCONN;
- if (task->tk_xprt->connecting)
- task->tk_xprt->connecting = 0;
- if (!task->tk_xprt->connected)
- task->tk_status = -ENOTCONN;
- else
- task->tk_status = -ETIMEDOUT;
- task->tk_timeout = 0;
- rpc_wake_up_task(task);
- spin_unlock_bh(&xprt_lock);
+
+ spin_lock(&xprt_lock);
+ xprt->connecting = 0;
+ rpc_wake_up(&xprt->reconn);
+ spin_unlock(&xprt_lock);
}
-extern spinlock_t rpc_queue_lock;
/*
- * Look up the RPC request corresponding to a reply.
- *
- * RED-PEN: Niiice... Guys, when will we learn finally that locking
- * in this manner is NOOP? --ANK
+ * Look up the RPC request corresponding to a reply, and then lock it.
*/
static inline struct rpc_rqst *
xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
@@ -511,6 +532,8 @@ xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
out_bad:
req = NULL;
out:
+ if (req && !rpc_lock_task(req->rq_task))
+ req = NULL;
spin_unlock_bh(&rpc_queue_lock);
return req;
}
@@ -524,9 +547,6 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
{
struct rpc_task *task = req->rq_task;
- req->rq_rlen = copied;
- req->rq_gotit = 1;
-
/* Adjust congestion window */
xprt_adjust_cwnd(xprt, copied);
@@ -549,12 +569,11 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
}
#endif
- /* ... and wake up the process. */
dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied);
task->tk_status = copied;
- if (!RPC_IS_RUNNING(task))
- rpc_wake_up_task(task);
+ /* ... and wake up the process. */
+ rpc_wake_up_task(task);
return;
}
@@ -612,6 +631,7 @@ static int csum_partial_copy_to_page_cache(struct iovec *iov,
static inline void
udp_data_ready(struct sock *sk, int len)
{
+ struct rpc_task *task;
struct rpc_xprt *xprt;
struct rpc_rqst *rovr;
struct sk_buff *skb;
@@ -626,7 +646,10 @@ udp_data_ready(struct sock *sk, int len)
dprintk("RPC: udp_data_ready client %p\n", xprt);
if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL)
- goto out_err;
+ return;
+
+ if (xprt->shutdown)
+ goto dropit;
repsize = skb->len - sizeof(struct udphdr);
if (repsize < 4) {
@@ -634,14 +657,15 @@ udp_data_ready(struct sock *sk, int len)
goto dropit;
}
- /* Look up the request corresponding to the given XID */
- if (!(rovr = xprt_lookup_rqst(xprt,
- *(u32 *) (skb->h.raw + sizeof(struct udphdr)))))
+ /* Look up and lock the request corresponding to the given XID */
+ rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + sizeof(struct udphdr)));
+ if (!rovr)
goto dropit;
+ task = rovr->rq_task;
- dprintk("RPC: %4d received reply\n", rovr->rq_task->tk_pid);
+ dprintk("RPC: %4d received reply\n", task->tk_pid);
xprt_pktdump("packet data:",
- (u32 *) (skb->h.raw + sizeof(struct udphdr)), repsize);
+ (u32 *) (skb->h.raw+sizeof(struct udphdr)), repsize);
if ((copied = rovr->rq_rlen) > repsize)
copied = repsize;
@@ -649,213 +673,287 @@ udp_data_ready(struct sock *sk, int len)
rovr->rq_damaged = 1;
/* 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;
+ goto out_unlock;
/* Something worked... */
dst_confirm(skb->dst);
xprt_complete_rqst(xprt, rovr, copied);
-dropit:
+ out_unlock:
+ rpc_unlock_task(task);
+
+ dropit:
skb_free_datagram(sk, skb);
- return;
-out_err:
- return;
}
/*
- * TCP record receive routine
- * This is not the most efficient code since we call recvfrom twice--
- * first receiving the record marker and XID, then the data.
- *
- * The optimal solution would be a RPC support in the TCP layer, which
- * would gather all data up to the next record marker and then pass us
- * the list of all TCP segments ready to be copied.
+ * TCP read fragment marker
*/
static inline int
-tcp_input_record(struct rpc_xprt *xprt)
+tcp_read_fraghdr(struct rpc_xprt *xprt)
{
- struct rpc_rqst *req;
- struct iovec *iov;
struct iovec riov;
- u32 offset;
- int result, maxcpy, reclen, avail, want;
+ int want, result;
- dprintk("RPC: tcp_input_record\n");
+ if (xprt->tcp_offset >= xprt->tcp_reclen + sizeof(xprt->tcp_recm)) {
+ xprt->tcp_offset = 0;
+ xprt->tcp_reclen = 0;
+ }
+ if (xprt->tcp_offset >= sizeof(xprt->tcp_recm))
+ goto done;
- offset = xprt->tcp_offset;
- result = -EAGAIN;
- if (offset < 4 || (!xprt->tcp_more && offset < 8)) {
- want = (xprt->tcp_more? 4 : 8) - offset;
- dprintk("RPC: reading header (%d bytes)\n", want);
- riov.iov_base = xprt->tcp_recm.data + offset;
+ want = sizeof(xprt->tcp_recm) - xprt->tcp_offset;
+ dprintk("RPC: reading header (%d bytes)\n", want);
+ do {
+ riov.iov_base = ((u8*) &xprt->tcp_recm) + xprt->tcp_offset;
riov.iov_len = want;
- result = xprt_recvmsg(xprt, &riov, 1, want);
+ result = xprt_recvmsg(xprt, &riov, 1, want, 0);
if (result < 0)
- goto done;
- offset += result;
- if (result < want) {
- result = -EAGAIN;
- goto done;
- }
+ return result;
+ xprt->tcp_offset += result;
+ want -= result;
+ } while (want);
- /* Get the record length and mask out the more_fragments bit */
- reclen = ntohl(xprt->tcp_reclen);
- dprintk("RPC: reclen %08x\n", reclen);
- xprt->tcp_more = (reclen & 0x80000000)? 0 : 1;
- reclen &= 0x7fffffff;
- xprt->tcp_total += reclen;
- xprt->tcp_reclen = reclen;
-
- dprintk("RPC: got xid %08x reclen %d morefrags %d\n",
- xprt->tcp_xid, xprt->tcp_reclen, xprt->tcp_more);
- if (!xprt->tcp_copied
- && (req = xprt_lookup_rqst(xprt, xprt->tcp_xid))) {
- iov = xprt->tcp_iovec;
- memcpy(iov, req->rq_rvec, req->rq_rnr * sizeof(iov[0]));
-#if 0
-*(u32 *)iov->iov_base = req->rq_xid;
-#endif
- iov->iov_base += 4;
- iov->iov_len -= 4;
- xprt->tcp_copied = 4;
- xprt->tcp_rqstp = req;
- }
- } else {
- reclen = xprt->tcp_reclen;
- }
+ /* Is this another fragment in the last message */
+ if (!xprt->tcp_more)
+ xprt->tcp_copied = 0; /* No, so we're reading a new message */
+
+ /* Get the record length and mask out the last fragment bit */
+ xprt->tcp_reclen = ntohl(xprt->tcp_recm);
+ xprt->tcp_more = (xprt->tcp_reclen & 0x80000000) ? 0 : 1;
+ xprt->tcp_reclen &= 0x7fffffff;
+
+ dprintk("RPC: New record reclen %d morefrags %d\n",
+ xprt->tcp_reclen, xprt->tcp_more);
+ done:
+ return xprt->tcp_reclen + sizeof(xprt->tcp_recm) - xprt->tcp_offset;
+}
+
+/*
+ * TCP read xid
+ */
+static inline int
+tcp_read_xid(struct rpc_xprt *xprt, int avail)
+{
+ struct iovec riov;
+ int want, result;
+
+ if (xprt->tcp_copied >= sizeof(xprt->tcp_xid) || !avail)
+ goto done;
+ want = MIN(sizeof(xprt->tcp_xid) - xprt->tcp_copied, avail);
+ do {
+ dprintk("RPC: reading xid (%d bytes)\n", want);
+ riov.iov_base = ((u8*) &xprt->tcp_xid) + xprt->tcp_copied;
+ riov.iov_len = want;
+ result = xprt_recvmsg(xprt, &riov, 1, want, 0);
+ if (result < 0)
+ return result;
+ xprt->tcp_copied += result;
+ xprt->tcp_offset += result;
+ want -= result;
+ avail -= result;
+ } while (want);
+ done:
+ return avail;
+}
- avail = reclen - (offset - 4);
- if ((req = xprt->tcp_rqstp) && req->rq_xid == xprt->tcp_xid
- && req->rq_task->tk_rpcwait == &xprt->pending) {
- want = MIN(req->rq_rlen - xprt->tcp_copied, avail);
+/*
+ * TCP read and complete request
+ */
+static inline int
+tcp_read_request(struct rpc_xprt *xprt, struct rpc_rqst *req, int avail)
+{
+ int want, result;
+ if (req->rq_rlen <= xprt->tcp_copied || !avail)
+ goto done;
+ want = MIN(req->rq_rlen - xprt->tcp_copied, avail);
+ do {
dprintk("RPC: %4d TCP receiving %d bytes\n",
- req->rq_task->tk_pid, want);
- /* Request must be re-encoded before retransmit */
- req->rq_damaged = 1;
- result = xprt_recvmsg(xprt, xprt->tcp_iovec, req->rq_rnr, want);
+ req->rq_task->tk_pid, want);
+
+ result = xprt_recvmsg(xprt, req->rq_rvec, req->rq_rnr, want, xprt->tcp_copied);
if (result < 0)
- goto done;
+ return result;
xprt->tcp_copied += result;
- offset += result;
+ xprt->tcp_offset += result;
avail -= result;
- if (result < want) {
- result = -EAGAIN;
- goto done;
- }
+ want -= result;
+ } while (want);
- maxcpy = MIN(req->rq_rlen, xprt->tcp_total);
- if (xprt->tcp_copied == maxcpy && !xprt->tcp_more) {
- dprintk("RPC: %4d received reply complete\n",
- req->rq_task->tk_pid);
- xprt_complete_rqst(xprt, req, xprt->tcp_total);
- xprt->tcp_copied = 0;
- xprt->tcp_rqstp = NULL;
- }
- }
+ done:
+ if (req->rq_rlen > xprt->tcp_copied && xprt->tcp_more)
+ return avail;
+ dprintk("RPC: %4d received reply complete\n", req->rq_task->tk_pid);
+ xprt_complete_rqst(xprt, req, xprt->tcp_copied);
- /* Skip over any trailing bytes on short reads */
- while (avail > 0) {
- static u8 dummy[64];
+ return avail;
+}
+/*
+ * TCP discard extra bytes from a short read
+ */
+static inline int
+tcp_read_discard(struct rpc_xprt *xprt, int avail)
+{
+ struct iovec riov;
+ static u8 dummy[64];
+ int want, result = 0;
+
+ while (avail) {
want = MIN(avail, sizeof(dummy));
riov.iov_base = dummy;
riov.iov_len = want;
dprintk("RPC: TCP skipping %d bytes\n", want);
- result = xprt_recvmsg(xprt, &riov, 1, want);
+ result = xprt_recvmsg(xprt, &riov, 1, want, 0);
if (result < 0)
- goto done;
- offset += result;
+ return result;
+ xprt->tcp_offset += result;
avail -= result;
- if (result < want) {
- result = -EAGAIN;
- goto done;
+ }
+ return avail;
+}
+
+/*
+ * TCP record receive routine
+ * This is not the most efficient code since we call recvfrom thrice--
+ * first receiving the record marker, then the XID, then the data.
+ *
+ * The optimal solution would be a RPC support in the TCP layer, which
+ * would gather all data up to the next record marker and then pass us
+ * the list of all TCP segments ready to be copied.
+ */
+static int
+tcp_input_record(struct rpc_xprt *xprt)
+{
+ struct rpc_rqst *req = NULL;
+ struct rpc_task *task = NULL;
+ int avail, result;
+
+ dprintk("RPC: tcp_input_record\n");
+
+ if (xprt->shutdown)
+ return -EIO;
+ if (!xprt->connected)
+ return -ENOTCONN;
+
+ /* Read in a new fragment marker if necessary */
+ /* Can we ever really expect to get completely empty fragments? */
+ if ((result = tcp_read_fraghdr(xprt)) <= 0)
+ return result;
+ avail = result;
+
+ /* Read in the xid if necessary */
+ if ((result = tcp_read_xid(xprt, avail)) <= 0)
+ return result;
+ avail = result;
+
+ /* Find and lock the request corresponding to this xid */
+ req = xprt_lookup_rqst(xprt, xprt->tcp_xid);
+ if (req) {
+ task = req->rq_task;
+ if (xprt->tcp_copied == sizeof(xprt->tcp_xid) || req->rq_damaged) {
+ req->rq_damaged = 1;
+ /* Read in the request data */
+ result = tcp_read_request(xprt, req, avail);
}
+ rpc_unlock_task(task);
+ if (result < 0)
+ return result;
+ avail = result;
}
- if (!xprt->tcp_more)
- xprt->tcp_total = 0;
- offset = 0;
-done:
- dprintk("RPC: tcp_input_record done (off %d total %d copied %d)\n",
- offset, xprt->tcp_total, xprt->tcp_copied);
- xprt->tcp_offset = offset;
+ /* Skip over any trailing bytes on short reads */
+ if ((result = tcp_read_discard(xprt, avail)) < 0)
+ return result;
+
+ dprintk("RPC: tcp_input_record done (off %d reclen %d copied %d)\n",
+ xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_copied);
+ result = xprt->tcp_reclen;
return result;
}
/*
* TCP task queue stuff
*/
-
-static struct rpc_xprt *rpc_xprt_pending = NULL; /* Chain by rx_pending of rpc_xprt's */
+LIST_HEAD(rpc_xprt_pending); /* List of xprts having pending tcp requests */
+
+static inline
+void tcp_rpciod_queue(void)
+{
+ rpciod_wake_up();
+}
+
+static inline
+void xprt_append_pending(struct rpc_xprt *xprt)
+{
+ if (!list_empty(&xprt->rx_pending))
+ return;
+ spin_lock_bh(&rpc_queue_lock);
+ if (list_empty(&xprt->rx_pending)) {
+ list_add(&xprt->rx_pending, rpc_xprt_pending.prev);
+ dprintk("RPC: xprt queue %p\n", xprt);
+ tcp_rpciod_queue();
+ }
+ spin_unlock_bh(&rpc_queue_lock);
+}
+
+static
+void xprt_remove_pending(struct rpc_xprt *xprt)
+{
+ spin_lock_bh(&rpc_queue_lock);
+ if (!list_empty(&xprt->rx_pending)) {
+ list_del(&xprt->rx_pending);
+ INIT_LIST_HEAD(&xprt->rx_pending);
+ }
+ spin_unlock_bh(&rpc_queue_lock);
+}
+
+static inline
+struct rpc_xprt *xprt_remove_pending_next(void)
+{
+ struct rpc_xprt *xprt = NULL;
+
+ spin_lock_bh(&rpc_queue_lock);
+ if (!list_empty(&rpc_xprt_pending)) {
+ xprt = list_entry(rpc_xprt_pending.next, struct rpc_xprt, rx_pending);
+ list_del(&xprt->rx_pending);
+ INIT_LIST_HEAD(&xprt->rx_pending);
+ }
+ spin_unlock_bh(&rpc_queue_lock);
+ return xprt;
+}
/*
* This is protected from tcp_data_ready and the stack as its run
* inside of the RPC I/O daemon
*/
-static void
-do_rpciod_tcp_dispatcher(void)
+void
+__rpciod_tcp_dispatcher(void)
{
struct rpc_xprt *xprt;
- int result = 0;
+ int safe_retry = 0, result;
dprintk("rpciod_tcp_dispatcher: Queue Running\n");
/*
* Empty each pending socket
*/
-
- while(1) {
- int safe_retry=0;
-
- if ((xprt = rpc_xprt_pending) == NULL) {
- break;
- }
- xprt->rx_pending_flag = 0;
- rpc_xprt_pending=xprt->rx_pending;
- xprt->rx_pending = NULL;
-
+ while ((xprt = xprt_remove_pending_next()) != NULL) {
dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt);
- do
- {
- if (safe_retry++ > 50)
- break;
+ do {
result = tcp_input_record(xprt);
- }
- while (result >= 0);
-
- switch (result) {
- case -EAGAIN:
- case -ENOTCONN:
- case -EPIPE:
- continue;
- default:
- printk(KERN_WARNING "RPC: unexpected error %d from tcp_input_record\n",
- result);
+ } while (result >= 0);
+
+ if (safe_retry++ > 200) {
+ schedule();
+ safe_retry = 0;
}
}
}
-void rpciod_tcp_dispatcher(void)
-{
- /* mama... start_bh_atomic was here...
- Calls to sock->ops _are_ _impossible_ with disabled bh. Period. --ANK
- */
- do_rpciod_tcp_dispatcher();
-}
-
-int xprt_tcp_pending(void)
-{
- return rpc_xprt_pending != NULL;
-}
-
-extern inline void tcp_rpciod_queue(void)
-{
- rpciod_wake_up();
-}
-
/*
* data_ready callback for TCP. We can't just jump into the
* tcp recvmsg functions inside of the network receive bh or
@@ -874,24 +972,15 @@ static void tcp_data_ready(struct sock *sk, int len)
return;
}
+ if (xprt->shutdown)
+ return;
+
+ xprt_append_pending(xprt);
+
dprintk("RPC: tcp_data_ready client %p\n", xprt);
dprintk("RPC: state %x conn %d dead %d zapped %d\n",
sk->state, xprt->connected,
sk->dead, sk->zapped);
- /*
- * If we are not waiting for the RPC bh run then
- * we are now
- */
- if (!xprt->rx_pending_flag) {
- dprintk("RPC: xprt queue %p\n", rpc_xprt_pending);
-
- xprt->rx_pending=rpc_xprt_pending;
- rpc_xprt_pending=xprt;
- xprt->rx_pending_flag=1;
- } else
- dprintk("RPC: xprt queued already %p\n", xprt);
- tcp_rpciod_queue();
-
}
@@ -907,26 +996,20 @@ tcp_state_change(struct sock *sk)
sk->state, xprt->connected,
sk->dead, sk->zapped);
- switch(sk->state) {
+ spin_lock_bh(&xprt_sock_lock);
+ switch (sk->state) {
case TCP_ESTABLISHED:
- if (xprt->connected)
- break;
xprt->connected = 1;
- xprt->connecting = 0;
+ if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
+ rpc_wake_up_task(xprt->snd_task);
rpc_wake_up(&xprt->reconn);
- rpc_wake_up_next(&xprt->sending);
- tcp_rpciod_queue();
- break;
- case TCP_CLOSE:
- if (xprt->connecting)
- break;
- xprt_disconnect(xprt);
- rpc_wake_up_status(&xprt->reconn, -ENOTCONN);
break;
default:
+ xprt->connected = 0;
+ rpc_wake_up_status(&xprt->pending, -ENOTCONN);
break;
}
-
+ spin_unlock_bh(&xprt_sock_lock);
}
/*
@@ -940,20 +1023,23 @@ tcp_write_space(struct sock *sk)
if (!(xprt = xprt_from_sock(sk)))
return;
+ if (xprt->shutdown)
+ return;
/* Wait until we have enough socket memory */
if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
return;
+ spin_lock_bh(&xprt_sock_lock);
if (xprt->write_space)
- return;
+ goto out_unlock;
xprt->write_space = 1;
- if (!xprt->snd_task)
- rpc_wake_up_next(&xprt->sending);
- else if (!RPC_IS_RUNNING(xprt->snd_task))
+ if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
rpc_wake_up_task(xprt->snd_task);
+ out_unlock:
+ spin_unlock_bh(&xprt_sock_lock);
}
static void
@@ -963,20 +1049,24 @@ udp_write_space(struct sock *sk)
if (!(xprt = xprt_from_sock(sk)))
return;
+ if (xprt->shutdown)
+ return;
/* Wait until we have enough socket memory */
if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
return;
+ spin_lock_bh(&xprt_sock_lock);
if (xprt->write_space)
- return;
+ goto out_unlock;
xprt->write_space = 1;
- if (!xprt->snd_task)
- rpc_wake_up_next(&xprt->sending);
- else if (!RPC_IS_RUNNING(xprt->snd_task))
+
+ if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
rpc_wake_up_task(xprt->snd_task);
+ out_unlock:
+ spin_unlock_bh(&xprt_sock_lock);
}
/*
@@ -987,9 +1077,8 @@ xprt_timer(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
- if (req) {
+ if (req)
xprt_adjust_cwnd(task->tk_xprt, -ETIMEDOUT);
- }
dprintk("RPC: %4d xprt_timer (%s request)\n",
task->tk_pid, req ? "pending" : "backlogged");
@@ -1010,12 +1099,13 @@ xprt_down_transmit(struct rpc_task *task)
struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
struct rpc_rqst *req = task->tk_rqstp;
- spin_lock_bh(&xprt_lock);
+ spin_lock(&xprt_lock);
if (xprt->snd_task && xprt->snd_task != task) {
dprintk("RPC: %4d TCP write queue full (task %d)\n",
task->tk_pid, xprt->snd_task->tk_pid);
- task->tk_timeout = req->rq_timeout.to_current;
- rpc_sleep_on(&xprt->sending, task, xprt_transmit, NULL);
+ task->tk_timeout = 0;
+ task->tk_status = -EAGAIN;
+ rpc_sleep_on(&xprt->sending, task, NULL, NULL);
} else if (!xprt->snd_task) {
xprt->snd_task = task;
#ifdef RPC_PROFILE
@@ -1023,23 +1113,23 @@ xprt_down_transmit(struct rpc_task *task)
#endif
req->rq_bytes_sent = 0;
}
- spin_unlock_bh(&xprt_lock);
+ spin_unlock(&xprt_lock);
return xprt->snd_task == task;
}
/*
* Releases the socket for use by other requests.
*/
-static void
+static inline void
xprt_up_transmit(struct rpc_task *task)
{
struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
if (xprt->snd_task && xprt->snd_task == task) {
- spin_lock_bh(&xprt_lock);
+ spin_lock(&xprt_lock);
xprt->snd_task = NULL;
rpc_wake_up_next(&xprt->sending);
- spin_unlock_bh(&xprt_lock);
+ spin_unlock(&xprt_lock);
}
}
@@ -1050,7 +1140,6 @@ xprt_up_transmit(struct rpc_task *task)
void
xprt_transmit(struct rpc_task *task)
{
- struct rpc_timeout *timeo;
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = req->rq_xprt;
@@ -1060,26 +1149,21 @@ xprt_transmit(struct rpc_task *task)
if (xprt->shutdown)
task->tk_status = -EIO;
+ if (!xprt->connected)
+ task->tk_status = -ENOTCONN;
+
if (task->tk_status < 0)
return;
- /* Reset timeout parameters */
- timeo = &req->rq_timeout;
- if (timeo->to_retries < 0) {
- dprintk("RPC: %4d xprt_transmit reset timeo\n",
- task->tk_pid);
- timeo->to_retries = xprt->timeout.to_retries;
- timeo->to_current = timeo->to_initval;
- }
+ if (task->tk_rpcwait)
+ rpc_remove_wait_queue(task);
/* set up everything as needed. */
/* Write the record marker */
if (xprt->stream) {
- u32 marker;
-
- marker = htonl(0x80000000|(req->rq_slen-4));
- *((u32 *) req->rq_svec[0].iov_base) = marker;
+ u32 *marker = req->rq_svec[0].iov_base;
+ *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker)));
}
if (!xprt_down_transmit(task))
@@ -1095,24 +1179,14 @@ do_xprt_transmit(struct rpc_task *task)
struct rpc_xprt *xprt = req->rq_xprt;
int status, retry = 0;
- if (xprt->shutdown) {
- task->tk_status = -EIO;
- goto out_release;
- }
/* For fast networks/servers we have to put the request on
* the pending list now:
+ * Note that we don't want the task timing out during the
+ * call to xprt_sendmsg(), so we initially disable the timeout,
+ * and then reset it later...
*/
- req->rq_gotit = 0;
- status = rpc_add_wait_queue(&xprt->pending, task);
- if (!status)
- task->tk_callback = NULL;
-
- if (status) {
- printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
- task->tk_status = status;
- goto out_release;
- }
+ xprt_receive(task);
/* Continue transmitting the packet/record. We must be careful
* to cope with writespace callbacks arriving _after_ we have
@@ -1129,80 +1203,67 @@ do_xprt_transmit(struct rpc_task *task)
req->rq_bytes_sent += status;
if (req->rq_bytes_sent >= req->rq_slen)
- goto out_release;
- }
-
- if (status < req->rq_slen)
- status = -EAGAIN;
-
- if (status >= 0 || !xprt->stream) {
- dprintk("RPC: %4d xmit complete\n", task->tk_pid);
- goto out_release;
+ goto out_receive;
+ } else {
+ if (status >= req->rq_slen)
+ goto out_receive;
+ status = -ENOMEM;
+ break;
}
dprintk("RPC: %4d xmit incomplete (%d left of %d)\n",
task->tk_pid, req->rq_slen - req->rq_bytes_sent,
req->rq_slen);
+ status = -EAGAIN;
if (retry++ > 50)
break;
}
+ rpc_unlock_task(task);
- task->tk_status = (status == -ENOMEM) ? -EAGAIN : status;
+ task->tk_status = status;
- /* We don't care if we got a reply, so don't protect
- * against bh. */
- if (task->tk_rpcwait == &xprt->pending)
- rpc_remove_wait_queue(task);
+ /* Note: at this point, task->tk_sleeping has not yet been set,
+ * hence there is no danger of the waking up task being put on
+ * schedq, and being picked up by a parallel run of rpciod().
+ */
+ rpc_wake_up_task(task);
+ if (!RPC_IS_RUNNING(task))
+ goto out_release;
- /* Protect against (udp|tcp)_write_space */
- spin_lock_bh(&xprt_lock);
- if (status == -ENOMEM || status == -EAGAIN) {
+ switch (status) {
+ case -ENOMEM:
+ /* Protect against (udp|tcp)_write_space */
task->tk_timeout = req->rq_timeout.to_current;
+ spin_lock_bh(&xprt_sock_lock);
if (!xprt->write_space)
- rpc_sleep_on(&xprt->sending, task, xprt_transmit_status,
- xprt_transmit_timeout);
- spin_unlock_bh(&xprt_lock);
+ rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+ spin_unlock_bh(&xprt_sock_lock);
return;
- }
- spin_unlock_bh(&xprt_lock);
-
-out_release:
- xprt_up_transmit(task);
-}
-
-/*
- * This callback is invoked when the sending task is forced to sleep
- * because the TCP write buffers are full
- */
-static void
-xprt_transmit_status(struct rpc_task *task)
-{
- struct rpc_xprt *xprt = task->tk_client->cl_xprt;
-
- dprintk("RPC: %4d transmit_status %d\n", task->tk_pid, task->tk_status);
- if (xprt->snd_task == task) {
- task->tk_status = 0;
- do_xprt_transmit(task);
+ case -EAGAIN:
+ /* Keep holding the socket if it is blocked */
+ rpc_delay(task, HZ>>4);
return;
+ case -ECONNREFUSED:
+ case -ENOTCONN:
+ if (!xprt->stream)
+ return;
+ default:
+ goto out_release;
}
-}
-/*
- * RPC transmit timeout handler.
- */
-static void
-xprt_transmit_timeout(struct rpc_task *task)
-{
- dprintk("RPC: %4d transmit_timeout %d\n", task->tk_pid, task->tk_status);
- task->tk_status = -ETIMEDOUT;
- task->tk_timeout = 0;
- rpc_wake_up_task(task);
+ out_receive:
+ dprintk("RPC: %4d xmit complete\n", task->tk_pid);
+ /* Set the task's receive timeout value */
+ task->tk_timeout = req->rq_timeout.to_current;
+ rpc_add_timer(task, xprt_timer);
+ rpc_unlock_task(task);
+ out_release:
xprt_up_transmit(task);
}
/*
- * Wait for the reply to our call.
+ * Queue the task for a reply to our call.
* When the callback is invoked, the congestion window should have
* been updated already.
*/
@@ -1214,42 +1275,8 @@ xprt_receive(struct rpc_task *task)
dprintk("RPC: %4d xprt_receive\n", task->tk_pid);
- /*
- * Wait until rq_gotit goes non-null, or timeout elapsed.
- */
- task->tk_timeout = req->rq_timeout.to_current;
-
- spin_lock_bh(&xprt_lock);
- if (task->tk_rpcwait)
- rpc_remove_wait_queue(task);
-
- if (task->tk_status < 0 || xprt->shutdown) {
- spin_unlock_bh(&xprt_lock);
- goto out;
- }
-
- if (!req->rq_gotit) {
- rpc_sleep_on(&xprt->pending, task,
- xprt_receive_status, xprt_timer);
- spin_unlock_bh(&xprt_lock);
- return;
- }
- spin_unlock_bh(&xprt_lock);
-
- dprintk("RPC: %4d xprt_receive returns %d\n",
- task->tk_pid, task->tk_status);
- out:
- xprt_receive_status(task);
-}
-
-static void
-xprt_receive_status(struct rpc_task *task)
-{
- struct rpc_xprt *xprt = task->tk_xprt;
-
- if (xprt->tcp_rqstp == task->tk_rqstp)
- xprt->tcp_rqstp = NULL;
-
+ task->tk_timeout = 0;
+ rpc_sleep_locked(&xprt->pending, task, NULL, NULL);
}
/*
@@ -1335,7 +1362,6 @@ xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, xid);
task->tk_status = 0;
- req->rq_gotit = 0;
req->rq_timeout = xprt->timeout;
req->rq_task = task;
req->rq_xprt = xprt;
@@ -1353,6 +1379,7 @@ xprt_release(struct rpc_task *task)
struct rpc_xprt *xprt = task->tk_xprt;
struct rpc_rqst *req;
+ xprt_up_transmit(task);
if (!(req = task->tk_rqstp))
return;
task->tk_rqstp = NULL;
@@ -1363,16 +1390,16 @@ xprt_release(struct rpc_task *task)
spin_lock(&xprt_lock);
req->rq_next = xprt->free;
xprt->free = req;
- spin_unlock(&xprt_lock);
/* remove slot from queue of pending */
- spin_lock_bh(&xprt_lock);
if (task->tk_rpcwait) {
printk("RPC: task of released request still queued!\n");
- rpc_del_timer(task);
+#ifdef RPC_DEBUG
+ printk("RPC: (task is on %s)\n", rpc_qname(task->tk_rpcwait));
+#endif
rpc_remove_wait_queue(task);
}
- spin_unlock_bh(&xprt_lock);
+ spin_unlock(&xprt_lock);
/* Decrease congestion value. */
xprt->cong -= RPC_CWNDSCALE;
@@ -1389,7 +1416,7 @@ xprt_default_timeout(struct rpc_timeout *to, int proto)
if (proto == IPPROTO_UDP)
xprt_set_timeout(to, 5, 5 * HZ);
else
- xprt_set_timeout(to, 5, 15 * HZ);
+ xprt_set_timeout(to, 5, 60 * HZ);
}
/*
@@ -1416,52 +1443,33 @@ xprt_setup(struct socket *sock, int proto,
{
struct rpc_xprt *xprt;
struct rpc_rqst *req;
- struct sock *inet;
int i;
dprintk("RPC: setting up %s transport...\n",
proto == IPPROTO_UDP? "UDP" : "TCP");
- inet = sock->sk;
-
if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
return NULL;
memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */
- xprt->file = NULL;
- xprt->sock = sock;
- xprt->inet = inet;
xprt->addr = *ap;
xprt->prot = proto;
xprt->stream = (proto == IPPROTO_TCP)? 1 : 0;
- xprt->congtime = jiffies;
- init_waitqueue_head(&xprt->cong_wait);
- inet->user_data = xprt;
- xprt->old_data_ready = inet->data_ready;
- xprt->old_state_change = inet->state_change;
- xprt->old_write_space = inet->write_space;
- if (proto == IPPROTO_UDP) {
- inet->data_ready = udp_data_ready;
- inet->write_space = udp_write_space;
- inet->no_check = UDP_CSUM_NORCV;
- xprt->cwnd = RPC_INITCWND;
- } else {
- inet->data_ready = tcp_data_ready;
- inet->state_change = tcp_state_change;
- inet->write_space = tcp_write_space;
+ if (xprt->stream) {
xprt->cwnd = RPC_MAXCWND;
xprt->nocong = 1;
- }
- xprt->connected = 1;
+ } else
+ xprt->cwnd = RPC_INITCWND;
+ xprt->congtime = jiffies;
+ init_waitqueue_head(&xprt->cong_wait);
/* Set timeout parameters */
if (to) {
xprt->timeout = *to;
xprt->timeout.to_current = to->to_initval;
xprt->timeout.to_resrvval = to->to_maxval << 1;
- } else {
+ } else
xprt_default_timeout(&xprt->timeout, xprt->prot);
- }
xprt->pending = RPC_INIT_WAITQ("xprt_pending");
xprt->sending = RPC_INIT_WAITQ("xprt_sending");
@@ -1474,13 +1482,11 @@ xprt_setup(struct socket *sock, int proto,
req->rq_next = NULL;
xprt->free = xprt->slot;
+ INIT_LIST_HEAD(&xprt->rx_pending);
+
dprintk("RPC: created transport %p\n", xprt);
- /*
- * TCP requires the rpc I/O daemon is present
- */
- if(proto==IPPROTO_TCP)
- rpciod_up();
+ xprt_bind_socket(xprt, sock);
return xprt;
}
@@ -1508,17 +1514,52 @@ xprt_bindresvport(struct socket *sock)
return err;
}
+static int
+xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ if (xprt->inet)
+ return -EBUSY;
+
+ sk->user_data = xprt;
+ xprt->old_data_ready = sk->data_ready;
+ xprt->old_state_change = sk->state_change;
+ xprt->old_write_space = sk->write_space;
+ if (xprt->prot == IPPROTO_UDP) {
+ sk->data_ready = udp_data_ready;
+ sk->write_space = udp_write_space;
+ sk->no_check = UDP_CSUM_NORCV;
+ xprt->connected = 1;
+ } else {
+ sk->data_ready = tcp_data_ready;
+ sk->state_change = tcp_state_change;
+ sk->write_space = tcp_write_space;
+ xprt->connected = 0;
+ }
+
+ /* Reset to new socket */
+ xprt->sock = sock;
+ xprt->inet = sk;
+ /*
+ * TCP requires the rpc I/O daemon is present
+ */
+ if(xprt->stream)
+ rpciod_up();
+
+ return 0;
+}
+
/*
* Create a client socket given the protocol and peer address.
*/
static struct socket *
-xprt_create_socket(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
+xprt_create_socket(int proto, struct rpc_timeout *to)
{
struct socket *sock;
int type, err;
- dprintk("RPC: xprt_create_socket(%08x, %s %d)\n",
- sap? ntohl(sap->sin_addr.s_addr) : 0,
+ dprintk("RPC: xprt_create_socket(%s %d)\n",
(proto == IPPROTO_UDP)? "udp" : "tcp", proto);
type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
@@ -1532,15 +1573,6 @@ xprt_create_socket(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
if (!current->fsuid && xprt_bindresvport(sock) < 0)
goto failed;
- if (type == SOCK_STREAM && sap) {
- err = sock->ops->connect(sock, (struct sockaddr *) sap,
- sizeof(*sap), 0);
- if (err < 0) {
- printk("RPC: TCP connect failed (%d).\n", -err);
- goto failed;
- }
- }
-
return sock;
failed:
@@ -1559,7 +1591,7 @@ xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
dprintk("RPC: xprt_create_proto called\n");
- if (!(sock = xprt_create_socket(proto, sap, to)))
+ if (!(sock = xprt_create_socket(proto, to)))
return NULL;
if (!(xprt = xprt_setup(sock, proto, sap, to)))
@@ -1587,8 +1619,6 @@ xprt_shutdown(struct rpc_xprt *xprt)
*/
int
xprt_clear_backlog(struct rpc_xprt *xprt) {
- if (!xprt)
- return 0;
if (RPCXPRT_CONGESTED(xprt))
return 0;
rpc_wake_up_next(&xprt->backlog);
@@ -1603,6 +1633,7 @@ int
xprt_destroy(struct rpc_xprt *xprt)
{
dprintk("RPC: destroying transport %p\n", xprt);
+ xprt_shutdown(xprt);
xprt_close(xprt);
kfree(xprt);
diff --git a/scripts/mkdep.c b/scripts/mkdep.c
index cb62dce5d..55a9a15a3 100644
--- a/scripts/mkdep.c
+++ b/scripts/mkdep.c
@@ -18,6 +18,10 @@
* the definition is inactivated, but I still used it. It turns out this
* actually happens a few times in the kernel source. The simple way to
* fix this problem is to remove this particular optimization.
+ *
+ * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
+ * - Changed so that 'filename.o' depends upon 'filename.[cS]'. This is so that
+ * missing source files are noticed, rather than silently ignored.
*/
#include <ctype.h>
@@ -47,6 +51,8 @@ struct path_struct {
};
+/* Current input file */
+static const char *g_filename;
/*
* This records all the configuration options seen.
@@ -58,7 +64,16 @@ char * str_config = NULL;
int size_config = 0;
int len_config = 0;
-
+static void
+do_depname(void)
+{
+ if (!hasdep) {
+ hasdep = 1;
+ printf("%s:", depname);
+ if (g_filename)
+ printf(" %s", g_filename);
+ }
+}
/*
* Grow the configuration string to a desired length.
@@ -193,10 +208,7 @@ void handle_include(int type, const char * name, int len)
if (access(path->buffer, F_OK) != 0)
return;
- if (!hasdep) {
- hasdep = 1;
- printf("%s:", depname);
- }
+ do_depname();
printf(" \\\n %s", path->buffer);
}
@@ -227,10 +239,7 @@ void use_config(const char * name, int len)
define_config(pc, len);
- if (!hasdep) {
- hasdep = 1;
- printf("%s: ", depname);
- }
+ do_depname();
printf(" \\\n $(wildcard %s.h)", path_array[0].buffer);
}
@@ -549,11 +558,13 @@ int main(int argc, char **argv)
while (--argc > 0) {
const char * filename = *++argv;
const char * command = __depname;
+ g_filename = 0;
len = strlen(filename);
memcpy(depname, filename, len+1);
if (len > 2 && filename[len-2] == '.') {
if (filename[len-1] == 'c' || filename[len-1] == 'S') {
depname[len-1] = 'o';
+ g_filename = filename;
command = "";
}
}