summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
commit46e045034336a2cc90c1798cd7cc07af744ddfd6 (patch)
tree3b9b51fc482e729f663d25333e77fbed9aaa939a
parent31dc59d503a02e84c4de98826452acaeb56dc15a (diff)
Merge with Linux 2.3.99-pre4.
-rw-r--r--CREDITS27
-rw-r--r--Documentation/Configure.help3928
-rw-r--r--Documentation/DocBook/Makefile36
-rw-r--r--Documentation/DocBook/kernel-api.tmpl94
-rw-r--r--Documentation/DocBook/parportbook.tmpl (renamed from Documentation/DocBook/parportbook.sgml)0
-rw-r--r--Documentation/arm/SA1100/Brutus2
-rw-r--r--Documentation/arm/SA1100/ThinClient33
-rw-r--r--Documentation/filesystems/ntfs.txt11
-rw-r--r--Documentation/sound/CMI833031
-rw-r--r--Documentation/sound/PAS16185
-rw-r--r--Documentation/sound/SoundPro2
-rw-r--r--Documentation/sysrq.txt18
-rw-r--r--Documentation/usb/CREDITS1
-rw-r--r--Documentation/usb/acm.txt232
-rw-r--r--Documentation/usb/hid.txt162
-rw-r--r--Documentation/usb/ibmcam.txt58
-rw-r--r--Documentation/usb/input.txt294
-rw-r--r--Documentation/usb/ov511.txt44
-rw-r--r--Documentation/usb/proc_usb_info.txt35
-rw-r--r--Documentation/usb/scanner-hp-sane.txt10
-rw-r--r--Documentation/usb/scanner.txt83
-rw-r--r--Documentation/usb/usb-help.txt16
-rw-r--r--Documentation/video4linux/README.cpia191
-rw-r--r--Documentation/video4linux/bttv/CARDLIST2
-rw-r--r--MAINTAINERS10
-rw-r--r--Makefile25
-rw-r--r--Rules.make2
-rw-r--r--arch/alpha/boot/Makefile4
-rw-r--r--arch/alpha/config.in6
-rw-r--r--arch/alpha/defconfig2
-rw-r--r--arch/alpha/kernel/Makefile4
-rw-r--r--arch/alpha/kernel/irq_i8259.c6
-rw-r--r--arch/alpha/kernel/osf_sys.c89
-rw-r--r--arch/arm/Makefile9
-rw-r--r--arch/arm/boot/compressed/head-sa1100.S5
-rw-r--r--arch/arm/config.in7
-rw-r--r--arch/arm/def-configs/brutus71
-rw-r--r--arch/arm/def-configs/footbridge356
-rw-r--r--arch/arm/def-configs/thinclient379
-rw-r--r--arch/arm/defconfig3
-rw-r--r--arch/arm/kernel/Makefile4
-rw-r--r--arch/arm/kernel/arch.c11
-rw-r--r--arch/arm/kernel/armksyms.c2
-rw-r--r--arch/arm/kernel/bios32.c4
-rw-r--r--arch/arm/kernel/entry-armv.S72
-rw-r--r--arch/arm/kernel/process.c29
-rw-r--r--arch/arm/kernel/setup.c4
-rw-r--r--arch/arm/lib/Makefile2
-rw-r--r--arch/arm/mm/Makefile2
-rw-r--r--arch/arm/mm/mm-armv.c7
-rw-r--r--arch/arm/mm/mm-sa1100.c18
-rw-r--r--arch/arm/mm/mm-shark.c25
-rw-r--r--arch/arm/mm/proc-sa110.S34
-rw-r--r--arch/i386/boot/compressed/head.S1
-rw-r--r--arch/i386/config.in14
-rw-r--r--arch/i386/defconfig38
-rw-r--r--arch/i386/kernel/Makefile2
-rw-r--r--arch/i386/kernel/acpi.c369
-rw-r--r--arch/i386/kernel/head.S18
-rw-r--r--arch/i386/kernel/irq.c2
-rw-r--r--arch/i386/kernel/mtrr.c2
-rw-r--r--arch/i386/kernel/pci-i386.c4
-rw-r--r--arch/i386/kernel/pci-pc.c2
-rw-r--r--arch/i386/kernel/setup.c4
-rw-r--r--arch/i386/lib/Makefile2
-rw-r--r--arch/i386/math-emu/Makefile2
-rw-r--r--arch/ia64/boot/Makefile4
-rw-r--r--arch/ia64/config.in12
-rw-r--r--arch/ia64/defconfig8
-rw-r--r--arch/ia64/dig/Makefile4
-rw-r--r--arch/ia64/ia32/Makefile4
-rw-r--r--arch/ia64/ia32/sys_ia32.c11
-rw-r--r--arch/ia64/kdb/Makefile2
-rw-r--r--arch/ia64/kernel/Makefile4
-rw-r--r--arch/ia64/lib/Makefile2
-rw-r--r--arch/ia64/sn/Makefile4
-rw-r--r--arch/ia64/sn/sn1/Makefile4
-rw-r--r--arch/m68k/config.in43
-rw-r--r--arch/m68k/defconfig6
-rw-r--r--arch/m68k/fpsp040/Makefile2
-rw-r--r--arch/m68k/ifpsp060/Makefile2
-rw-r--r--arch/m68k/kernel/Makefile2
-rw-r--r--arch/m68k/lib/Makefile2
-rw-r--r--arch/m68k/math-emu/Makefile2
-rw-r--r--arch/m68k/sun3/Makefile2
-rw-r--r--arch/mips/config.in23
-rw-r--r--arch/mips/defconfig37
-rw-r--r--arch/mips/defconfig-decstation90
-rw-r--r--arch/mips/defconfig-ip2237
-rw-r--r--arch/mips/kernel/sysirix.c2
-rw-r--r--arch/mips64/config.in14
-rw-r--r--arch/mips64/defconfig42
-rw-r--r--arch/mips64/defconfig-ip2240
-rw-r--r--arch/mips64/defconfig-ip2742
-rw-r--r--arch/mips64/sgi-ip27/ip27-memory.c2
-rw-r--r--arch/ppc/8xx_io/enet.c51
-rw-r--r--arch/ppc/8xx_io/uart.c2
-rw-r--r--arch/ppc/Makefile2
-rw-r--r--arch/ppc/boot/Makefile4
-rw-r--r--arch/ppc/chrpboot/Makefile4
-rw-r--r--arch/ppc/config.in10
-rw-r--r--arch/ppc/defconfig3
-rw-r--r--arch/ppc/kernel/feature.c8
-rw-r--r--arch/ppc/kernel/m8xx_setup.c1
-rw-r--r--arch/ppc/lib/Makefile2
-rw-r--r--arch/ppc/math-emu/math.c56
-rw-r--r--arch/ppc/math-emu/sfp-machine.h2
-rw-r--r--arch/ppc/mbxboot/Makefile6
-rw-r--r--arch/ppc/mm/fault.c42
-rw-r--r--arch/sh/Makefile2
-rw-r--r--arch/sh/config.in5
-rw-r--r--arch/sh/defconfig2
-rw-r--r--arch/sh/kernel/Makefile4
-rw-r--r--arch/sh/kernel/entry.S556
-rw-r--r--arch/sh/kernel/fpu.c6
-rw-r--r--arch/sh/kernel/head.S9
-rw-r--r--arch/sh/kernel/irq.c6
-rw-r--r--arch/sh/kernel/irq_imask.c39
-rw-r--r--arch/sh/kernel/process.c35
-rw-r--r--arch/sh/kernel/ptrace.c595
-rw-r--r--arch/sh/kernel/signal.c77
-rw-r--r--arch/sh/lib/Makefile2
-rw-r--r--arch/sh/mm/cache.c83
-rw-r--r--arch/sh/mm/fault.c27
-rw-r--r--arch/sh/mm/init.c2
-rw-r--r--arch/sparc/config.in4
-rw-r--r--arch/sparc/defconfig2
-rw-r--r--arch/sparc/kernel/Makefile10
-rw-r--r--arch/sparc/kernel/ioport.c50
-rw-r--r--arch/sparc/kernel/setup.c9
-rw-r--r--arch/sparc/kernel/signal.c4
-rw-r--r--arch/sparc/kernel/sys_sunos.c97
-rw-r--r--arch/sparc/lib/Makefile4
-rw-r--r--arch/sparc/math-emu/Makefile4
-rw-r--r--arch/sparc/mm/Makefile15
-rw-r--r--arch/sparc/mm/sun4c.c12
-rw-r--r--arch/sparc64/config.in5
-rw-r--r--arch/sparc64/defconfig4
-rw-r--r--arch/sparc64/kernel/Makefile12
-rw-r--r--arch/sparc64/kernel/dtlb_base.S24
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S8
-rw-r--r--arch/sparc64/kernel/ebus.c14
-rw-r--r--arch/sparc64/kernel/entry.S39
-rw-r--r--arch/sparc64/kernel/etrap.S309
-rw-r--r--arch/sparc64/kernel/ioctl32.c21
-rw-r--r--arch/sparc64/kernel/itlb_base.S26
-rw-r--r--arch/sparc64/kernel/pci_common.c161
-rw-r--r--arch/sparc64/kernel/pci_impl.h6
-rw-r--r--arch/sparc64/kernel/pci_psycho.c25
-rw-r--r--arch/sparc64/kernel/pci_sabre.c22
-rw-r--r--arch/sparc64/kernel/process.c57
-rw-r--r--arch/sparc64/kernel/rtrap.S253
-rw-r--r--arch/sparc64/kernel/semaphore.c10
-rw-r--r--arch/sparc64/kernel/signal.c4
-rw-r--r--arch/sparc64/kernel/signal32.c4
-rw-r--r--arch/sparc64/kernel/smp.c96
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c9
-rw-r--r--arch/sparc64/kernel/sys32.S188
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c110
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c122
-rw-r--r--arch/sparc64/kernel/winfixup.S28
-rw-r--r--arch/sparc64/lib/Makefile8
-rw-r--r--arch/sparc64/lib/VIScopy.S6
-rw-r--r--arch/sparc64/lib/bitops.S110
-rw-r--r--arch/sparc64/lib/blockops.S60
-rw-r--r--arch/sparc64/mm/Makefile4
-rw-r--r--arch/sparc64/mm/fault.c382
-rw-r--r--arch/sparc64/mm/ultra.S85
-rw-r--r--arch/sparc64/prom/Makefile4
-rw-r--r--arch/sparc64/solaris/Makefile4
-rw-r--r--arch/sparc64/solaris/fs.c41
-rw-r--r--arch/sparc64/solaris/misc.c2
-rw-r--r--arch/sparc64/solaris/socksys.c3
-rw-r--r--arch/sparc64/solaris/timod.c4
-rw-r--r--drivers/acorn/char/keyb_ps2.c7
-rw-r--r--drivers/acorn/scsi/acornscsi.h5
-rw-r--r--drivers/acorn/scsi/arxescsi.c21
-rw-r--r--drivers/acorn/scsi/arxescsi.h38
-rw-r--r--drivers/acorn/scsi/cumana_2.c55
-rw-r--r--drivers/acorn/scsi/cumana_2.h45
-rw-r--r--drivers/acorn/scsi/eesox.c76
-rw-r--r--drivers/acorn/scsi/eesox.h37
-rw-r--r--drivers/acorn/scsi/fas216.c1032
-rw-r--r--drivers/acorn/scsi/fas216.h12
-rw-r--r--drivers/acorn/scsi/msgqueue.h2
-rw-r--r--drivers/acorn/scsi/powertec.c51
-rw-r--r--drivers/acorn/scsi/powertec.h43
-rw-r--r--drivers/acorn/scsi/queue.h2
-rw-r--r--drivers/atm/fore200e.c3
-rw-r--r--drivers/block/Config.in36
-rw-r--r--drivers/block/ll_rw_blk.c34
-rw-r--r--drivers/block/lvm.c2
-rw-r--r--drivers/block/md.c213
-rw-r--r--drivers/block/nbd.c8
-rw-r--r--drivers/block/paride/pcd.c2
-rw-r--r--drivers/block/paride/pd.c76
-rw-r--r--drivers/block/paride/pf.c76
-rw-r--r--drivers/block/rd.c3
-rw-r--r--drivers/block/xd.c43
-rw-r--r--drivers/char/Config.in12
-rw-r--r--drivers/char/Makefile8
-rw-r--r--drivers/char/agp/agpgart_be.c24
-rw-r--r--drivers/char/applicom.c544
-rw-r--r--drivers/char/bttv.c241
-rw-r--r--drivers/char/bttv.h5
-rw-r--r--drivers/char/console.c2
-rw-r--r--drivers/char/cpia.c3319
-rw-r--r--drivers/char/cpia.h421
-rw-r--r--drivers/char/cpia_pp.c745
-rw-r--r--drivers/char/cpia_usb.c626
-rw-r--r--drivers/char/joystick/joy-spaceball.c6
-rw-r--r--drivers/char/joystick/joy-spaceorb.c6
-rw-r--r--drivers/char/joystick/joy-warrior.c25
-rw-r--r--drivers/char/joystick/joystick.c84
-rw-r--r--drivers/char/mem.c6
-rw-r--r--drivers/char/n_r3964.c10
-rw-r--r--drivers/char/pcwd.c33
-rw-r--r--drivers/char/ppdev.c2
-rw-r--r--drivers/char/pty.c4
-rw-r--r--drivers/char/serial.c7
-rw-r--r--drivers/char/sh-sci.c39
-rw-r--r--drivers/char/sh-sci.h46
-rw-r--r--drivers/char/tty_io.c15
-rw-r--r--drivers/char/tuner.c3
-rw-r--r--drivers/char/videodev.c8
-rw-r--r--drivers/char/wd501p.h25
-rw-r--r--drivers/char/wdt_pci.c558
-rw-r--r--drivers/i2c/i2c-elektor.c2
-rw-r--r--drivers/ide/ide-disk.c20
-rw-r--r--drivers/ide/ide-pci.c2
-rw-r--r--drivers/ide/ide.c1
-rw-r--r--drivers/net/8390.c19
-rw-r--r--drivers/net/Config.in7
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/Space.c8
-rw-r--r--drivers/net/defxx.c194
-rw-r--r--drivers/net/defxx.h1
-rw-r--r--drivers/net/eepro100.c1604
-rw-r--r--drivers/net/loopback.c14
-rw-r--r--drivers/net/pcmcia/Config.in1
-rw-r--r--drivers/net/pcmcia/Makefile9
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c635
-rw-r--r--drivers/net/ppp_async.c31
-rw-r--r--drivers/net/ppp_generic.c272
-rw-r--r--drivers/net/ppp_synctty.c567
-rw-r--r--drivers/net/sk98lin/skge.c15
-rw-r--r--drivers/net/sunhme.c17
-rw-r--r--drivers/net/tokenring/Config.in4
-rw-r--r--drivers/net/tokenring/ibmtr.c50
-rw-r--r--drivers/net/wan/cycx_drv.c25
-rw-r--r--drivers/net/wan/cycx_main.c26
-rw-r--r--drivers/net/wan/cycx_x25.c24
-rw-r--r--drivers/net/wan/z85230.c2
-rw-r--r--drivers/parport/ChangeLog5
-rw-r--r--drivers/parport/parport_pc.c27
-rw-r--r--drivers/parport/parport_sunbpp.c4
-rw-r--r--drivers/parport/share.c235
-rw-r--r--drivers/pci/gen-devlist.c26
-rw-r--r--drivers/pci/pci.ids4
-rw-r--r--drivers/pci/setup-res.c2
-rw-r--r--drivers/scsi/ChangeLog.ncr53c8xx10
-rw-r--r--drivers/scsi/ChangeLog.sym53c8xx8
-rw-r--r--drivers/scsi/Config.in31
-rw-r--r--drivers/scsi/Makefile8
-rw-r--r--drivers/scsi/dmx3191d.c125
-rw-r--r--drivers/scsi/dmx3191d.h74
-rw-r--r--drivers/scsi/esp.c9
-rw-r--r--drivers/scsi/esp.h4
-rw-r--r--drivers/scsi/hosts.c7
-rw-r--r--drivers/scsi/hosts.h2
-rw-r--r--drivers/scsi/ncr53c8xx.c34
-rw-r--r--drivers/scsi/qlogicisp.c8
-rw-r--r--drivers/scsi/scsi.c2
-rw-r--r--drivers/scsi/sd.c4
-rw-r--r--drivers/scsi/sg.c52
-rw-r--r--drivers/scsi/sym53c8xx.c35
-rw-r--r--drivers/scsi/sym53c8xx_comm.h10
-rw-r--r--drivers/scsi/wd33c93.c2
-rw-r--r--drivers/sound/Makefile16
-rw-r--r--drivers/sound/ad1816.c3
-rw-r--r--drivers/sound/aedsp16.c1
-rw-r--r--drivers/sound/dev_table.c39
-rw-r--r--drivers/sound/dev_table.h16
-rw-r--r--drivers/sound/dmasound.c5821
-rw-r--r--drivers/sound/dmasound.h36
-rw-r--r--drivers/sound/dmasound/.cvsignore5
-rw-r--r--drivers/sound/dmasound/Config.in27
-rw-r--r--drivers/sound/dmasound/Makefile38
-rw-r--r--drivers/sound/dmasound/dmasound.h246
-rw-r--r--drivers/sound/dmasound/dmasound_atari.c1560
-rw-r--r--drivers/sound/dmasound/dmasound_awacs.c2113
-rw-r--r--drivers/sound/dmasound/dmasound_core.c1313
-rw-r--r--drivers/sound/dmasound/dmasound_paula.c690
-rw-r--r--drivers/sound/dmasound/dmasound_q40.c587
-rw-r--r--drivers/sound/mad16.c2
-rw-r--r--drivers/sound/sb.h15
-rw-r--r--drivers/sound/sb_card.c47
-rw-r--r--drivers/sound/sb_common.c20
-rw-r--r--drivers/sound/sb_ess.c14
-rw-r--r--drivers/sound/sb_mixer.c3
-rw-r--r--drivers/sound/sound_calls.h7
-rw-r--r--drivers/sound/sound_core.c20
-rw-r--r--drivers/sound/soundcard.c163
-rw-r--r--drivers/sound/trix.c2
-rw-r--r--drivers/sound/via82cxxx_audio.c2
-rw-r--r--drivers/telephony/phonedev.c24
-rw-r--r--drivers/usb/Config.in33
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/acm.c38
-rw-r--r--drivers/usb/audio.c62
-rw-r--r--drivers/usb/audio.h2
-rw-r--r--drivers/usb/cpia.c1425
-rw-r--r--drivers/usb/cpia.h205
-rw-r--r--drivers/usb/devices.c3
-rw-r--r--drivers/usb/devio.c2
-rw-r--r--drivers/usb/drivers.c4
-rw-r--r--drivers/usb/evdev.c122
-rw-r--r--drivers/usb/hid.c2
-rw-r--r--drivers/usb/hub.c30
-rw-r--r--drivers/usb/ibmcam.c39
-rw-r--r--drivers/usb/inode.c3
-rw-r--r--drivers/usb/input.c155
-rw-r--r--drivers/usb/joydev.c91
-rw-r--r--drivers/usb/keybdev.c131
-rw-r--r--drivers/usb/mdc800.c74
-rw-r--r--drivers/usb/mousedev.c312
-rw-r--r--drivers/usb/ov511.c663
-rw-r--r--drivers/usb/ov511.h63
-rw-r--r--drivers/usb/pegasus.c53
-rw-r--r--drivers/usb/printer.c10
-rw-r--r--drivers/usb/scanner.c125
-rw-r--r--drivers/usb/scanner.h7
-rw-r--r--drivers/usb/serial/Makefile62
-rw-r--r--drivers/usb/serial/ezusb_convert.pl4
-rw-r--r--drivers/usb/serial/ftdi_sio.c728
-rw-r--r--drivers/usb/serial/ftdi_sio.h573
-rw-r--r--drivers/usb/serial/keyspan_pda.c717
-rw-r--r--drivers/usb/serial/usb-serial.c2593
-rw-r--r--drivers/usb/serial/usb-serial.h376
-rw-r--r--drivers/usb/serial/usbserial.c1323
-rw-r--r--drivers/usb/serial/visor.c209
-rw-r--r--drivers/usb/serial/visor.h74
-rw-r--r--drivers/usb/serial/whiteheat.c251
-rw-r--r--drivers/usb/serial/whiteheat_fw.h (renamed from drivers/usb/serial/whiteheat.h)1552
-rw-r--r--drivers/usb/uhci.c404
-rw-r--r--drivers/usb/uhci.h31
-rw-r--r--drivers/usb/usb-core.c5
-rw-r--r--drivers/usb/usb-debug.c7
-rw-r--r--drivers/usb/usb-ohci.c348
-rw-r--r--drivers/usb/usb-storage.c1279
-rw-r--r--drivers/usb/usb-storage.h8
-rw-r--r--drivers/usb/usb-uhci.c73
-rw-r--r--drivers/usb/usb-uhci.h9
-rw-r--r--drivers/usb/usb.c63
-rw-r--r--drivers/video/Config.in12
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/amifb.c2
-rw-r--r--drivers/video/aty128fb.c2
-rw-r--r--drivers/video/atyfb.c2
-rw-r--r--drivers/video/fbmem.c5
-rw-r--r--drivers/video/sa1100fb.c1147
-rw-r--r--drivers/video/tgafb.c2
-rw-r--r--fs/Config.in70
-rw-r--r--fs/Makefile10
-rw-r--r--fs/adfs/dir.c2
-rw-r--r--fs/autofs/dirhash.c3
-rw-r--r--fs/autofs/root.c6
-rw-r--r--fs/autofs/symlink.c4
-rw-r--r--fs/autofs4/expire.c6
-rw-r--r--fs/autofs4/root.c4
-rw-r--r--fs/autofs4/symlink.c6
-rw-r--r--fs/bad_inode.c27
-rw-r--r--fs/dcache.c191
-rw-r--r--fs/devfs/base.c13
-rw-r--r--fs/dquot.c21
-rw-r--r--fs/exec.c19
-rw-r--r--fs/ext2/namei.c295
-rw-r--r--fs/ext2/super.c9
-rw-r--r--fs/ext2/symlink.c4
-rw-r--r--fs/file_table.c4
-rw-r--r--fs/hfs/dir.c12
-rw-r--r--fs/hpfs/dir.c2
-rw-r--r--fs/inode.c128
-rw-r--r--fs/ioctl.c4
-rw-r--r--fs/lockd/clntlock.c2
-rw-r--r--fs/lockd/clntproc.c98
-rw-r--r--fs/lockd/host.c35
-rw-r--r--fs/lockd/mon.c44
-rw-r--r--fs/lockd/svc4proc.c14
-rw-r--r--fs/lockd/svclock.c44
-rw-r--r--fs/lockd/svcproc.c9
-rw-r--r--fs/lockd/svcsubs.c4
-rw-r--r--fs/lockd/xdr.c95
-rw-r--r--fs/lockd/xdr4.c82
-rw-r--r--fs/locks.c47
-rw-r--r--fs/namei.c801
-rw-r--r--fs/ncpfs/Config.in20
-rw-r--r--fs/nfs/Makefile3
-rw-r--r--fs/nfs/dir.c845
-rw-r--r--fs/nfs/file.c5
-rw-r--r--fs/nfs/flushd.c1
-rw-r--r--fs/nfs/inode.c494
-rw-r--r--fs/nfs/mount_clnt.c65
-rw-r--r--fs/nfs/nfs2xdr.c390
-rw-r--r--fs/nfs/nfs3proc.c477
-rw-r--r--fs/nfs/nfs3xdr.c1147
-rw-r--r--fs/nfs/nfsroot.c45
-rw-r--r--fs/nfs/proc.c328
-rw-r--r--fs/nfs/read.c56
-rw-r--r--fs/nfs/symlink.c22
-rw-r--r--fs/nfs/write.c181
-rw-r--r--fs/nfsd/export.c7
-rw-r--r--fs/nfsd/lockd.c3
-rw-r--r--fs/nfsd/nfs3xdr.c11
-rw-r--r--fs/nfsd/nfsctl.c1
-rw-r--r--fs/nfsd/vfs.c47
-rw-r--r--fs/ntfs/Makefile2
-rw-r--r--fs/ntfs/fs.c4
-rw-r--r--fs/open.c123
-rw-r--r--fs/partitions/Config.in7
-rw-r--r--fs/proc/array.c4
-rw-r--r--fs/proc/base.c89
-rw-r--r--fs/proc/generic.c4
-rw-r--r--fs/proc/root.c6
-rw-r--r--fs/ramfs/.cvsignore2
-rw-r--r--fs/ramfs/Makefile11
-rw-r--r--fs/ramfs/inode.c393
-rw-r--r--fs/read_write.c13
-rw-r--r--fs/super.c203
-rw-r--r--fs/udf/file.c2
-rw-r--r--fs/udf/inode.c10
-rw-r--r--fs/ufs/symlink.c4
-rw-r--r--fs/umsdos/dir.c5
-rw-r--r--include/asm-alpha/namei.h3
-rw-r--r--include/asm-arm/arch-arc/system.h6
-rw-r--r--include/asm-arm/arch-cl7500/system.h7
-rw-r--r--include/asm-arm/arch-cl7500/vmalloc.h16
-rw-r--r--include/asm-arm/arch-ebsa110/hardware.h1
-rw-r--r--include/asm-arm/arch-ebsa110/system.h26
-rw-r--r--include/asm-arm/arch-ebsa110/vmalloc.h16
-rw-r--r--include/asm-arm/arch-ebsa285/hardware.h3
-rw-r--r--include/asm-arm/arch-ebsa285/system.h23
-rw-r--r--include/asm-arm/arch-ebsa285/vmalloc.h16
-rw-r--r--include/asm-arm/arch-nexuspci/system.h7
-rw-r--r--include/asm-arm/arch-nexuspci/vmalloc.h16
-rw-r--r--include/asm-arm/arch-rpc/hardware.h1
-rw-r--r--include/asm-arm/arch-rpc/system.h23
-rw-r--r--include/asm-arm/arch-rpc/vmalloc.h16
-rw-r--r--include/asm-arm/arch-sa1100/hardware.h1
-rw-r--r--include/asm-arm/arch-sa1100/keyboard.h62
-rw-r--r--include/asm-arm/arch-sa1100/system.h62
-rw-r--r--include/asm-arm/arch-sa1100/vmalloc.h16
-rw-r--r--include/asm-arm/arch-shark/dma.h18
-rw-r--r--include/asm-arm/arch-shark/hardware.h49
-rw-r--r--include/asm-arm/arch-shark/ide.h45
-rw-r--r--include/asm-arm/arch-shark/io.h207
-rw-r--r--include/asm-arm/arch-shark/irq.h123
-rw-r--r--include/asm-arm/arch-shark/irqs.h11
-rw-r--r--include/asm-arm/arch-shark/keyboard.h95
-rw-r--r--include/asm-arm/arch-shark/memory.h35
-rw-r--r--include/asm-arm/arch-shark/param.h10
-rw-r--r--include/asm-arm/arch-shark/processor.h28
-rw-r--r--include/asm-arm/arch-shark/serial.h33
-rw-r--r--include/asm-arm/arch-shark/system.h21
-rw-r--r--include/asm-arm/arch-shark/time.h101
-rw-r--r--include/asm-arm/arch-shark/timex.h5
-rw-r--r--include/asm-arm/arch-shark/uncompress.h34
-rw-r--r--include/asm-arm/checksum.h8
-rw-r--r--include/asm-arm/cpu-multi32.h4
-rw-r--r--include/asm-arm/cpu-single.h2
-rw-r--r--include/asm-arm/namei.h41
-rw-r--r--include/asm-arm/proc-armv/pgtable.h16
-rw-r--r--include/asm-i386/namei.h3
-rw-r--r--include/asm-ia64/namei.h3
-rw-r--r--include/asm-m68k/namei.h3
-rw-r--r--include/asm-mips/namei.h36
-rw-r--r--include/asm-mips64/namei.h3
-rw-r--r--include/asm-ppc/namei.h3
-rw-r--r--include/asm-sh/bitops.h2
-rw-r--r--include/asm-sh/byteorder.h2
-rw-r--r--include/asm-sh/checksum.h96
-rw-r--r--include/asm-sh/current.h4
-rw-r--r--include/asm-sh/delay.h6
-rw-r--r--include/asm-sh/mman.h6
-rw-r--r--include/asm-sh/namei.h3
-rw-r--r--include/asm-sh/processor.h41
-rw-r--r--include/asm-sh/ptrace.h90
-rw-r--r--include/asm-sh/sigcontext.h12
-rw-r--r--include/asm-sh/string.h50
-rw-r--r--include/asm-sh/system.h81
-rw-r--r--include/asm-sh/uaccess.h108
-rw-r--r--include/asm-sh/unistd.h2
-rw-r--r--include/asm-sh/user.h10
-rw-r--r--include/asm-sparc/io.h27
-rw-r--r--include/asm-sparc/namei.h43
-rw-r--r--include/asm-sparc/page.h19
-rw-r--r--include/asm-sparc/pgtable.h8
-rw-r--r--include/asm-sparc64/asm_offsets.h114
-rw-r--r--include/asm-sparc64/bitops.h188
-rw-r--r--include/asm-sparc64/io.h64
-rw-r--r--include/asm-sparc64/namei.h43
-rw-r--r--include/asm-sparc64/pbm.h6
-rw-r--r--include/asm-sparc64/pgalloc.h26
-rw-r--r--include/asm-sparc64/pgtable.h61
-rw-r--r--include/asm-sparc64/processor.h36
-rw-r--r--include/asm-sparc64/system.h14
-rw-r--r--include/linux/blk.h22
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--include/linux/bootmem.h1
-rw-r--r--include/linux/cycx_x25.h6
-rw-r--r--include/linux/dcache.h49
-rw-r--r--include/linux/errno.h10
-rw-r--r--include/linux/fs.h70
-rw-r--r--include/linux/ibmtr.h454
-rw-r--r--include/linux/if_ppp.h3
-rw-r--r--include/linux/input.h56
-rw-r--r--include/linux/lockd/lockd.h2
-rw-r--r--include/linux/lockd/nlm.h7
-rw-r--r--include/linux/mm.h12
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--include/linux/mount.h28
-rw-r--r--include/linux/nbd.h1
-rw-r--r--include/linux/net.h8
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack.h8
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_ftp.h1
-rw-r--r--include/linux/netfilter_ipv4/ip_queue.h36
-rw-r--r--include/linux/netfilter_ipv4/ipt_REJECT.h3
-rw-r--r--include/linux/nfs.h181
-rw-r--r--include/linux/nfs2.h74
-rw-r--r--include/linux/nfs3.h216
-rw-r--r--include/linux/nfs_fs.h98
-rw-r--r--include/linux/nfs_fs_i.h26
-rw-r--r--include/linux/nfs_fs_sb.h11
-rw-r--r--include/linux/nfs_mount.h15
-rw-r--r--include/linux/nfs_xdr.h374
-rw-r--r--include/linux/nfsd/const.h14
-rw-r--r--include/linux/pci.h3
-rw-r--r--include/linux/ppp_channel.h8
-rw-r--r--include/linux/proc_fs_i.h2
-rw-r--r--include/linux/raid/md_u.h6
-rw-r--r--include/linux/sched.h3
-rw-r--r--include/linux/skbuff.h355
-rw-r--r--include/linux/sunrpc/sched.h1
-rw-r--r--include/linux/sunrpc/svc.h1
-rw-r--r--include/linux/sunrpc/xdr.h4
-rw-r--r--include/linux/swap.h4
-rw-r--r--include/linux/tty.h3
-rw-r--r--include/linux/udf_fs.h8
-rw-r--r--include/linux/usb.h23
-rw-r--r--include/linux/usbdevice_fs.h (renamed from drivers/usb/usbdevice_fs.h)0
-rw-r--r--include/net/sock.h41
-rw-r--r--include/net/tcp.h18
-rw-r--r--include/scsi/sg.h7
-rw-r--r--init/main.c16
-rw-r--r--ipc/shm.c272
-rw-r--r--kernel/acct.c5
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/kmod.c22
-rw-r--r--kernel/ksyms.c5
-rw-r--r--kernel/panic.c18
-rw-r--r--kernel/sched.c1
-rw-r--r--mm/bootmem.c2
-rw-r--r--mm/filemap.c61
-rw-r--r--mm/memory.c2
-rw-r--r--mm/numa.c11
-rw-r--r--mm/page_alloc.c29
-rw-r--r--mm/slab.c12
-rw-r--r--mm/swap_state.c7
-rw-r--r--mm/swapfile.c4
-rw-r--r--mm/vmscan.c24
-rw-r--r--net/Config.in6
-rw-r--r--net/Makefile2
-rw-r--r--net/bridge/br.c2
-rw-r--r--net/bridge/br_input.c6
-rw-r--r--net/core/datagram.c7
-rw-r--r--net/core/dev.c312
-rw-r--r--net/core/filter.c29
-rw-r--r--net/core/skbuff.c91
-rw-r--r--net/core/sock.c34
-rw-r--r--net/decnet/af_decnet.c4
-rw-r--r--net/decnet/dn_nsp_in.c3
-rw-r--r--net/decnet/dn_nsp_out.c4
-rw-r--r--net/ipv4/af_inet.c4
-rw-r--r--net/ipv4/icmp.c3
-rw-r--r--net/ipv4/ip_output.c13
-rw-r--r--net/ipv4/netfilter/.cvsignore2
-rw-r--r--net/ipv4/netfilter/Config.in7
-rw-r--r--net/ipv4/netfilter/Makefile54
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c38
-rw-r--r--net/ipv4/netfilter/ip_conntrack_ftp.c5
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_icmp.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c6
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_udp.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c5
-rw-r--r--net/ipv4/netfilter/ip_fw_compat.c2
-rw-r--r--net/ipv4/netfilter/ip_fw_compat_masq.c1
-rw-r--r--net/ipv4/netfilter/ip_nat_ftp.c9
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c8
-rw-r--r--net/ipv4/netfilter/ip_queue.c516
-rw-r--r--net/ipv4/netfilter/ip_tables.c83
-rw-r--r--net/ipv4/netfilter/ipchains_core.c2
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c12
-rw-r--r--net/ipv4/netfilter/ipt_MARK.c10
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c2
-rw-r--r--net/ipv4/netfilter/ipt_MIRROR.c3
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c2
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c15
-rw-r--r--net/ipv4/netfilter/ipt_TOS.c10
-rw-r--r--net/ipv4/netfilter/ipt_limit.c1
-rw-r--r--net/ipv4/netfilter/ipt_mac.c1
-rw-r--r--net/ipv4/netfilter/ipt_mark.c2
-rw-r--r--net/ipv4/netfilter/ipt_multiport.c2
-rw-r--r--net/ipv4/netfilter/ipt_owner.c4
-rw-r--r--net/ipv4/netfilter/ipt_state.c8
-rw-r--r--net/ipv4/netfilter/ipt_tos.c2
-rw-r--r--net/ipv4/netfilter/ipt_unclean.c2
-rw-r--r--net/ipv4/tcp.c88
-rw-r--r--net/ipv4/tcp_input.c51
-rw-r--r--net/ipv4/tcp_ipv4.c5
-rw-r--r--net/ipv4/tcp_output.c44
-rw-r--r--net/ipv6/icmp.c3
-rw-r--r--net/ipv6/tcp_ipv6.c3
-rw-r--r--net/ipx/af_spx.c6
-rw-r--r--net/khttpd/security.c6
-rw-r--r--net/khttpd/sockets.c1
-rw-r--r--net/khttpd/waitheaders.c7
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/netsyms.c46
-rw-r--r--net/socket.c11
-rw-r--r--net/sunrpc/clnt.c16
-rw-r--r--net/sunrpc/sched.c67
-rw-r--r--net/sunrpc/sunrpc_syms.c4
-rw-r--r--net/sunrpc/svcsock.c3
-rw-r--r--net/sunrpc/xdr.c62
-rw-r--r--net/sunrpc/xprt.c7
-rw-r--r--net/unix/af_unix.c86
-rw-r--r--scripts/Menuconfig10
-rw-r--r--scripts/checkincludes.pl24
-rw-r--r--scripts/docproc.c6
-rw-r--r--scripts/gen-all-syms2
-rw-r--r--scripts/kernel-doc16
642 files changed, 42156 insertions, 25192 deletions
diff --git a/CREDITS b/CREDITS
index b5436e948..bbab863c5 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1381,7 +1381,7 @@ S: 370 01 Ceske Budejovice
S: Czech Republic
N: Bas Laarhoven
-E: bas@vimec.nl
+E: sjml@xs4all.nl
D: Loadable modules and ftape driver
S: J. Obrechtstr 23
S: NL-5216 GP 's-Hertogenbosch
@@ -1526,9 +1526,10 @@ D: SLS distribution
D: Initial implementation of VC's, pty's and select()
N: Pavel Machek
-E: pavel@atrey.karlin.mff.cuni.cz
-D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
-D: Network block device, sun4/330 port
+E: pavel@ucw.cz
+E: pavel@suse.cz
+D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd
+D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB
S: Volkova 1131
S: 198 00 Praha 9
S: Czech Republic
@@ -1569,6 +1570,15 @@ S: 2200 Mission College Blvd
S: Santa Clara, CA 95052
S: USA
+N: Petko Manolov
+E: petkan@spct.net
+D: USB ethernet (pegasus) driver
+D: optimizing i[45]86 string routines
+D: i386 task swithing hacks
+S: 5, Vrah Mancho str.
+S: 1324 Sofia
+S: Bulgaria
+
N: Martin Mares
E: mj@suse.cz
E: mj@ucw.cz
@@ -2114,6 +2124,15 @@ S: 301/222 City Walk
S: Canberra ACT 2601
S: Australia
+N: Bill Ryder
+E: bryder@sgi.com
+D: FTDI_SIO usb/serial converter driver
+W: http://reality.sgi.com/bryder_wellington/ftdi_sio
+S: I/3 Walter St
+S: Wellington
+S: New Zealand
+
+
N: Sampo Saaristo
E: sambo@cs.tut.fi
D: Co-author of Multi-Protocol Over ATM (MPOA)
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 08acaf9f3..eb5e4efec 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -59,7 +59,7 @@
# All this was shamelessly stolen from several different sources. Many
# thanks to all the contributors. Feel free to use these help texts in
# your own kernel configuration tools. The texts are copyrighted (c)
-# 1995-1999 by Axel Boldt and many others and are governed by the GNU
+# 1995-2000 by Axel Boldt and many others and are governed by the GNU
# General Public License.
Prompt for development and/or incomplete code/drivers
@@ -112,18 +112,23 @@ CONFIG_SMP
Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
Management" code will be disabled if you say Y here.
- See also: Documentation/SMP.txt, Documentation/smp.tex,
- Documentation/smp.txt, and Documentation/IO-APIC.txt. Also see the
+ See also the files Documentation/smp.tex, Documentation/smp.txt,
+ Documentation/IO-APIC.txt, Documentation/nmi_watchdog.txt and the
SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ .
If you don't know what to do here, say N.
APIC and IO-APIC Support on Uniprocessors
CONFIG_X86_UP_IOAPIC
- This option enables uniprocessor-kernels to switch into IO-APIC mode
- if there is an IO-APIC in the system. Such a kernel will still boot
- on IO-APIC-less systems with no slowdown at all. SMP kernels include
- IO-APIC support unconditionally.
+ APIC (Advanced Programmable Interrupt Controller) is a scheme for
+ delivering hardware interrupt requests to the CPU. It is commonly
+ used on systems with several CPU's. If you have a single-CPU system
+ which uses APIC, you can say Y here to use it. If you say Y here
+ even though your machine doesn't have APIC, then the kernel will
+ still run with now slowdown at all.
+
+ If you have system with several CPU's, you do not need to say Y
+ here: APIC will be used automatically.
Kernel math emulation
CONFIG_MATH_EMULATION
@@ -140,10 +145,8 @@ CONFIG_MATH_EMULATION
command line option "no387", which comes handy if your coprocessor
is broken. 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 .) This
- means that it is a good idea to say Y here if you intend to use this
- kernel on different machines.
+ boot time.) This means that it is a good idea to say Y here if you
+ intend to use this kernel on different machines.
More information about the internals of the Linux math coprocessor
emulation can be found in arch/i386/math-emu/README.
@@ -187,9 +190,9 @@ 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). This will result in the old "3GB/1GB"
- virtual/physical memory split. 3BG are mapped so as each processus
+ virtual/physical memory split. 3GB 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
+ The remaining part of the 4GB 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.
@@ -277,7 +280,10 @@ CONFIG_BLK_DEV_LOOP
This is useful if you want to check an ISO 9660 file system before
burning the CD, or if you want to use floppy images without first
- writing them to floppy.
+ writing them to floppy. Furthermore, some Linux distributions avoid
+ the need for a dedicated Linux partition by keeping their complete
+ root file system inside a DOS FAT file using this loop device
+ driver.
The loop device driver can also be used to "hide" a file system in a
disk partition, floppy, or regular file, either using encryption
@@ -289,13 +295,13 @@ CONFIG_BLK_DEV_LOOP
ftp://verden.pvv.org/pub/linux/kerneli/v2.1/ , and then you need to
say Y to this option.
- Note that alternative ways to use encrypted file systems are provided
- by the cfs package, which can be gotten from
+ Note that alternative ways to use encrypted file systems are
+ provided by the cfs package, which can be gotten from
ftp://ftp.replay.com/pub/crypto/disk/ , and the newer tcfs package,
available at http://tcfs.dia.unisa.it/ . You do not need to say Y
here if you want to use one of these. However, using cfs requires
- saying Y to "NFS file system support" below while using tcfs requires
- applying a kernel patch.
+ saying Y to "NFS file system support" below while using tcfs
+ requires applying a kernel patch.
To use the loop device, you need the losetup utility and a recent
version of the mount program, both contained in the util-linux
@@ -341,35 +347,39 @@ CONFIG_BLK_DEV_NBD
ATA/IDE/MFM/RLL support
CONFIG_IDE
- If you say Y here, your kernel will be able to manage low cost mass storage
- units such as ATA/(E)IDE and ATAPI units.
+ If you say Y here, your kernel will be able to manage low cost mass
+ storage units such as ATA/(E)IDE and ATAPI units. The most common
+ cases are IDE hard drives and ATAPI CDROM drives.
- Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard for
- mass storage units such as hard disks. It was designed by Western Digital
- and Compaq Computer in 1984. It was then named ST506.
- Quite a number of disks use IDE interface. State of the art disks use SCSI
- interface.
+ If your system is pure SCSI and doesn't use these interfaces, you
+ can say N here.
+
+ Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+ for mass storage units such as hard disks. It was designed by
+ Western Digital and Compaq Computer in 1984. It was then named
+ ST506. Quite a number of disks use the IDE interface.
- AT Atachment (ATA) is a subset of the IDE specifications.
+ AT Attachment (ATA) is a subset of the IDE specifications.
ST506 was also called ATA-1.
- Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is ATA-3. It
- provides support for larger disks (up to 8.4GB by means of the LBA standard),
- more disks (4 instead of 2) and for other mass storage units such as tapes
- and cdrom.
- UDMA/33 (aka UltraDMA/33) is ATA-4 and provides faster (and more CPU friendly)
- transfer modes than previous PIO (Programmed processor Input/Ouput) from
- previous ATA/IDE standards by means of fast DMA controlers.
+ Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+ ATA-3. It provides support for larger disks (up to 8.4GB by means of
+ the LBA standard), more disks (4 instead of 2) and for other mass
+ storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+ ATA-4 and provides faster (and more CPU friendly) transfer modes
+ than previous PIO (Programmed processor Input/Output) from previous
+ ATA/IDE standards by means of fast DMA controllers.
- ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and CDROM
- drives, similar in many respects to the SCSI protocol.
+ ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+ CDROM drives, similar in many respects to the SCSI protocol.
- SMART IDE (Self Monitoring, Analysis and Reporting Technology) was designed
- in order to prevent data corruption and disk crash by detecting pre hardware
- faillure conditions (heat, access time, and the like...). Disks builded since
- june 1995 may follow this standard. The kernel itself don't manage this;
- however there are quite a number of user programs such as smart that can
- query the status of SMART parameters disk.
+ SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+ designed in order to prevent data corruption and disk crash by
+ detecting pre hardware failure conditions (heat, access time, and
+ the like...). Disks built since June 1995 may follow this
+ standard. The kernel itself don't manage this; however there are
+ quite a number of user programs such as smart that can query the
+ status of SMART parameters disk.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -385,15 +395,15 @@ CONFIG_BLK_DEV_IDE
If you say Y here, you will use the full-featured IDE driver to
control up to ten ATA/IDE interfaces, each being able to serve a
"master" and a "slave" device, for a total of up to twenty ATA/IDE
- disk/cdrom/tape/floppy drives. People with SCSI-only systems
- can say N or M here.
+ disk/cdrom/tape/floppy drives.
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/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 .
+ detected, sound card ATA/IDE ports, module support, and other
+ topics, is 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 .
To fine-tune ATA/IDE drive/interface parameters for improved
performance, look for the hdparm package at
@@ -403,7 +413,7 @@ CONFIG_BLK_DEV_IDE
inserted in and removed from the running kernel whenever you want),
say M here and read Documentation/modules.txt and
Documentation/ide.txt. The module will be called ide-mod.o. Do not
- compile this driver as a module if your root filesystem (the one
+ compile this driver as a module if your root file system (the one
containing the directory /) is located on an IDE device.
If you have one or more IDE drives, say Y or M here. If your system
@@ -428,8 +438,6 @@ CONFIG_BLK_DEV_HD_ONLY
Disk-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto .
- People with SCSI-only systems can say N here.
-
Use old disk-only driver on primary interface
CONFIG_BLK_DEV_HD_IDE
There are two drivers for MFM/RLL/IDE disks. Most people use just
@@ -446,9 +454,6 @@ CONFIG_BLK_DEV_HD_IDE
Normally, just say N here; you will then use the new driver for all
4 interfaces.
- People with SCSI-only systems don't need this and can say N here as
- well.
-
Include IDE/ATA-2 DISK support
CONFIG_BLK_DEV_IDEDISK
This will include enhanced support for MFM/RLL/IDE hard disks. If
@@ -505,8 +510,8 @@ CONFIG_BLK_DEV_IDETAPE
to the SCSI protocol. If you have an SCSI tape drive however, you
can say N here.
- This now includes the OnStream DI-30 tape drive support.
- Will not work with SCSI protocol, until there is support for the
+ You should also say Y if you have an OnStream DI-30 tape drive; this
+ will not work with the SCSI protocol, until there is support for the
SC-30 and SC-50 versions.
If you say Y here, the tape drive will be identified at boot time
@@ -547,14 +552,17 @@ CONFIG_BLK_DEV_IDESCSI
and will allow you to use a SCSI device driver instead of a native
ATAPI driver.
- Must pass "hdx=scsi" per devices if you want the native EIDE sub-drivers
- to skip over the native support. This is required for use of CD-RW's.
-
This is useful if you have an ATAPI device for which no native
driver has been written (for example, an ATAPI PD-CD or CDR drive);
you can then use this emulation together with an appropriate SCSI
device driver. In order to do this, say Y here and to "SCSI support"
- and "SCSI generic support", below.
+ and "SCSI generic support", below. You must then provide the kernel
+ command line "hdx=scsi" (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) for devices if you want the
+ native EIDE sub-drivers to skip over the native support, so that
+ this SCSI emulation can be used instead. This is required for use of
+ CD-RW's.
Note that this option does NOT allow you to attach SCSI devices to a
box that doesn't have a SCSI host adapter installed.
@@ -562,12 +570,10 @@ CONFIG_BLK_DEV_IDESCSI
If both this SCSI emulation and native ATAPI support are compiled
into the kernel, the native support will be used.
- People with SCSI-only systems can say N here. If unsure, say N.
-
ISA-PNP EIDE support
CONFIG_BLK_DEV_ISAPNP
- If you have an ISA EIDE card that is PnP and requires setup first
- before scanning for devices, say Y here.
+ If you have an ISA EIDE card that is PnP (Plug and Play) and
+ requires setup first before scanning for devices, say Y here.
If unsure, say N.
@@ -587,16 +593,12 @@ CONFIG_BLK_DEV_CMD640
(VLB) instead of PCI, you must also supply a kernel boot parameter
to enable the CMD640 bugfix/support: "ide0=cmd640_vlb". (Try "man
bootparam" or see the documentation of your boot loader about how to
- pass options to the kernel. The lilo procedure is also explained in
- the SCSI-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto .)
+ pass options to the kernel.)
The CMD640 chip is also used on add-in cards by Acculogic, and on
the "CSA-6400E PCI to IDE controller" that some people have. For
details, read Documentation/ide.txt.
- People with SCSI-only systems should say N here. If unsure, say Y.
-
CMD640 enhanced support
CONFIG_BLK_DEV_CMD640_ENHANCED
This option includes support for setting/autotuning PIO modes and
@@ -615,16 +617,12 @@ CONFIG_BLK_DEV_RZ1000
Linux. This may slow disk throughput by a few percent, but at least
things will operate 100% reliably.
- People with SCSI-only systems should say N here. If unsure, say Y.
-
Generic PCI IDE chipset support
CONFIG_BLK_DEV_IDEPCI
Say Y here for PCI systems which use IDE drive(s).
This option helps the IDE driver to automatically detect and
configure all PCI-based IDE interfaces in your system.
- People with SCSI-only systems should say N here; if unsure say Y.
-
Support for sharing PCI IDE interrupts
CONFIG_IDEPCI_SHARE_IRQ
Some ATA/IDE chipsets have hardware support which allows for
@@ -646,8 +644,8 @@ 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/ide/ide-dma.c and the
- file Documentation/ide.txt for more information.
+ 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.
@@ -671,16 +669,14 @@ CONFIG_BLK_DEV_OFFBOARD
cards (off-board controllers) are relegated to ide2 and ide3.
Answering Y here will allow you to reverse the situation, with
off-board controllers on ide0/1 and on-board controllers on ide2/3.
- This can improve the usability of some boot managers such as LILO
+ This can improve the usability of some boot managers such as lilo
when booting from a drive on an off-board controller.
If you say Y here, and you actually want to reverse the device scan
order as explained above, you also need to issue the kernel command
line option "ide=reverse". (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 .)
+ pass options to the kernel at boot time.)
Note that, if you do this, the order of the hd* devices will be
rearranged which may require modification of fstab and other files.
@@ -693,7 +689,7 @@ CONFIG_IDEDMA_PCI_AUTO
DMA for IDE drives and chipsets which support it. Due to concerns
about a couple of cases where buggy hardware may have caused damage,
the default is now to NOT use DMA automatically. To revert to the
- previous behavior, say Y to this question.
+ previous behaviour, say Y to this question.
If you suspect your hardware is at all flakey, say N here.
Do NOT email the IDE kernel people regarding this issue!
@@ -703,8 +699,9 @@ CONFIG_IDEDMA_PCI_AUTO
Various ATA, Work(s) In Progress (EXPERIMENTAL)
CONFIG_IDEDMA_PCI_WIP
- If you enable this you will be capable of using and testing
- highly developmental projects.
+ If you enable this you will be able to use and test highly
+ developmental projects. If you say N, this configure script will
+ simply skip those options.
It is SAFEST to say N to this question.
@@ -726,8 +723,9 @@ 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/ide/aec6210.c
- 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/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
@@ -736,33 +734,37 @@ CONFIG_AEC6210_TUNING
ALI M15x3 chipset support
CONFIG_BLK_DEV_ALI15X3
- This driver ensures (U)DMA support for ALI 1543 and 1543C,
- 1535, 1535D onboard chipsets. It also tests for Simplex mode and
- enables normal dual channel support.
+ This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
+ onboard chipsets. It also tests for Simplex mode and enables
+ normal dual channel support.
+ If you say Y here, you also need to say Y to "Use DMA by default
+ when available", above.
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.
+ 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 CORRUPTION, 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.
+ 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.
+ This driver ensures (U)DMA support for the AMD756 Viper chipset.
+ If you say Y here, you also need to say Y to "Use DMA by default
+ when available", above.
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.
AMD Viper ATA-66 Override support (WIP)
@@ -773,8 +775,8 @@ CONFIG_AMD7409_OVERRIDE
CMD64X chipset support
CONFIG_BLK_DEV_CMD64X
- Say Y here if you have an IDE controller which uses any of these chipsets,
- CMD643, CMD646, or CMD648.
+ Say Y here if you have an IDE controller which uses any of these
+ chipsets: CMD643, CMD646, or CMD648.
CMD64X chipset RAID support (WIP)
CONFIG_CMD64X_RAID
@@ -786,7 +788,8 @@ CONFIG_BLK_DEV_CY82C693
This driver adds detection and support for the CY82C693 chipset
used on Digital's PC-Alpha 164SX boards.
- If you say Y here, then say Y to "Use DMA by default when available" as well.
+ If you say Y here, you need to say Y to "Use DMA by default
+ when available" as well.
Cyrix CS5530 MediaGX chipset support
CONFIG_BLK_DEV_CS5530
@@ -795,6 +798,8 @@ CONFIG_BLK_DEV_CS5530
It is safe to say Y to this question.
+ People with SCSI-only systems should say N here. If unsure, say Y.
+
HPT34X chipset support
CONFIG_BLK_DEV_HPT34X
This driver adds up to 4 more EIDE devices sharing a single
@@ -806,38 +811,39 @@ 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/ide/hpt34x.c
- If you say Y here, then say Y to "Use DMA by default when available" as well.
+ This is a dangerous thing to attempt currently! 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.
HPT366 chipset support
CONFIG_BLK_DEV_HPT366
- This is an Ultra DMA chipset for ATA-66.
+ HPT366 is an Ultra DMA chipset for ATA-66.
This driver adds up to 4 more EIDE devices sharing a single
- interrupt. The HPT366 chipset in its current form is a non-bootable,
- without special LILO commands for redirecting the reference to device 0x80.
- The other solution is to include "CONFIG_BLK_DEV_OFFBOARD" unless your
- mainboard has the chipset native mounted. Regardless one should use the
- fore mentioned option and call at LILO or include in your append-line:
- "ide=reverse". This driver requires dynamic tuning of the chipset during
- the ide-probe at boot. It is reported to support DVD II drives, by the
+ interrupt.
+
+ The HPT366 chipset in its current form is non-bootable. One solution
+ for this problem are special LILO commands for redirecting the
+ reference to device 0x80. The other solution is to say Y to "Boot
+ off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless
+ your mother board has the chipset natively mounted. Regardless one
+ should use the fore mentioned option and call at LILO or include
+ "ide=reverse" in LILO's append-line.
+
+ This driver requires dynamic tuning of the chipset during 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/ide/hpt366.c
- If you say Y here, then say Y to "Use DMA by default when available" as well.
-
HPT366 Fast Interrupts (WIP)
CONFIG_HPT366_FIP
-
If unsure, say N.
-HPT366 mode three unsupported (WIP)
+HPT366 mode three unsupported (EXPERIMENTAL) (WIP)
CONFIG_HPT366_MODE3
- This is an undocumented mode that the HA366 can default to in many cases.
- If unsure, say N.
+ This is an undocumented mode that the HA366 can default to in many
+ cases. If unsure, say N.
NS87415 support (EXPERIMENTAL)
CONFIG_BLK_DEV_NS87415
@@ -858,12 +864,14 @@ 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/ide/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.
+ If you say Y here, you should also say Y to "PIIXn Tuning support",
+ below.
+
+ If unsure, say N.
-PIIXn Tuning support
+PIIXn Tuning support (EXPERIMENTAL)
CONFIG_PIIX_TUNING
This driver extension adds DMA mode setting and tuning for all PIIX
IDE controllers by Intel. Since the BIOS can sometimes improperly
@@ -873,7 +881,7 @@ CONFIG_PIIX_TUNING
Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
2 if the BIOS can not perform this task at initialization.
- If unsure, say Y.
+ If unsure, say N.
PROMISE PDC20246/PDC20262 support
CONFIG_BLK_DEV_PDC202XX
@@ -883,10 +891,10 @@ CONFIG_BLK_DEV_PDC202XX
interrupt. This add-on card is a bootable PCI UDMA controller. Since
multiple cards can be installed and there are BIOS ROM problems that
happen if the BIOS revisions of all installed cards (three-max) do
- not match, the driver attempts to do dynamic tuning of the chipset at
- boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required for
- more than one card. This card may require that you say Y to "Special
- UDMA Feature (EXPERIMENTAL)".
+ not match, the driver attempts to do dynamic tuning of the chipset
+ at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required
+ for more than one card. This card may require that you say Y to
+ "Special UDMA Feature (EXPERIMENTAL)".
Promise Ultra66 or PDC20262
@@ -896,12 +904,14 @@ CONFIG_BLK_DEV_PDC202XX
boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS
1.11 or newer required.
- If you say Y here, then say Y to "Use DMA by default when available" as well.
+ If you say Y here, you need to say Y to "Use DMA by default when
+ available" as well.
+
Please read the comments at the top of drivers/ide/pdc202xx.c
If unsure, say N.
-Special UDMA Feature
+Special UDMA Feature (EXPERIMENTAL)
CONFIG_PDC202XX_BURST
For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally
for PDC20246/Ultra33 that has BIOS setup failures when using 3 or
@@ -918,6 +928,17 @@ CONFIG_PDC202XX_MASTER
Say N.
+SiS5513 chipset support
+CONFIG_BLK_DEV_SIS5513
+ This driver ensures (U)DMA support for SIS5513 chipset based
+ mainboards. SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all
+ other DMA mode 2 limited chipsets are unsupported to date.
+
+ If you say Y here, you need to say Y to "Use DMA by default when
+ available" as well.
+
+ Please read the comments at the top of drivers/ide/sis5513.c
+
Winbond SL82c105 support
CONFIG_BLK_DEV_SL82C105
If you have a Winbond SL82c105 IDE controller, say Y here to enable
@@ -933,16 +954,18 @@ CONFIG_BLK_DEV_TRM290
VIA82CXXX chipset support (EXPERIMENTAL)
CONFIG_BLK_DEV_VIA82CXXX
- This allows you to to configure your chipset for a better use while
- running (U)DMA: it will allow you to enable efficiently the second
- channel dma usage, as it is may not be set by BIOS. It allows you to
- run a kernel command line at boot time in order to set fifo config.
- 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.
+ This allows you to to configure your chipset for a better use while
+ running (U)DMA: it will allow you to enable efficiently the second
+ channel dma usage, as it may not be set by BIOS. It allows you to
+ pass a kernel command line at boot time in order to set fifo
+ config. If no command line is provided, it will try to set fifo
+ configuration at its best. It will allow you to get information from
+ /proc/ide/via provided you enabled "proc" support.
+
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.
+ If you say Y here, then say Y to "Use DMA by default when available"
+ as well.
If unsure, say N.
@@ -1045,7 +1068,7 @@ CONFIG_BLK_DEV_BUDDHA
Amiga IDE Doubler support (EXPERIMENTAL)
CONFIG_BLK_DEV_IDEDOUBLER
- This driver provides support for the so called `IDE doublers' (made
+ This driver provides support for the so-called `IDE doublers' (made
by various manufacturers, e.g. Eyetech) that can be connected to the
builtin IDE interface of some Amiga models. Using such an IDE
doubler, you can connect up to four instead of two IDE devices on
@@ -1087,11 +1110,6 @@ CONFIG_BLK_DEV_MAC_IDE
devices (hard disks, CD-ROM drives, etc.) that are connected to the
builtin IDE interface.
-IDE card support
-CONFIG_BLK_DEV_IDE_CARDS
- On Acorn systems, say Y here if you wish to use an IDE interface
- expansion card. If you do not or are unsure, say N to this.
-
ICS IDE interface support
CONFIG_BLK_DEV_IDE_ICSIDE
On Acorn systems, say Y here if you wish to use the ICS IDE
@@ -1100,7 +1118,8 @@ CONFIG_BLK_DEV_IDE_ICSIDE
ICS DMA support
CONFIG_BLK_DEV_IDEDMA_ICS
- No help for CONFIG_BLK_DEV_IDEDMA_ICS
+ Say Y here if you want to add DMA (Direct Memory Access) support to
+ the ICS IDE driver.
Use ICS DMA by default
CONFIG_IDEDMA_ICS_AUTO
@@ -1113,10 +1132,6 @@ CONFIG_IDEDMA_ICS_AUTO
If you suspect your hardware is at all flakey, say N here.
Do NOT email the IDE kernel people regarding this issue!
-RapIDE interface support
-CONFIG_BLK_DEV_IDE_RAPIDE
- No help for CONFIG_BLK_DEV_IDE_RAPIDE
-
XT hard disk support
CONFIG_BLK_DEV_XD
Very old 8 bit hard disk controllers used in the IBM XT computer
@@ -1133,7 +1148,7 @@ PS/2 ESDI hard disk support
CONFIG_BLK_DEV_PS2
Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
hard disk.
-
+
If you want to compile the driver 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
@@ -1157,7 +1172,7 @@ CONFIG_PARIDE
your computer's parallel port. Most of them are actually IDE devices
using a parallel port IDE adapter. This option enables the PARIDE
subsystem which contains drivers for many of these external drives.
- Read linux/Documentation/paride.txt for more information.
+ Read Documentation/paride.txt for more information.
If you have said Y to the "Parallel-port support" configuration
option, you may share a single port between your printer and other
@@ -1199,8 +1214,8 @@ CONFIG_PARIDE_PCD
system. Among the devices supported by this driver are the
MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If
you have such a CD-ROM drive, you should also say Y or M to "ISO
- 9660 CDROM file system support" below, because that's the file system
- used on CDROMs.
+ 9660 CDROM file system support" below, because that's the file
+ system used on CDROMs.
Parallel port ATAPI disks
CONFIG_PARIDE_PF
@@ -1241,7 +1256,7 @@ CONFIG_PARIDE_PG
your system.
This driver implements an API loosely related to the generic SCSI
- driver. See /usr/include/linux/pg.h for details.
+ driver. See include/linux/pg.h for details.
You can obtain the most recent version of cdrecord from
ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ . Versions 1.6.1a3 and
@@ -1401,9 +1416,13 @@ CONFIG_BLK_DEV_LVM
to new capacity needs. Logical volumes are accessed as block
devices named /dev/VolumeGroupName/LogicalVolumeName.
- For details see /usr/src/linux/Documentaion/LVM-HOWTO.
+ For details see Documentation/LVM-HOWTO. You will need supporting
+ user space software from http://linux.msede.com/lvm .
- To get the newest software see <http://linux.msede.com/lvm>.
+ If you want to compile this support 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 lvm-mod.o.
Logical Volume Manager /proc file system information
CONFIG_LVM_PROC_FS
@@ -1517,37 +1536,30 @@ CONFIG_MD_BOOT
answer Y here. For lilo and loadlin options see the file
Documentation/md.txt.
-Support for Deskstation RPC44
-CONFIG_DESKSTATION_RPC44
- This is a machine with a R4400 100 MHz CPU. To compile a Linux
- kernel that runs on these, say Y here. For details about Linux
- on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
- http://oss.sgi.com/mips.
-
Support for Acer PICA 1 chipset
CONFIG_ACER_PICA_61
This is a machine with a R4400 133/150 MHz CPU. To compile a Linux
kernel that runs on these, say Y here. For details about Linux on
the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
- http://oss.sgi.com/mips.
+ http://oss.sgi.com/mips .
Support for Algorithmics P4032 (EXPERIMENTAL)
CONFIG_ALGOR_P4032
This is an evaluation board of the British company Algorithmics. The
board uses the R4300 and a R5230 CPUs. For more information about
- this board see http://www.algor.co.uk.
+ this board see http://www.algor.co.uk .
Support for BAGET MIPS series
CONFIG_BAGET_MIPS
This enables support for the Baget, a Russian embedded system. For
more details about the Baget see the Linux/MIPS FAQ on
- http://oss.sgi.com/mips.
+ http://oss.sgi.com/mips .
Support for DECstations
CONFIG_DECSTATION
This enables support for DEC's MIPS based workstations. For details
- see the Linux/MIPS FAQ on http://oss.sgi.com/mips. the
- DECstation porting pages on http://decstation.unix-ag.org.
+ see the Linux/MIPS FAQ on http://oss.sgi.com/mips and the
+ DECstation porting pages on http://decstation.unix-ag.org .
If you have one of the following DECstation Models you definitely
want to choose R4xx0 for the CPU Type:
@@ -1561,26 +1573,8 @@ CONFIG_DECSTATION
Support for NEC DDB Vrc-5074
CONFIG_DDB5074
- This enables support for the VR5000-based NEC DDB Vrc-5074 evaluation
- board.
-
-IDE card support
-CONFIG_BLK_DEV_IDE_CARDS
- On Acorn systems, say Y here if you wish to use an IDE interface
- expansion card. If you do not or are unsure, say N to this.
-
-ICS IDE interface
-CONFIG_BLK_DEV_IDE_ICS
- On Acorn systems, say Y here if you wish to use the ICS IDE
- interface card. This is not required for ICS partition support.
- If you are unsure, say N to this.
-
-ADFS partition support
-CONFIG_BLK_DEV_PART
- This allows Linux on Acorn systems to determine its partitions in
- the 'non-ADFS' partition area of the hard disk - usually located
- after the ADFS partition. You are probably using this system, so
- you should say Y it.
+ This enables support for the VR5000-based NEC DDB Vrc-5074
+ evaluation board.
Support for Mips Magnum 4000
CONFIG_MIPS_MAGNUM_4000
@@ -1598,9 +1592,9 @@ CONFIG_OLIVETTI_M700
Support for SGI IP22
CONFIG_SGI_IP22
- This are the SGI Indy, Challenge S and Indigo2, as well as certain OEM
- variants like the Tandem CMN B006S. To compile a Linux kernel that
- runs on these, say Y here.
+ This are the SGI Indy, Challenge S and Indigo2, as well as certain
+ OEM variants like the Tandem CMN B006S. To compile a Linux kernel
+ that runs on these, say Y here.
Support for SGI IP27
This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
@@ -1611,7 +1605,7 @@ IP27 N-Mode
CONFIG_SGI_SN0_N_MODE
The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be
configured in either N-Modes which allows for more nodes or M-Mode
- which allows for more more memory. Your system is most probly
+ which allows for more more memory. Your system is most probably
running in M-Mode, so you should say N here.
MIPS JAZZ onboard SONIC Ethernet support
@@ -1621,26 +1615,26 @@ CONFIG_MIPS_JAZZ_SONIC
MIPS JAZZ FAS216 SCSI support
CONFIG_JAZZ_ESP
- This is the driver for the onboard SCSI hostadapter of MIPS Magnum 4000,
- Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+ This is the driver for the onboard SCSI host adapter of MIPS Magnum
+ 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM
+ systems.
CPU type
CONFIG_CPU_R3000
- Please make shure to pick the right CPU type. Linux/MIPS is not
+ Please make sure to pick the right CPU type. Linux/MIPS is not
designed to be generic, i.e. Kernels compiled for R3000 CPUs will
*not* work on R4000 Machines and vice versa.
- However, since most the supported Machines have an R4000 (or similar)
- CPU R4xx0 might be a safe bet.
+ However, since most the supported Machines have an R4000 (or
+ similar) CPU, R4xx0 might be a safe bet.
If the resulting Kernel does not work try to recompile with R3000.
Support for large 64-bit configurations
CONFIG_MIPS_INSANE_LARGE
MIPS R10000 does support a 44 bit / 16TB address space as opposed to
- previous 64-bit processors which only did only support 40 bit / 1TB. If
- you need processes of more than 1TB virtual address space activate this.
- Activating CONFIG_MIPS_INSANE_LARGE results in additional memory usage,
- so only activate this if you really need. Very few people will need
- this.
+ previous 64-bit processors which only supported 40 bit / 1TB. If you
+ need processes of more than 1TB virtual address space, say Y here.
+ This will result in additional memory usage, so it is not
+ recommended for normal users.
Generate little endian code
CONFIG_CPU_LITTLE_ENDIAN
@@ -1648,11 +1642,6 @@ CONFIG_CPU_LITTLE_ENDIAN
byte order. These modes require different kernels. Say Y if your
machine is little endian, N if it's a big endian machine.
-Kernel support for IRIX binaries
-CONFIG_BINFMT_IRIX
- If you say Y here, the kernel will support running of IRIX binaries.
- You will need IRIX libraries for this to work.
-
Networking support
CONFIG_NET
Unless you really know what you are doing, you should say Y here.
@@ -1675,7 +1664,7 @@ CONFIG_FILTER
socket and thereby tell the kernel that it should allow or disallow
certain types of data to get through the socket. Linux Socket
Filtering works on all socket types except TCP for now. See the text
- file linux/Documentation/networking/filter.txt for more information.
+ file Documentation/networking/filter.txt for more information.
If unsure, say N.
Network packet filtering
@@ -1710,7 +1699,7 @@ CONFIG_NETFILTER
are completely invisible to the outside world, even though they can
reach the outside and can receive replies. It is even possible to
run globally visible servers from within a masqueraded local network
- using a mechanism called port-forwarding. Masquerading is also often
+ using a mechanism called portforwarding. Masquerading is also often
called NAT (Network Address Translation).
Another use of Netfilter is in transparent proxying: if a machine on
@@ -1720,7 +1709,7 @@ CONFIG_NETFILTER
Various modules exist for netfilter which replace the previous
masquerading (ipmasqadm), packet filtering (ipchains), transparent
- proxying, and port-forwarding mechanisms. More information is
+ proxying, and portforwarding mechanisms. More information is
available from http://netfilter.kernelnotes.org .
Make sure to say N to "Fast switching" below if you intend to say Y
@@ -1729,6 +1718,11 @@ CONFIG_NETFILTER
Chances are that you should say Y here if you compile a kernel which
will run as a router and N for regular hosts. If unsure, say N.
+Network packet filtering debugging
+CONFIG_NETFILTER_DEBUG
+ You can say Y here if you want to get additional messages useful in
+ debugging the netfilter code.
+
IP: connection tracking (required for masq/NAT)
CONFIG_IP_NF_CONNTRACK
Connection tracking keeps a record of what packets have passed
@@ -1773,7 +1767,8 @@ CONFIG_IP_NF_IPTABLES
limit match support
CONFIG_IP_NF_MATCH_LIMIT
limit matching allows you to control the rate at which a rule can be
- matched: mainly useful in combination with the LOG target.
+ matched: mainly useful in combination with the LOG target ("LOG
+ target support", below).
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
@@ -1831,7 +1826,6 @@ CONFIG_IP_NF_MATCH_UNCLEAN
Owner match support (EXPERIMENTAL)
CONFIG_IP_NF_MATCH_OWNER
-
Packet owner matching allows you to match locally-generated packets
based on who created them: the user, group, process or session.
@@ -1889,7 +1883,7 @@ CONFIG_IP_NF_TARGET_REDIRECT
REDIRECT is a special case of NAT: all incoming connections are
mapped onto the incoming interface's address, causing the packets to
come to the local machine instead of passing through. This is
- useful for tranparent proxies.
+ useful for transparent proxies.
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
@@ -1914,11 +1908,12 @@ CONFIG_IP_NF_TARGET_TOS
MARK target support
CONFIG_IP_NF_TARGET_MARK
- This option adds a `MARK' target, which allows you to create rules in
- the `mangle' table which alter the netfilter mark (nfmark) field
- associated with the packet packet prior to routing. This can change
- the routing method (see `IP: use netfilter MARK value as routing key')
- and can also be used by other subsystems to change their behavior.
+ This option adds a `MARK' target, which allows you to create rules
+ in the `mangle' table which alter the netfilter mark (nfmark) field
+ associated with the packet packet prior to routing. This can change
+ the routing method (see `IP: use netfilter MARK value as routing
+ key') and can also be used by other subsystems to change their
+ behavior.
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
@@ -1989,11 +1984,6 @@ CONFIG_SYN_COOKIES
If unsure, say Y.
-Sun floppy controller support
-CONFIG_BLK_DEV_SUNFD
- This is support for floppy drives on Sun SPARC workstations. Say Y
- if you have a floppy drive, otherwise N. Easy.
-
Alpha system type
CONFIG_ALPHA_GENERIC
This is the system type of your hardware. A "generic" kernel will
@@ -2060,12 +2050,6 @@ CONFIG_ALPHA_SRM
If unsure, say N.
-Use SRM PCI setup
-CONFIG_ALPHA_SRM_SETUP
- This option controls whether or not the PCI configuration set up by
- SRM is modified. If you say Y, the existing PCI configuration will
- be left intact.
-
Non-standard serial port support
CONFIG_SERIAL_NONSTANDARD
Say Y here if you have any non-standard serial boards -- boards
@@ -2128,7 +2112,7 @@ CONFIG_SERIAL_MULTIPORT
SGI PROM Console Support
CONFIG_SGI_PROM_CONSOLE
- Enable this if you want to use the PROMs for console I/O.
+ Say Y here if you want to use the PROMs for console I/O.
SGI Zilog85C30 serial support
CONFIG_SGI_SERIAL
@@ -2144,7 +2128,7 @@ CONFIG_SGI_NEWPORT_GFX
SGI Newport Console support
CONFIG_SGI_NEWPORT_CONSOLE
- Enable this if you want the console on the Newport aka XL graphics
+ Say Y here if you want the console on the Newport aka XL graphics
card of your Indy. Most people say Y here.
SGI DS1286 RTC support
@@ -2152,51 +2136,131 @@ CONFIG_SGI_DS1286
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
will get access to the real time clock built into your computer.
- Every SGI has such a clock built in. It reports status information
- via the file /proc/rtc and its behaviour is set by various ioctls on
+ Every SGI has such a clock built in. It reports status information
+ via the file /proc/rtc and its behaviour is set by various ioctls on
/dev/rtc.
-SGI Vino Video For Linux (EXPERIMENTAL)
-CONFIG_SGI_VIDEO_VINO
- Support for the SGI Vino Video hardware which is part of the Newport
- aka XL graphics card. Most people will say N here.
-
Support the Bell Technologies HUB6 card
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,
including serial port cards, modems, and the modem functions of
- multifunction ethernet/modem cards.
+ multi-function ethernet/modem cards. (PCMCIA- or PC-cards are
+ credit-card size devices often used with laptops.)
This driver 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 serial_cs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
+ The module will be called serial_cs.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt. If unsure,
say N.
CardBus serial device support
CONFIG_PCMCIA_SERIAL_CB
Say Y here to enable support for CardBus serial devices, including
- the modem functions of multifunction ethernet/modem devices.
+ serial port cards, modems, and the modem functions of multi-function
+ ethernet/modem devices. (CardBus cards are the newer and better
+ version of PCMCIA- or PC-cards: credit card size devices often
+ used with laptops.)
This driver 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 serial_cb.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
+ The module will be called serial_cb.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt. If unsure,
say N.
+/dev/agpgart (AGP Support) (EXPERIMENTAL)
+CONFIG_AGP
+ AGP (Accelerated Graphics Port) is a bus system mainly used to
+ connect graphics cards to the rest of the system.
+
+ If you have an AGP system and you say Y here, it will be possible to
+ use the AGP features of your 3D rendering video card. This code acts
+ as a sort of "AGP driver" for the motherboard's chipset. The glx
+ module will then be able to program the GART (graphics aperture
+ relocation table) registers with appropriate values to transfer
+ commands to the card.
+
+ If you need more texture memory than you can get with the AGP GART
+ (theoretically up to 256 MB, but in practice usually 64 or 128 MB
+ due to kernel allocation issues), you could use PCI accesses
+ and have up to a couple gigs of texture space.
+
+ Note that this is the only means to have XFree4/GLX use
+ write-combining with MTRR support on the AGP bus. Without it, OpenGL
+ direct rendering will be a lot slower but still faster than PIO.
+
+ For the moment, you should probably say N, unless you want to test
+ the GLX component for XFree86 3.3.6, which can be downloaded from
+ http://utah-glx.sourceforge.net/ , or need to use the 810 Xserver in
+ XFree 3.3.6.
+
+ This driver is available as a module. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt. The module
+ will be called agpgart.o.
+
+Intel 440LX/BX/GX support
+CONFIG_AGP_INTEL
+ This option gives you AGP support for the GLX component of the
+ "soon to be released" XFree86 4.x on Intel 440LX/BX/GX chipsets.
+
+ For the moment, you should probably say N, unless you want to test
+ the GLX component for XFree86 3.3.6, which can be downloaded from
+ http://utah-glx.sourceforge.net/ .
+
+Intel I810/I810 DC100/I810e support
+CONFIG_AGP_I810
+ This option gives you AGP support for the Xserver for the Intel
+ 810 chipset boards. This is required to do any useful video
+ modes.
+
+VIA chipset support
+CONFIG_AGP_VIA
+ This option gives you AGP support for the GLX component of the
+ "soon to be released" XFree86 4.x on VIA MPV3/Apollo Pro chipsets.
+
+ For the moment, you should probably say N, unless you want to test
+ the GLX component for XFree86 3.3.6, which can be downloaded from
+ http://utah-glx.sourceforge.net/ .
+
+AMD Irongate support
+CONFIG_AGP_AMD
+ This option gives you AGP support for the GLX component of the
+ "soon to be released" XFree86 4.x on Intel AMD Irongate chipset.
+
+ For the moment, you should probably say N, unless you want to test
+ the GLX component for XFree86 3.3.6, which can be downloaded from
+ http://utah-glx.sourceforge.net/ .
+
+Generic SiS support
+CONFIG_AGP_SIS
+ This option gives you AGP support for the GLX component of the "soon
+ to be released" XFree86 4.x on Silicon Integrated Systems [SiS]
+ chipsets.
+
+ Note that 5591/5592 AGP chipsets are NOT supported.
+
+ For the moment, you should probably say N, unless you want to test
+ the GLX component for XFree86 3.3.6, which can be downloaded from
+ http://utah-glx.sourceforge.net/ .
+
+ALI M1541 support
+CONFIG_AGP_ALI
+ This option gives you AGP support for the GLX component of the
+ "soon to be released" XFree86 4.x on the ALi M1541 chipset.
+
+ This chipset can do AGP 1x and 2x, but note that there is an
+ acknowledged incompatibility with Matrox G200 cards. Due to
+ timing issues, this chipset cannot do AGP 2x with the G200.
+ This is a hardware limitation. AGP 1x seems to be fine, though.
+
+ For the moment, you should probably say N, unless you want to test
+ the GLX component for XFree86 3.3.6, which can be downloaded from
+ http://utah-glx.sourceforge.net/ .
+
PCI support
CONFIG_PCI
Find out whether you have a PCI motherboard. PCI is the name of a
@@ -2221,16 +2285,17 @@ CONFIG_PCI_GOBIOS
devices. If you choose "BIOS", the BIOS will be used, if you choose
"Direct", the BIOS won't be used, and if you choose "Any", the
kernel will try the direct access method and falls back to the BIOS
- if that doesn't work. If unsure, go with the default.
+ if that doesn't work. If unsure, go with the default, which is
+ "Any".
PCI device name database
CONFIG_PCI_NAMES
By default, the kernel contains a database of all known PCI device
- names to make the information in /proc/pci, /proc/ioports and similar
- files comprehensible to the user. This database increases size of
- the kernel image by about 80KB, but it gets freed after the system
- boots up, so it doesn't take up kernel memory. Anyway, if you are
- building an installation floppy or kernel for an embedded system
+ names to make the information in /proc/pci, /proc/ioports and
+ similar files comprehensible to the user. This database increases
+ size of the kernel image by about 80KB, but it gets freed after the
+ system boots up, so it doesn't take up kernel memory. Anyway, if you
+ are building an installation floppy or kernel for an embedded system
where kernel image size really matters, you can disable this feature
and you'll get device ID numbers instead of names.
@@ -2343,8 +2408,9 @@ CONFIG_PNP
Say Y here if you would like Linux to configure your Plug and Play
devices. You should then also say Y to "ISA Plug and Play support",
- below. Alternatively, you can configure your PnP devices using the
- user space utilities contained in the isapnptools package.
+ below. Alternatively, you can say N here and configure your PnP
+ devices using the user space utilities contained in the isapnptools
+ package.
This support is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -2354,7 +2420,8 @@ CONFIG_PNP
ISA Plug and Play support
CONFIG_ISAPNP
Say Y here if you would like support for ISA Plug and Play devices.
-
+ Some information is in Documentation/isapnp.txt.
+
This support is also available as a module called isapnp.o ( =
code which can be inserted in and removed from the running kernel
whenever you want). If you want to compile it as a module, say M
@@ -2362,13 +2429,27 @@ CONFIG_ISAPNP
If unsure, say Y.
-PCMCIA/CardBus support
+Support for hot-pluggable devices
+CONFIG_HOTPLUG
+ Say Y here if you want to attach devices to your computer that can
+ be attached and detached while the system is running. The most
+ prominent example of this are PCMCIA- or PC-cards, credit-card size
+ devices such as network cards, modems or hard drives which are
+ plugged into slots found on all modern laptop computers.
+
+PCMCIA/Cardbus support
CONFIG_PCMCIA
- Include kernel support for PCMCIA and CardBus devices. Because
- PCMCIA support requires additional components that are not part of
- the kernel (i.e., the pcmcia-cs package), building PCMCIA into the
- kernel is generally not recommended unless you have a specific
- need. If unsure, say N.
+ Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+ computer. These are credit-card size devices such as network cards,
+ modems or hard drives often used with laptops computers. There are
+ actually two varieties of these cards: the older 16 bit PCMCIA cards
+ and the newer 32 bit CardBus cards. If you want to use CardBus
+ cards, you need to say Y here and also to "CardBus support" below.
+
+ To use your PC-cards, you will need supporting software from David
+ Hinds' pcmcia-cs package (see the file Documentation/Changes for
+ location). Please also read the PCMCIA-HOWTO, available from
+ http://www.linuxdoc.org/docs.html#howto
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -2376,27 +2457,32 @@ CONFIG_PCMCIA
and ds.o. If you want to compile it as a module, say M here and
read Documentation/modules.txt.
- You will also need David Hinds' pcmcia-cs package (see the file
- Documentation/Changes for location). For more information, see the
- PCMCIA-HOWTO.
-
CardBus support
CONFIG_CARDBUS
- There are two types of PCMCIA devices: 16-bit PC Cards, and higher
- performance 32-bit CardBus devices. Use this option to include
- support for CardBus devices. If unsure, say Y.
+ CardBus is a bus mastering architecture for PC-cards, which allows
+ for 32 bit PC-cards (the original PCMCIA standard specifies only
+ a 16 bit wide bus). Many newer PC-cards are actually CardBus cards.
+
+ To use your PC-cards, you will need supporting software from David
+ Hinds' pcmcia-cs package (see the file Documentation/Changes for
+ location).
+
+ If unsure, say Y.
i82365/Yenta compatible bridge support
CONFIG_I82365
- Include support for PCMCIA and CardBus host bridges that are
- register compatible with the Intel i82365 and/or the Yenta
+ Say Y here to include support for PCMCIA and CardBus host bridges
+ that are register compatible with the Intel i82365 and/or the Yenta
specification: this includes virtually all modern PCMCIA bridges.
- If unsure, say Y.
+ "Bridge" is the name used for the hardware inside your computer that
+ PCMCIA cards are plugged into. If unsure, say Y.
Databook TCIC host bridge support
CONFIG_TCIC
- Include support for the Databook TCIC family of PCMCIA host bridges.
- These are only found on a handful of old systems. If unsure, say N.
+ Say Y here to include support for the Databook TCIC family of PCMCIA
+ host bridges. These are only found on a handful of old systems.
+ "Bridge" is the name used for the hardware inside your computer that
+ PCMCIA cards are plugged into. If unsure, say N.
System V IPC
CONFIG_SYSVIPC
@@ -2414,9 +2500,9 @@ CONFIG_SYSVIPC
http://www.linuxdoc.org/docs.html#guide .
Shared memory is now implemented using a new (minimal) virtual file
- system, which you need to mount before programs can use shared memory.
- To do this automatically at system startup just add the following line
- to your /etc/fstab:
+ system, which you need to mount before programs can use shared
+ memory. To do this automatically at system startup just add the
+ following line to your /etc/fstab:
none /var/shm shm defaults 0 0
@@ -2451,21 +2537,24 @@ CONFIG_SYSCTL
Kernel core (/proc/kcore) format
CONFIG_KCORE_ELF
- If you enabled support for /proc file system then the file /proc/kcore
- will contain the kernel core image. This can be used in gdb:
+ If you enabled support for /proc file system then the file
+ /proc/kcore will contain the kernel core image. This can be used
+ in gdb:
$ cd /usr/src/linux ; gdb vmlinux /proc/kcore
- Selecting ELF will make /proc/kcore appear in ELF core format as defined
- by the Executable and Linking Format specification. Selecting A.OUT will
- choose the old "a.out" format which may be necessary for some old versions
+ You have two choices here: ELF and A.OUT. Selecting ELF will make
+ /proc/kcore appear in ELF core format as defined by the Executable
+ and Linking Format specification. Selecting A.OUT will choose the
+ old "a.out" format which may be necessary for some old versions
of binutils or on some architectures.
- This is especially useful if you have compiled the kernel with "-g" option
- to preserve debugging information. It is mainly used for examining kernel
- data structures on the live kernel so if you don't understand what this
- means or are not a kernel hacker, just leave it at its default value ELF.
-
+ This is especially useful if you have compiled the kernel with the
+ "-g" option to preserve debugging information. It is mainly used
+ for examining kernel data structures on the live kernel so if you
+ don't understand what this means or are not a kernel hacker, just
+ leave it at its default value ELF.
+
Kernel support for ELF binaries
CONFIG_BINFMT_ELF
ELF (Executable and Linkable Format) is a format for libraries and
@@ -2569,10 +2658,10 @@ CONFIG_M386
all x86 CPU types (albeit not optimally fast), you can specify
"386" here.
- If you specify one of "486" or "586" or "Pentium" or "PPro", then
- the kernel will not necessarily run on earlier architectures (e.g. a
- Pentium optimized kernel will run on a PPro, but not necessarily on
- a i486).
+ If you specify one of "486" or "586" or "Pentium" or "PPro" or
+ "Athlon", then the kernel will not necessarily run on earlier
+ architectures (e.g. a Pentium optimized kernel will run on a PPro,
+ but not necessarily on a i486).
Here are the settings recommended for greatest speed:
- "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
@@ -2583,11 +2672,11 @@ CONFIG_M386
UMC U5D or U5S.
- "586" for generic Pentium CPUs, possibly lacking the TSC
(time stamp counter) register.
- - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5.
+ - "Pentium" for the Intel Pentium/Pentium MMX, and AMD K5.
- "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and
- Intel Pentium II/Pentium Pro.
+ Intel Pentium Pro/Celeron/Pentium II/Pentium III.
- "K6/II/III" for the AMD K6, K6-II and K6-III (aka K6-3D).
- - "Athlon" for the AMD Athlon (aka K7)
+ - "Athlon" for the AMD Athlon (K7).
If you don't know what to do, choose "386".
@@ -2612,9 +2701,7 @@ CONFIG_VIDEO_SELECT
"vga=" option from your boot loader (lilo or loadlin) or set
"vga=ask" which brings up a video mode menu on kernel startup. (Try
"man bootparam" or see the documentation of your boot loader about
- how to pass options to the kernel. The lilo procedure is also
- explained in the SCSI-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto .)
+ how to pass options to the kernel.)
Read the file Documentation/svga.txt for more information about the
Video mode selection support. If unsure, say N.
@@ -2658,11 +2745,6 @@ CONFIG_FB_ACORN
hardware found in Acorn RISC PCs and other ARM-based machines. If
unsure, say N.
-Apollo frame buffer device
-CONFIG_FB_APOLLO
- This is the frame buffer device driver for the monochrome graphics
- hardware found in some Apollo workstations.
-
Amiga native chipset support
CONFIG_FB_AMIGA
This is the frame buffer device driver for the builtin graphics
@@ -2769,8 +2851,8 @@ CONFIG_FB_S3TRIO
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.
+ 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
@@ -2797,17 +2879,18 @@ CONFIG_FB_ATY
inserted and removed from the running kernel whenever you want). The
module will be called atyfb.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-
+
ATI Rage128 display support (EXPERIMENTAL)
CONFIG_FB_ATY128
This driver supports graphics boards with the ATI Rage128 chips.
- Say Y if you have such a graphics board.
+ Say Y if you have such a graphics board and read
+ Documentation/fb/aty128fb.txt.
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 aty128fb.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-
+
PowerMac "control" frame buffer device support
CONFIG_FB_CONTROL
This driver supports a frame buffer for the graphics adapter in the
@@ -2828,16 +2911,6 @@ CONFIG_FB_CT65550
This is the frame buffer device driver for the Chips & Technologies
65550 graphics chip in PowerBooks.
-Mac frame buffer device
-CONFIG_FB_MAC
- This is the frame buffer device driver for the graphics hardware in
- m68k Macintoshes.
-
-HP300 frame buffer device
-CONFIG_FB_HP300
- This is the frame buffer device driver for the Topcat graphics
- hardware found in HP300 workstations.
-
TGA frame buffer support
CONFIG_FB_TGA
This is the frame buffer device driver for generic TGA graphic
@@ -2853,10 +2926,11 @@ CONFIG_FB_VESA
VGA 16-color planar support
CONFIG_FBCON_VGA_PLANES
This low level frame buffer console driver enable the kernel to use
- the 16-color planar modes of the old VGA cards where the bits of each
- pixel are separated into 4 plans.
- Only answer Y here if you have an (very old) VGA card that isn't
- VESA 2 compatible.
+ the 16-color planar modes of the old VGA cards where the bits of
+ each pixel are separated into 4 planes.
+
+ Only answer Y here if you have a (very old) VGA card that isn't VESA
+ 2 compatible.
VGA 16-color graphics console
CONFIG_FB_VGA16
@@ -2870,12 +2944,12 @@ CONFIG_FB_VGA16
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.
+ 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.
+ 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).
@@ -2895,22 +2969,21 @@ CONFIG_FBCON_FONTWIDTH8_ONLY
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
- This is the high resolution console font for Sun machines with very big
- letters (like the letters used in the SPARC PROM). If the standard font
- is unreadable for you, say Y, otherwise say N.
+ This is the high resolution console font for Sun machines with very
+ big letters (like the letters used in the SPARC PROM). If the
+ standard font is unreadable for you, say Y, otherwise say N.
VGA 8x8 font
CONFIG_FONT_8x8
This is the "high resolution" font for the VGA frame buffer (the one
- 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.
+ provided by the text console 80x50 (and higher) modes).
+
+ Note that 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.
@@ -2923,7 +2996,6 @@ CONFIG_FB_COMPAT_XPMAC
(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.
@@ -2932,11 +3004,12 @@ CONFIG_FBCON_HGA
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.
+ 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,
+ Say Y here if you have a Matrox Millennium, Matrox Millennium II,
Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video or
Matrox G400 card in your box. At this time, support for the G100,
@@ -2976,49 +3049,51 @@ CONFIG_FB_MATROX_G100
you select "Advanced lowlevel driver options", you should check 8
bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32
bpp packed pixel. You can also use font widths different from 8.
-
- If you need support for G400 secondary head, you must first enable
- I2C support and I2C bit-banging support in character devices section,
- and then Matrox I2C support and G400 secondary head support here
- in framebuffer section.
+
+ If you need support for G400 secondary head, you must first say Y to
+ "I2C support" and "I2C bit-banging support" in the character devices
+ section, and then to "Matrox I2C support" and "G400 second head
+ support" here in the framebuffer section.
Matrox I2C support
CONFIG_FB_MATROX_I2C
- This drivers creates I2C buses which are needed for accessing
- DDC (I2C) bus present on all Matroxes, I2C bus which interconnects
- Matrox optional devices, like MGA-TVO on G200 and G400, and
- secondary head DDC bus, present on G400 only.
+ This drivers creates I2C buses which are needed for accessing the
+ DDC (I2C) bus present on all Matroxes, an I2C bus which
+ interconnects Matrox optional devices, like MGA-TVO on G200 and
+ G400, and the secondary head DDC bus, present on G400 only.
You can say Y or M here if you want to experiment with monitor
detection code. You must say Y or M here if you want to use either
second head of G400 or MGA-TVO on G200 or G400.
- If you compile it as module, it will create module named i2c-matroxfb.o.
+ If you compile it as module, it will create a module named
+ i2c-matroxfb.o.
Matrox G400 second head support
CONFIG_FB_MATROX_MAVEN
- Say Y or M here if you want to use secondary head on G400 or MGA-TVO
- add-on on G200. Secondary head is not compatible with accelerated
- XFree 3.3.x SVGA servers - secondary head output is blanked while you
- are in X. With XFree 3.9.17 preview you can use both heads if you use
- SVGA over fbdev or fbdev driver on first head and fbdev driver on
- second head.
+ Say Y or M here if you want to use a secondary head (meaning two
+ monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary
+ head is not compatible with accelerated XFree 3.3.x SVGA servers -
+ secondary head output is blanked while you are in X. With XFree
+ 3.9.17 preview you can use both heads if you use SVGA over fbdev or
+ the fbdev driver on first head and the fbdev driver on second head.
- If you compile it as module, two modules are created, matroxfb_crtc2.o
- and matroxfb_maven.o. Matroxfb_maven is needed for both G200 and G400,
- matroxfb_crtc2 is needed only by G400. You must also load i2c-matroxfb
- to get it to run.
+ If you compile it as module, two modules are created,
+ matroxfb_crtc2.o and matroxfb_maven.o. Matroxfb_maven is needed for
+ both G200 and G400, matroxfb_crtc2 is needed only by G400. You must
+ also load i2c-matroxfb to get it to run.
- Driver starts in monitor mode and you must use matroxset tool (available
- at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) to switch it to PAL
- or NTSC or to swap primary and secondary head outputs. Secondary head
- driver also always start in 640x480 resolution, you must use fbset to
- change it.
+ The driver starts in monitor mode and you must use the matroxset
+ tool (available at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest)
+ to switch it to PAL or NTSC or to swap primary and secondary head
+ outputs. Secondary head driver also always start in 640x480
+ resolution, you must use fbset to change it.
- Also do not forget that second head supports only 16 and 32 bpp packed
- pixels, so it is good idea to compile them into kernel too. You can
- use only some font widths, as driver uses generic painting procedures
- (secondary head does not use acceleration engine).
+ Also do not forget that second head supports only 16 and 32 bpp
+ packed pixels, so it is a good idea to compile them into the kernel
+ too. You can use only some font widths, as the driver uses generic
+ painting procedures (the secondary head does not use acceleration
+ engine).
There is no need for enabling 'Matrox multihead support' if you have
only one Matrox card in the box.
@@ -3026,16 +3101,17 @@ CONFIG_FB_MATROX_MAVEN
Matrox unified driver multihead support
CONFIG_FB_MATROX_MULTIHEAD
Say Y here if you have more than one (supported) Matrox device in
- your computer and you want to use all of them. If you have only one
- device, you should say N because the driver compiled with Y is
- larger and a bit slower, especially on ia32 (ix86).
+ your computer and you want to use all of them for different monitors
+ ("multihead"). If you have only one device, you should say N because
+ the driver compiled with Y is larger and a bit slower, especially on
+ ia32 (ix86).
If you said M to "Matrox unified accelerated driver" and N here, you
- will still be able to use several Matrox devices simultaneously.
- This is slightly faster but uses 40 KB of kernel memory per Matrox
- card. You do this by inserting several instances of the module
- matroxfb.o into the kernel with insmod, supplying the parameter
- "dev=N" where N is 0, 1, etc. for the different Matrox devices.
+ will still be able to use several Matrox devices simultaneously:
+ insert several instances of the module matroxfb.o into the kernel
+ with insmod, supplying the parameter "dev=N" where N is 0, 1, etc.
+ for the different Matrox devices. This method is slightly faster but
+ uses 40 KB of kernel memory per Matrox card.
MDA text console (dual-headed)
CONFIG_MDA_CONSOLE
@@ -3188,12 +3264,6 @@ CONFIG_FBCON_MAC
bits per pixel packed pixels on Mac. It supports variable font
widths for low resolution screens.
-#VGA 16-color planar support
-#CONFIG_FBCON_VGA_PLANES
-###
-###What is this?
-###
-
VGA characters/attributes support
CONFIG_FBCON_VGA
This is the low level frame buffer console driver for VGA text mode;
@@ -3266,17 +3336,11 @@ CONFIG_PARPORT_OTHER
other non-standard types of parallel ports. This causes a
performance loss, so most people say N.
-Sun Ultra/AX-style hardware
-CONFIG_PARPORT_AX
- Say Y here if you need support for the parallel port hardware on Sun
- Ultra/AX machines. This code is also available as a module (say M),
- called parport_ax.o. If in doubt, saying N is the safe plan.
-
Support IEEE1284 status readback
CONFIG_PRINTER_READBACK
- If you have a device on your parallel port that support this protocol,
- this option'll enable it to report its status.
- It is safe to say Y.
+ If you have a device on your parallel port that support this
+ protocol, this option will allow the device to report its status. It
+ is safe to say Y.
IEEE1284 transfer modes
CONFIG_PARPORT_1284
@@ -3366,9 +3430,9 @@ CONFIG_INET
Internet connected Unix computer; for more information, read
http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ).
- If you say Y here and also to "/proc file system support" and "Sysctl
- support" below, you can change various aspects of the behavior of
- the TCP/IP code by writing to the (virtual) files in
+ If you say Y here and also to "/proc file system support" and
+ "Sysctl support" below, you can change various aspects of the
+ behavior of the TCP/IP code by writing to the (virtual) files in
/proc/sys/net/ipv4/*; the options are explained in the file
Documentation/Networking/ip-sysctl.txt.
@@ -3377,7 +3441,7 @@ CONFIG_INET
IP: multicasting
CONFIG_IP_MULTICAST
This is code for addressing several networked computers at once,
- enlarging your kernel by about 2 kB. You need multicasting if you
+ enlarging your kernel by about 2 KB. You need multicasting if you
intend to participate in the MBONE, a high bandwidth network on top
of the Internet which carries audio and video broadcasts. More
information about the MBONE is on the WWW at
@@ -3502,8 +3566,8 @@ CONFIG_IP_ROUTER
echo "1" > /proc/sys/net/ipv4/ip_forward
- at boot time after the /proc file system has been mounted. You can do
- that even if you say N here.
+ at boot time after the /proc file system has been mounted. You can
+ do that even if you say N here.
If unsure, say N here.
@@ -3511,7 +3575,7 @@ IP: kernel level autoconfiguration
CONFIG_IP_PNP
This enables automatic configuration of IP addresses of devices and
of the routing table during kernel boot, based on either information
- supplied at the kernel command line or by BOOTP or RARP protocols.
+ supplied on the kernel command line or by BOOTP or RARP protocols.
You need to say Y only for diskless machines requiring network
access to boot (in which case you want to say Y to "Root file system
on NFS" as well), because all other machines configure the network
@@ -3633,16 +3697,7 @@ CONFIG_INET_PCTCP
saying Y here. Everyone else says N.
People having problems with NCSA telnet should see the file
- linux/Documentation/networking/ncsa-telnet.
-
-Assume subnets are local
-CONFIG_INET_SNARL
- Say Y if you are on a subnetted network with all machines connected
- by Ethernet segments only, as this option optimizes network access
- for this special case. If there are other connections, e.g. SLIP
- links, between machines of your IP network, say N. If in doubt,
- answer N. The PATH mtu discovery facility will cover most cases
- anyway.
+ Documentation/networking/ncsa-telnet.
Path MTU Discovery (normally enabled)
CONFIG_PATH_MTU_DISCOVERY
@@ -3751,6 +3806,20 @@ CONFIG_IPV6_NETLINK
say Y to "Kernel/User network link driver" and to "Routing
messages" instead.
+Kernel httpd acceleration (EXPERIMENTAL)
+CONFIG_KHTTPD
+ The kernel httpd acceleration daemon (kHTTPd) is a (limited)
+ web server built into the kernel. It is limited since it can only
+ serve files from the file system. Saying "M" here builds the
+ kHTTPd module; this is NOT enough to have a working kHTTPd.
+ For safety reasons, the module has to be activated by doing a
+ "echo 1 > /proc/sys/net/khttpd/start" after inserting the module.
+
+ Before using this, read the README in net/khttpd !
+
+ The kHTTPd is experimental. Be careful when using it on a production
+ machine. Also note that kHTTPd doesn't support virtual servers yet.
+
IPX networking
CONFIG_IPX
This is support for the Novell networking protocol, IPX, commonly
@@ -3760,7 +3829,7 @@ CONFIG_IPX
ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) or from within
the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto ). In order to do the
- former, you'll also have to say Y to "NCP file systems support",
+ former, you'll also have to say Y to "NCP file system support",
below.
IPX is similar in scope to IP, while SPX, which runs on top of IPX,
@@ -3819,7 +3888,7 @@ CONFIG_SPX
Note that Novell NetWare file sharing does not use SPX; it uses a
protocol called NCP, for which separate Linux support is available
- ("NCP file systems support" below for the client side, and the user
+ ("NCP file system support" below for the client side, and the user
space programs lwared or mars_nwe for the server side).
Say Y here if you have use for SPX; read the IPX-HOWTO at
@@ -3844,7 +3913,7 @@ CONFIG_DECNET
More detailed documentation is available in the
Documentation/networking/decnet.txt file.
- Be sure to say Y to "/proc file systems support" and "Sysctl support"
+ Be sure to say Y to "/proc file system support" and "Sysctl support"
below when using DECnet, since you will need sysctl support to aid
in configuration at run time.
@@ -3865,22 +3934,28 @@ DECnet Router Support (EXPERIMENTAL)
CONFIG_DECNET_ROUTER
Add support for turning your DECnet Endnode into a level 1 or 2
router. This is an unfinished option for developers only. If you do
- turn it on, then make sure that you also say Y to "Kernel/User
- network link driver", "Routing messages" and "Network packet
+ say Y here, then make sure that you also say Y to "Kernel/User
+ network link driver", "Routing messages" and "Network packet
filtering". The first two are required to allow configuration via
rtnetlink (currently you need Alexey Kuznetsov's iproute2 package
- from ftp.inr.ac.ru). The "Network packet filtering" option will
- be required for the forthcoming routing daemon to work.
+ from ftp://ftp.inr.ac.ru). The "Network packet filtering" option
+ will be required for the forthcoming routing daemon to work.
See Documentation/networking/decnet.txt for more information.
+DECnet: use FWMARK value as routing key
+CONFIG_DECNET_ROUTE_FWMARK
+ If you say Y here, you will be able to specify different routes for
+ packets with different FWMARK ("firewalling mark") values
+ (see ipchains(8), "-m" argument).
+
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
+AppleTalk protocol support
CONFIG_ATALK
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
@@ -3894,7 +3969,7 @@ CONFIG_ATALK
supported by Linux.
General information about how to connect Linux, Windows machines and
- Macs is on the WWW at http://www.eats.com/linux_mac_win.html The
+ Macs is on the WWW at http://www.eats.com/linux_mac_win.html . The
NET-3-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto , contains valuable
information as well.
@@ -4401,17 +4476,23 @@ CONFIG_BRIDGE
Ethernet bridge, which means that the different Ethernet segments it
is connected to will appear as one Ethernet to the participants.
Several such bridges can work together to create even larger
- networks of Ethernets using the IEEE 802.1d spanning tree protocol.
- As this is a standard, Linux bridges will interwork properly with
+ networks of Ethernets using the IEEE 802.1 spanning tree algorithm.
+ As this is a standard, Linux bridges will cooperate properly with
other third party bridge products.
In order to use the ethernet bridge, you'll need the bridge
- configuration tools available from ftp://openrock.net/bridge. Please
- read the Bridge mini-HOWTO for more information. Note that if your
- box acts as a bridge, it probably contains several Ethernet devices,
- but the kernel is not able to recognize more than one at boot time
- without help; for details read the Ethernet-HOWTO, available from in
- http://www.linuxdoc.org/docs.html#howto .
+ configuration tools; see Documentation/networking/bridge.txt for
+ location. Please read the Bridge mini-HOWTO for more information.
+
+ Note that if your box acts as a bridge, it probably contains several
+ Ethernet devices, but the kernel is not able to recognize more than
+ one at boot time without help; for details read the Ethernet-HOWTO,
+ available from in http://www.linuxdoc.org/docs.html#howto .
+
+ If you want to compile this code 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 bridge.o.
If unsure, say N.
@@ -4491,16 +4572,17 @@ CONFIG_ATM
Classical IP over ATM
CONFIG_ATM_CLIP
Classical IP over ATM for PVCs and SVCs, supporting InARP and
- ATMARP. Typically you will either use LAN Emulation (LANE) or
- Classical IP to communicate with other IP hosts on your ATM network.
+ ATMARP. If you want to communication with other IP hosts on your ATM
+ network, you will typically either say Y here or to "LAN Emulation
+ (LANE)" below.
-Do NOT send ICMP if no neighbor
+Do NOT send ICMP if no neighbour
CONFIG_ATM_CLIP_NO_ICMP
- Normally, an "ICMP host unreachable" message is sent if a neighbor
+ Normally, an "ICMP host unreachable" message is sent if a neighbour
cannot be reached because there is no VC to it in the kernel's
ATMARP table. This may cause problems when ATMARP table entries are
briefly removed during revalidation. If you say Y here, packets to
- such neighbors are silently discarded instead.
+ such neighbours are silently discarded instead.
LAN Emulation (LANE) support
CONFIG_ATM_LANE
@@ -4524,12 +4606,16 @@ CONFIG_ATM_TCP
Efficient Networks ENI155P
CONFIG_ATM_ENI
Driver for the Efficient Networks ENI155p series and SMC ATM
- Power155 155 Mbps ATM adapters. Both, the versions with 512kB and
+ Power155 155 Mbps ATM adapters. Both, the versions with 512KB and
2MB on-board RAM (Efficient calls them "C" and "S", respectively),
and the FPGA and the ASIC Tonga versions of the board are supported.
The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D)
adapters.
+ This driver is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called eni.o.
+
Enable extended debugging
CONFIG_ATM_ENI_DEBUG
Extended debugging records various events and displays that list
@@ -4610,6 +4696,10 @@ CONFIG_ATM_ZATM
Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM
adapters.
+ This driver is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called zatm.o.
+
Enable extended debugging
CONFIG_ATM_ZATM_DEBUG
Extended debugging records various events and displays that list
@@ -4632,7 +4722,11 @@ IDT 77201/11 (NICStAR) (ForeRunnerLE)
CONFIG_ATM_NICSTAR
The NICStAR chipset family is used in a large number of ATM NICs for
25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
- series.
+ series. Say Y if you have one of those.
+
+ This driver is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called nicstar.o.
ForeRunner LE155 PHYsical layer
CONFIG_ATM_NICSTAR_USE_SUNI
@@ -4717,6 +4811,35 @@ CONFIG_ATM_IA_DEBUG
speed of the driver, and the size of your syslog files! When
inactive, they will have only a modest impact on performance.
+Linux telephony support
+CONFIG_PHONE
+ Say Y here if you have a telephony card, which for example allows
+ you to use a regular phone for voice-over-IP applications.
+
+ Note: this has nothing to do with modems. You do not need to say Y
+ here in order to be able to use a modem under Linux.
+
+ This support is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called phonedev.o.
+
+QuickNet Internet LineJack/PhoneJack support
+CONFIG_PHONE_IXJ
+ Say M if you have a telephony card manufactured by Quicknet
+ Technologies, Inc. These include the Internet PhoneJACK and
+ Internet LineJACK Telephony Cards. You will get a module called
+ ixj.o.
+
+ For the ISA versions of these products, you can configure the
+ cards using the isapnp tools (pnpdump/isapnp) or you can use the
+ isapnp support. Please read Documentation/telephony/ixj.txt.
+
+ For more information on these cards, see Quicknet's web site at:
+ http://www.quicknet.net/ .
+
+ If you do not have any Quicknet telephony cards, you can safely
+ say N here.
+
FORE Systems 200E-series
CONFIG_ATM_FORE200E
This is a driver for the FORE Systems 200E-series ATM adapter
@@ -4729,14 +4852,14 @@ CONFIG_ATM_FORE200E
Enable PCA-200E card support on PCI-based hosts
CONFIG_ATM_FORE200E_PCA
- Enable this if you want your PCA-200E cards to be probed.
+ Say Y here if you want your PCA-200E cards to be probed.
Use default PCA-200E firmware
CONFIG_ATM_FORE200E_PCA_DEFAULT_FW
Use the default PCA-200E firmware data shipped with the driver.
Normal users do not have to deal with the firmware stuff, so
- this feature is normally enabled.
+ they should say Y here.
Pathname of user-supplied binary firmware
CONFIG_ATM_FORE200E_PCA_FW
@@ -4744,20 +4867,20 @@ CONFIG_ATM_FORE200E_PCA_FW
firmware image supplied by the user. This pathname may be
absolute or relative to the drivers/atm directory.
- The driver comes with an adequate firmware image, so normal users
- do not have to supply an alternative one. They just enable the use
- of the default firmware instead.
+ The driver comes with an adequate firmware image, so normal users do
+ not have to supply an alternative one. They just say Y to "Use
+ default PCA-200E firmware" instead.
Enable SBA-200E card support on SBUS-based hosts
CONFIG_ATM_FORE200E_SBA
- Enable this if you want your SBA-200E cards to be probed.
+ Say Y here if you want your SBA-200E cards to be probed.
Use default SBA-200E firmware
CONFIG_ATM_FORE200E_SBA_DEFAULT_FW
Use the default SBA-200E firmware data shipped with the driver.
Normal users do not have to deal with the firmware stuff, so
- this feature is normally enabled.
+ they should say Y here.
Pathname of user-supplied binary firmware
CONFIG_ATM_FORE200E_SBA_FW
@@ -4765,9 +4888,9 @@ CONFIG_ATM_FORE200E_SBA_FW
firmware image supplied by the user. This pathname may be
absolute or relative to the drivers/atm directory.
- The driver comes with an adequate firmware image, so normal users
- do not have to supply an alternative one. They just enable the use
- of the default firmware instead.
+ The driver comes with an adequate firmware image, so normal users do
+ not have to supply an alternative one. They just say Y to "Use
+ default SBA-200E firmware", above.
Maximum number of tx retries
CONFIG_ATM_FORE200E_TX_RETRY
@@ -4815,8 +4938,8 @@ CONFIG_SCSI
The module will be called scsi_mod.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt and
Documentation/scsi.txt. However, do not compile this as a module if
- your root file systems (the one containing the directory /) is located
- on a SCSI device.
+ your root file system (the one containing the directory /) is
+ located on a SCSI device.
SCSI disk support
CONFIG_BLK_DEV_SD
@@ -4831,15 +4954,15 @@ CONFIG_BLK_DEV_SD
The module will be called sd_mod.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt and
Documentation/scsi.txt. Do not compile this driver as a module if
- your root file systems (the one containing the directory /) is located
- on a SCSI disk. In this case, do not compile the driver for your
- SCSI host adapter (below) as a module either.
+ your root file system (the one containing the directory /) is
+ located on a SCSI disk. In this case, do not compile the driver for
+ your SCSI host adapter (below) as a module either.
Extra SCSI Disks
CONFIG_SD_EXTRA_DEVS
This controls the amount of additional space allocated in tables for
drivers that are loaded as modules after the kernel is booted. In
- the event that the SCSI core itself was loaded as a module, this this
+ the event that the SCSI core itself was loaded as a module, this
value is the number of additional disks that can be loaded after the
first host driver is loaded.
@@ -4847,6 +4970,8 @@ CONFIG_SD_EXTRA_DEVS
involved with resizing the internal arrays on the fly. Someday this
flag will go away, and everything will work automatically.
+ If you don't understand what's going on, go with the default.
+
SCSI tape support
CONFIG_CHR_DEV_ST
If you want to use a SCSI tape drive under Linux, say Y and read the
@@ -4866,7 +4991,7 @@ CONFIG_BLK_DEV_SR
If you want to use a SCSI CDROM under Linux, say Y and read the
SCSI-HOWTO and the CDROM-HOWTO at
http://www.linuxdoc.org/docs.html#howto . Also make sure to say Y
- or M to "ISO 9660 CDROM file systems support" later.
+ or M to "ISO 9660 CDROM file system support" later.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -4877,15 +5002,17 @@ CONFIG_BLK_DEV_SR
Extra SCSI CDROMs
CONFIG_SR_EXTRA_DEVS
This controls the amount of additional space allocated in tables for
- drivers that are loaded as modules after the kernel is booted. In the
- event that the SCSI core itself was loaded as a module, this this value
- is the number of additional CDROMs that can be loaded after the first
- host driver is loaded.
+ drivers that are loaded as modules after the kernel is booted. In
+ the event that the SCSI core itself was loaded as a module, this
+ value is the number of additional CDROMs that can be loaded after
+ the first host driver is loaded.
Admittedly this isn't pretty, but there are tons of race conditions
involved with resizing the internal arrays on the fly. Someday this
flag will go away, and everything will work automatically.
+ If you don't understand what's going on, go with the default.
+
Enable vendor-specific extensions (for SCSI CDROM)
CONFIG_BLK_DEV_SR_VENDOR
This enables the usage of vendor specific SCSI commands. This is
@@ -4899,14 +5026,15 @@ CONFIG_CHR_DEV_SG
about anything having "SCSI" in its name other than hard disks,
CDROMs or tapes, say Y here. These won't be supported by the kernel
directly, so you need some additional software which knows how to
- talk to these devices using the SCSI protocol. For CD-writers, you
- would need the program cdwrite, available from
- ftp://metalab.unc.edu/pub/Linux/utils/disk-management ; for other
- devices, it's possible that you'll have to write the driver software
- yourself, so have a look at the SCSI-HOWTO and at the
- SCSI-Programming-HOWTO, both available from
- http://www.linuxdoc.org/docs.html#howto . Please read the file
- Documentation/scsi-generic.txt for more information.
+ talk to these devices using the SCSI protocol. For scanners, look at
+ SANE (www.mostang.com/sane). For CD writer software look at cdrecord
+ (www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private
+ /cdrecord.html) and for burning a "disk at once": cdrdao
+ (www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high quality
+ digital reader of audio CDs (www.xiph.org/paranoia).
+ For other devices, it's possible that you'll have to write the driver
+ software yourself. Please read the file Documentation/scsi-generic.txt
+ for more 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),
@@ -4916,13 +5044,14 @@ CONFIG_CHR_DEV_SG
Debug new queueing code for SCSI
CONFIG_SCSI_DEBUG_QUEUES
- This option turns on a lot of additional consistency checking for the new
- queueing code. This will adversely affect performance, but it is likely
- that bugs will be caught sooner if this is turned on. This will typically
- cause the kernel to panic if an error is detected, but it would have probably
- crashed if the panic weren't there. Comments/questions/problems to
- linux-scsi mailing list please. See http://www.andante.org/scsi_queue.html
- for more uptodate information.
+ This option turns on a lot of additional consistency checking for
+ the new queueing code. This will adversely affect performance, but
+ it is likely that bugs will be caught sooner if this is turned on.
+ This will typically cause the kernel to panic if an error is
+ detected, but it would have probably crashed if the panic weren't
+ there. Comments/questions/problems to linux-scsi mailing list
+ please. See http://www.andante.org/scsi_queue.html for more
+ up-to-date information.
Probe all LUNs on each SCSI device
CONFIG_SCSI_MULTI_LUN
@@ -4946,12 +5075,12 @@ CONFIG_SCSI_LOGGING
of SCSI related problems.
If you say Y here, no logging output will appear by default, but you
- can enable logging by saying Y to "/proc file systems support" and
+ can enable logging by saying Y to "/proc file system support" and
"Sysctl support" below and executing the command
echo "scsi log token [level]" > /proc/scsi/scsi
- at boot time after the /proc file systems has been mounted.
+ at boot time after the /proc file system has been mounted.
There are a number of things that can be used for 'token' (you can
find them in the source: drivers/scsi/scsi.c), and this allows you
@@ -4982,7 +5111,7 @@ CONFIG_SCSI_AHA152X
It is explained in section 3.3 of the SCSI-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto . You might also want to
- read the comments at the top of drivers/scsi/aha152x.c.
+ read the file drivers/scsi/README.aha152x.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -5129,18 +5258,22 @@ CONFIG_AIC7XXX_RESET_DELAY
after a bus reset to be ready for the next command, but most hard
drives and CD-ROM devices are ready in only a few seconds. This
option has a maximum upper limit of 20 seconds to avoid bad
- interactions between the aic7xxx driver and the rest of the linux
+ interactions between the aic7xxx driver and the rest of the Linux
kernel. The default value has been reduced to 5 seconds. If this
doesn't work with your hardware, try increasing this value.
IBM ServeRAID Support
CONFIG_SCSI_IPS
This is support for the IBM ServeRAID hardware RAID controllers.
- Consult the SCSI-HOWTO, available via anonymous FTP from
- ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, and the file
- README.ips in drivers/scsi for more information. If this driver
- does not work correctly without modification please contact the
- author by email at ipslinux@us.ibm.com.
+
+ Please consult the SCSI-HOWTO, available from
+ http://www.linuxdoc.org/docs.html#howto .
+
+ You can build this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ but only a single instance may be loaded. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt. The
+ module will be called ips.o.
BusLogic SCSI support
CONFIG_SCSI_BUSLOGIC
@@ -5165,6 +5298,15 @@ CONFIG_SCSI_OMIT_FLASHPOINT
substantial, so users of MultiMaster Host Adapters may wish to omit
it.
+DMX3191D SCSI support
+CONFIG_SCSI_DMX3191D
+ This is support for Domex DMX3191D SCSI Host Adapters.
+
+ This driver 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 dmx3191d.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
DTC3180/3280 SCSI support
CONFIG_SCSI_DTC3280
This is support for DTC 3180/3280 SCSI Host Adapters. Please read
@@ -5528,9 +5670,7 @@ CONFIG_SCSI_IBMMCA
info like under OS/2, but more informative, by setting
'ibmmcascsi=display' as an additional kernel parameter. Try "man
bootparam" or see the documentation of your boot loader about how to
- pass options to the kernel. The lilo procedure is also explained in
- the SCSI-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto .
+ pass options to the kernel.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -5857,13 +5997,32 @@ CONFIG_SCSI_SYM53C416
read Documentation/modules.txt. The module will be called
sym53c416.o.
+Simple 53c710 SCSI support (Compaq, NCR machines)
+CONFIG_SCSI_SIM710
+ This is a simple driver for NCR53c710 based SCSI host adapters.
+
+ More complex drivers for this chip are available ("NCR53c7,8xx SCSI
+ support", above), but they require that the scsi chip be able to do
+ DMA block moves between memory and on-chip registers, which can
+ cause problems under certain conditions. This driver is designed to
+ avoid these problems and is intended to work with any Intel machines
+ using 53c710 chips, including various Compaq and NCR machines.
+
+ Please read the comments at the top of the file
+ drivers/scsi/sim710.c for more information.
+
+ If you want to compile this driver 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 sim710.o.
+
Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
CONFIG_SCSI_DC390T
This driver supports PCI SCSI host adapters based on the Am53C974A
chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
PCscsi/PCnet (Am53/79C974) solutions.
- Documentation can be found in linux/drivers/scsi/README.tmscsim.
+ Documentation can be found in drivers/scsi/README.tmscsim.
Note that this driver does NOT support Tekram DC390W/U/F, which are
based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those.
@@ -5881,7 +6040,7 @@ CONFIG_SCSI_DC390T_NOGENSUPP
EEPROM to get initial values for its settings, such as speed,
termination, etc. If it can't find this EEPROM, it will use defaults
or the user supplied boot/module parameters. For details on driver
- configuration see linux/drivers/scsi/README.tmscsim.
+ configuration see drivers/scsi/README.tmscsim.
If you say Y here and if no EEPROM is found, the driver gives up and
thus only supports Tekram DC390(T) adapters. This can be useful if
@@ -6015,21 +6174,28 @@ CONFIG_SCSI_DEBUG
important data. This is primarily of use to people trying to debug
the middle and upper layers of the SCSI subsystem. If unsure, say N.
-Fibre Channel support
+Fibre Channel support and FC4 SCSI support
CONFIG_FC4
- This is an experimental 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.
+ Fibre Channel is a high speed serial protocol mainly used to
+ connect large storage devices to the computer; it is compatible with
+ and intended to replace SCSI.
+
+ This is an experimental support for storage arrays connected to your
+ computer using optical fibre cables and the "X3.269-199X Fibre
+ Channel Protocol for SCSI" specification. If you want to use this,
+ you need to say Y here and to "SCSI support" as well as to 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.
Sun SOC
CONFIG_FC4_SOC
Serial Optical Channel is an interface card with one or two Fibre
- Optic ports, each of which can be connected to a disk array. Note that
- if you have older firmware in the card, you'll need the microcode from
- the Solaris driver to make it work.
+ Optic ports, each of which can be connected to a disk array. Note
+ that if you have older firmware in the card, you'll need the
+ microcode from the Solaris driver to make it work.
This support is also available as a module called soc.o ( = code
which can be inserted in and removed from the running kernel
@@ -6038,11 +6204,11 @@ CONFIG_FC4_SOC
Sun SOC+ (aka SOCAL)
CONFIG_FC4_SOCAL
- Serial Optical Channel Plus is an interface card with up to two Fibre
- Optic ports. This card supports FC Arbitrated Loop (usually A5000 or
- internal FC disks in E[3-6]000 machines through the Interface Board).
- You'll probably need the microcode from the Solaris driver to make it
- work.
+ Serial Optical Channel Plus is an interface card with up to two
+ Fibre Optic ports. This card supports FC Arbitrated Loop (usually
+ A5000 or internal FC disks in E[3-6]000 machines through the
+ Interface Board). You'll probably need the microcode from the
+ Solaris driver to make it work.
This support is also available as a module called socal.o ( = code
which can be inserted in and removed from the running kernel
@@ -6060,9 +6226,9 @@ CONFIG_SCSI_PLUTO
Sun Enterprise Network Array (A5000 and EX500)
CONFIG_SCSI_FCAL
- This driver drives FC-AL disks connected through a Fibre Channel card
- using the drivers/fc4 layer (currently only SOCAL).
- The most common is either A5000 array or internal disks in E[3-6]000
+ This driver drives FC-AL disks connected through a Fibre Channel
+ card using the drivers/fc4 layer (currently only SOCAL). The most
+ common is either A5000 array or internal disks in E[3-6]000
machines.
This support is also available as a module called fcal.o ( = code
@@ -6123,6 +6289,96 @@ CONFIG_SCSI_POWERTECSCSI
This enables support for the Powertec SCSI card on Acorn systems. If
you have one of these, say Y. If unsure, say N.
+IEEE 1394 (aka FireWire) support
+CONFIG_IEEE1394
+ IEEE 1394 describes a high performance serial bus, which is also
+ known as FireWire(tm) or i.Link(tm) and is used for connecting all
+ sorts of devices (most notably digital video cameras) to your
+ computer.
+
+ If you have FireWire hardware and want to use it, say Y here. This
+ is the core support only, you will also need to select a driver for
+ your IEEE 1394 adapter.
+
+ 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 ieee1394.o.
+
+TI PCILynx IEEE 1394 support
+CONFIG_IEEE1394_PCILYNX
+ Say Y here if you have a IEEE-1394 controller with the Texas
+ Instruments PCILynx chip. Note: this driver is written for revision
+ 2 of this chip and may not work with revision 0.
+
+ 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 pcilynx.o.
+
+Use local RAM on PCILynx board
+CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ This option makes the PCILynx driver use local RAM available on some
+ PCILynx setups for Packet Control Lists. Local RAM is random access
+ memory which resides on the PCILynx board as opposed to on your
+ computer's motherboard. Local RAM may speed up command processing
+ because no PCI transfers are necessary during use of the Packet
+ Control Lists.
+
+ Note that there are no known PCILynx systems providing local RAM
+ except for the evaluation boards by Texas Instruments and that the
+ PCILynx does not reliably report missing RAM. This means that it is
+ dangerous to say Y here if you are not absolutely sure that your
+ board provides 64KB of local RAM.
+
+ If unsure, say N.
+
+Adaptec AIC-5800 IEEE 1394 support
+CONFIG_IEEE1394_AIC5800
+ Say Y here if you have a IEEE 1394 controller using the Adaptec
+ AIC-5800 chip. All Adaptec host adapters (89xx series) use this
+ chip, as well as miro's DV boards.
+
+ 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 aic5800.o.
+
+OHCI (Open Host Controller Interface) support
+CONFIG_IEEE1394_OHCI1394
+ Say Y here if you have a IEEE 1394 controller based on OHCI.
+ The current driver was only tested with OHCI chipsets made
+ by Texas Instruments. However, most third-party vendors use
+ TI chips.
+
+ 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 ohci1394.o.
+
+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
+ direct communication of user programs with the IEEE 1394 bus and
+ thus with the attached peripherals.
+
+ 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 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.
+
Network device support?
CONFIG_NETDEVICES
You can say N here if you don't intend to connect your Linux box to
@@ -6150,29 +6406,9 @@ CONFIG_NETDEVICES
Make sure to read the NET-3-HOWTO. Eventually, you will have to read
Olaf Kirch's excellent and free book "Network Administrator's
- Guide", to be found in ftp://metalab.unc.edu/pub/Linux/docs/LDP . If
+ Guide", to be found in http://www.linuxdoc.org/docs.html#guide . If
unsure, say Y.
-Bonding driver support
-CONFIG_BONDING
- Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
- Channels together. This is called 'Etherchannel' by Cisco, 'Trunking'
- by Sun, and 'Bonding' in Linux.
-
- If you have two ethernet connections to some other computer, you can
- make them behave like one double speed connection using this driver.
- Naturally, this has to be supported at the other end as well, either
- 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 ethernet segments instead
- of serial lines.
-
- 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 bonding.o.
-
Dummy net driver support
CONFIG_DUMMY
This is essentially a bit-bucket device (i.e. traffic you send to
@@ -6183,7 +6419,7 @@ CONFIG_DUMMY
thing often comes in handy, the default is Y. It won't enlarge your
kernel either. What a deal. Read about it in the Network
Administrator's Guide, available from
- http://metalab.unc.edu/mdw/linux.html#guide .
+ http://www.linuxdoc.org/docs.html#guide .
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -6192,6 +6428,26 @@ CONFIG_DUMMY
time, you need to compile this driver as a module. Instead of
'dummy', the devices will then be called 'dummy0', 'dummy1' etc.
+Bonding driver support
+CONFIG_BONDING
+ Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
+ Channels together. This is called 'Etherchannel' by Cisco,
+ 'Trunking' by Sun, and 'Bonding' in Linux.
+
+ If you have two ethernet connections to some other computer, you can
+ make them behave like one double speed connection using this driver.
+ Naturally, this has to be supported at the other end as well, either
+ with a similar Bonding Linux driver, a Cisco 5500 switch or a
+ SunTrunking SunSoft driver.
+
+ This is similar to the EQL driver, but it merges Ethernet segments
+ instead of serial lines.
+
+ 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 bonding.o.
+
SLIP (serial line) support
CONFIG_SLIP
Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
@@ -6231,11 +6487,11 @@ CONFIG_SLIP_COMPRESSED
on both ends. Ask your access provider if you are not sure and
answer Y, just in case. You will still be able to use plain SLIP. If
you plan to use SLiRP, the SLIP emulator (available from
- ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which allows
- you to use SLIP over a regular dial up shell connection, you
+ ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which
+ allows you to use SLIP over a regular dial up shell connection, you
definitely want to say Y here. The NET-3-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto , explains how to
- configure CSLIP. This won't enlarge your kernel.
+ http://www.linuxdoc.org/docs.html#howto , explains how to configure
+ CSLIP. This won't enlarge your kernel.
Keepalive and linefill
CONFIG_SLIP_SMART
@@ -6296,6 +6552,7 @@ CONFIG_PPP_ASYNC
into and removed from the running kernel). If you want to compile
it as a module, say M here and read Documentation/modules.txt.
+PPP support for sync tty ports
CONFIG_PPP_SYNC_TTY
Say Y (or M) here if you want to be able to use PPP over synchronous
(HDLC) tty devices, such as the SyncLink adapter. These devices
@@ -6338,10 +6595,20 @@ CONFIG_PPP_BSDCOMP
Wireless LAN (non-hamradio)
CONFIG_NET_RADIO
Support for wireless LANs and everything having to do with radio,
- but not with amateur radio. 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 radio
- interfaces.
+ but not with amateur radio or FM broadcasting.
+
+ Saying Y here also enables the Wireless Extensions (creates
+ /proc/net/wireless and enables ifconfig access). The Wireless
+ Extension is a generic API allowing a driver to expose to the user
+ space configuration and statistics specific to common Wireless LANs.
+ The beauty of it is that a single set of tool can support all the
+ variations of Wireless LANs, regardless of their type (as long as
+ the driver supports Wireless Extension). Another advantage is that
+ these parameters may be changed on the fly without restarting the
+ driver (or Linux). If you wish to use Wireless Extensions with
+ wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch
+ the tools from
+ http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html .
Some user-level drivers for scarab devices which don't require
special kernel support are available from
@@ -6388,8 +6655,8 @@ CONFIG_WAVELAN
in the source code drivers/net/wavelan.p.h.
You will also need the wireless tools package available from
- ftp://hyper.stanford.edu/pub/pcmcia/contrib/ . Please read the man
- pages contained therein.
+ http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html .
+ Please read the man pages contained therein.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -6402,95 +6669,109 @@ CONFIG_ARLAN
Aironet makes Arlan, a class of wireless LAN adapters. These use the
www.Telxon.com chip, which is also used on several similar cards.
This driver is tested on the 655 and IC2200 series cards. Look at
- http://www.ylenurme.ee/~elmer/655/ for latest information.
+ http://www.ylenurme.ee/~elmer/655/ for the latest information.
The driver is built as two modules, arlan and arlan-proc. The latter
is the /proc interface and is not needed most of time.
- On some computers the card ends up in non-valid state after some time.
- Use a ping-reset script to clear it.
+ On some computers the card ends up in non-valid state after some
+ time. Use a ping-reset script to clear it.
Aironet 4500/4800 series adapters
CONFIG_AIRONET4500
www.aironet.com (recently bought by Cisco) makes these 802.11 DS
adapters. Driver by Elmer Joandi (elmer@ylenurme.ee).
- Work sponsored by www.spectrumwireless.net and www.vendomar.ee
- This configuration option enables common code for all devices (PCI, ISA,
- PCMCIA)
- module is aironet4500_core
+
+ Say Y here if you have such an adapter, and then say Y below to
+ the option that applies to your particular type of card (PCI, ISA,
+ or PCMCIA).
+
+ This driver 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 aironet4500_core.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt as well as
+ Documentation/networking/net-modules.txt.
+
quick config parameters:
SSID=tsunami - "The Password"
adhoc=1 there are no Access Points around
- master=1 Adhoc master (the one who creates network sync)
- slave=1 Adhoc slave(btw, it is still forming own net
+ master=1 Adhoc master (the one who creates network
+ sync)
+ slave=1 Adhoc slave (btw, it is still forming own net
sometimes, and has problems with firmware...
change IbssJoinNetTimeout from /proc...)
channel=1..? meaningful in adhoc mode
- all other parameters can be set via /proc interface
- These parameters belong to .._card module, but alas, they are here
- if you have problems with screwing up card, both_bap_lock=1 is conservative
- value (performance hit 15%)
- for any other configuration options look at ..._proc module
+
+ If you have problems with screwing up card, both_bap_lock=1 is a
+ conservative value (performance hit 15%).
+
+ All other parameters can be set via the proc interface.
Aironet 4500/4800 ISA/PCI/PNP/365 support
CONFIG_AIRONET4500_NONCS
- This is module aironet4500_card, which includes _possibility_ to
- support for following
- PCI device
- ISA device in ISA mode(does not work currently)
- ISA device in PNP mode
- PCMCIA device _without_ cardservices, direct 365 chip INIT,
- does not work currently
- PCMCIA _with_ CardServices(normal way) is at another module
- radio parameters are currently configurable at ..._core module
+ If you have an ISA, PCI or PCMCIA Aironet 4500/4800 wireless LAN
+ card, say Y here, and then also to the options below that apply
+ to you.
+
+ This driver 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 aironet4500_card.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt
Aironet 4500/4800 PNP support
CONFIG_AIRONET4500_PNP
- This option should be enabled for ISA cards, remember to enable
- PNP jumper on board.
- module aironet4500_card
+ If you have an ISA Aironet 4500/4800 card which you want to use in
+ PNP (Plug and Play) mode, say Y here. This is the recommended mode
+ for ISA cards. Remember however to enable the PNP jumper on the
+ board if you say Y here.
Aironet 4500/4800 PCI support
CONFIG_AIRONET4500_PCI
- This option should be enabled for PCI cards
- module aironet4500_card
+ If you have an PCI Aironet 4500/4800 card, say Y here.
Aironet 4500/4800 ISA broken support (EXPERIMENTAL)
CONFIG_AIRONET4500_ISA
- This option enables support for ISA cards in non-PNP mode.
- Does not operate correctly by now.
- module aironet4500_card
+ If you have an ISA Aironet 4500/4800 card which you want to run in
+ non-PNP mode, say Y here. This is not recommended and does not work
+ correctly at this point. Say N.
Aironet 4500/4800 I365 broken support (EXPERIMENTAL)
CONFIG_AIRONET4500_I365
- This option enables support for PCMCIA cards on i365 controller
- _without_ cardservices. Doesn't have much sense and is not working
- properly. Comes from times where there was no PCMCIA support in
- kernel main source tree
+ If you have a PCMCIA Aironet 4500/4800 card which you want to use
+ without the standard PCMCIA cardservices provided by the pcmcia-cs
+ package, say Y here. This is not recommended, so say N.
Aironet 4500/4800 PCMCIA support
CONFIG_AIRONET4500_CS
- This option enables support for PCMCIA cards to be used with
- CardServices.
- This is not for ISA and PCI adapters.
- module aironet4500_cs.o
- The same option is both on:
- 1. PCMCIA netdevices configuring panel
- 2. Wireless netdevices configuring panel
- Possibility to change this option depends on options set in 2.
+ Say Y here if you have a PCMCIA Aironet 4500/4800 card which you
+ want to use with the standard PCMCIA cardservices provided by the
+ pcmcia-cs package.
+
+ This driver 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 aironet4500_cs.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
Aironet 4500/4800 PROC interface
CONFIG_AIRONET4500_PROC
- This option enables /proc/sys/aironet4500 interface for
- configuring the device.
- NOTE: it takes lot of memory. Compile it as module and remove
- after configuration
- module: aironet4500_proc
- additional info: look into drivers/net/aironet4500_rids.c
- this is quite human-readable(no need to know C)
+ If you say Y here (and to the "/proc file system" below), you will
+ be able to configure your Aironet card via the
+ /proc/sys/aironet4500 interface.
+ Additional info: look in drivers/net/aironet4500_rids.c.
-
+ This driver 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 aironet4500_proc.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
+
+ NOTE: the proc interface uses a lot of memory, so it is recommended
+ to compile it as a module and remove the module after
+ configuration.
LAPB over Ethernet driver
CONFIG_LAPBETHER
@@ -6520,8 +6801,18 @@ CONFIG_X25_ASY
PCMCIA network device support
CONFIG_NET_PCMCIA
- Say Y if you would like to include support for any PCMCIA network
- adapters. If unsure, say N.
+ Say Y if you would like to include support for any PCMCIA or CardBus
+ network adapters, then say Y to the driver for your particular card
+ below. PCMCIA- or PC-cards are credit-card size devices often used
+ with laptops computers; CardBus is the newer and faster version of
+ PCMCIA.
+
+ To use your PC-cards, you will need supporting software from David
+ Hinds' pcmcia-cs package (see the file Documentation/Changes for
+ location). You also want to check out the PCMCIA-HOWTO, available
+ from http://www.linuxdoc.org/docs.html#howto .
+
+ If unsure, say N.
3Com 3c589 PCMCIA support
CONFIG_PCMCIA_3C589
@@ -6552,8 +6843,8 @@ CONFIG_PCMCIA_FMVJ18X
This driver 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 fmvj18x_cs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
+ The module will be called fmvj18x_cs.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt. If unsure,
say N.
NE2000 compatible PCMCIA support
@@ -6574,8 +6865,8 @@ CONFIG_PCMCIA_NMCLAN
This driver 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 nmclan_cs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
+ The module will be called nmclan_cs.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt. If unsure,
say N.
SMC 91Cxx PCMCIA support
@@ -6585,9 +6876,9 @@ CONFIG_PCMCIA_SMC91C92
This driver 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 smc91c92_cs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
- say N.
+ The module will be called smc91c92_cs.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt. If
+ unsure, say N.
Xircom 16-bit PCMCIA support
CONFIG_PCMCIA_XIRC2PS
@@ -6596,10 +6887,21 @@ CONFIG_PCMCIA_XIRC2PS
This driver 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 xirc2ps_cs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
+ The module will be called xirc2ps_cs.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt. If unsure,
say N.
+COM20020 ARCnet PCMCIA support
+CONFIG_ARCNET_COM20020_CS
+ Say Y here if you intend to attach this type of ARCnet PCMCIA card
+ to your computer.
+
+ This driver 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 com20020_cs.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt. If
+ unsure, say N.
+
3Com 3c575 CardBus support
CONFIG_PCMCIA_3C575
This driver supports the 3Com 3c575 series of CardBus Fast Ethernet
@@ -6610,20 +6912,36 @@ CONFIG_PCMCIA_3C575
The module will be called 3c575_cb.o. If you want to do that, say M
here and read Documentation/modules.txt. If unsure, say N.
-SMC EPIC CardBus support
-CONFIG_PCMCIA_EPIC100
- This driver supports CardBus Fast Ethernet adapters based on the SMC
- EPIC chipset.
+Xircom Tulip-like CardBus support
+CONFIG_PCMCIA_XIRTULIP
+ This driver is for the Digital "Tulip" Ethernet CardBus adapters.
+ 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.
- This driver can only be compiled as a module ( = code which can be
+ This driver 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 epic100_cb.o. If you want to do that, say
- M here and read Documentation/modules.txt. If unsure, say N.
+ The module will be called xircom_tulip_cb.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. If
+ unsure, say N.
+
+Pcmcia Wireless LAN
+CONFIG_NET_PCMCIA_RADIO
+ Say Y here if you would like to use a PCMCIA (PC-card) device to
+ connect to a wireless local area network. Then say Y to the driver
+ for your particular card below.
+
+ To use your PC-cards, you will need supporting software from David
+ Hinds' pcmcia-cs package (see the file Documentation/Changes for
+ location). You also want to check out the PCMCIA-HOWTO, available
+ from http://www.linuxdoc.org/docs.html#howto .
Aviator/Raytheon 2.4MHz wireless support
CONFIG_PCMCIA_RAYCS
Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
(PC-card) wireless Ethernet networking card to your computer.
+ Please read the file Documentation/networking/ray_cs.txt for
+ details.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -6633,13 +6951,13 @@ CONFIG_PCMCIA_RAYCS
Xircom Netwave AirSurfer wireless support
CONFIG_PCMCIA_NETWAVE
- Say Y here if you intend to attach a Xircom Netwave AirSurfer PCMCIA
- (PC-card) wireless Ethernet networking card to your computer.
+ Say Y here if you intend to attach this type of PCMCIA (PC-card)
+ wireless Ethernet networking card to your computer.
This driver 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 netwave_cs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
+ The module will be called netwave_cs.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt. If unsure,
say N.
AT&T/Lucent Wavelan wireless support
@@ -6650,8 +6968,8 @@ CONFIG_PCMCIA_WAVELAN
This driver 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 wavelan_cs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. If unsure,
+ The module will be called wavelan_cs.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt. If unsure,
say N.
PLIP (parallel port) support
@@ -6814,17 +7132,6 @@ 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
@@ -6850,18 +7157,6 @@ 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
@@ -6917,9 +7212,15 @@ CONFIG_NET_SCHED
That package also contains some documentation; for more, check out
http://snafu.freedom.org/linux2.2/iproute-notes.html .
- If you say Y here and to "/proc file system support" below, you will
- be able to read status information about packet schedulers from the
- file /proc/net/psched.
+ This Quality of Service (QoS) support will enable you to use
+ Differentiated Services (diffserv) and Resource Reservation Protocol
+ (RSVP) on your Linux router if you also say Y to "QoS support",
+ "Packet classifier API" and to some classifiers below. Documentation
+ and software is at http://icawwww1.ipfl.ch/linux/diffserv/ .
+
+ If you say Y here and to "/proc file system" below, you will be able
+ to read status information about packet schedulers from the file
+ /proc/net/psched.
The available schedulers are listed in the following questions; you
can say Y to as many as you like. If unsure, say N now.
@@ -7030,12 +7331,23 @@ CONFIG_NET_SCH_TBF
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
+### Add these
+#+tristate ' GRED queue' CONFIG_NET_SCH_GRED
+#+tristate ' Diffserv field marker' CONFIG_NET_SCH_DSMARK
+#+tristate ' Ingress Qdisc' CONFIG_NET_SCH_INGRESS
+
QoS support
CONFIG_NET_QOS
Say Y here if you want to include Quality Of Service scheduling
features, which means that you will be able to request certain
rate-of-flow limits for your network devices.
+ This Quality of Service (QoS) support will enable you to use
+ Differentiated Services (diffserv) and Resource Reservation Protocol
+ (RSVP) on your Linux router if you also say Y to "Packet classifier
+ API" and to some classifiers below. Documentation and software is at
+ http://icawwww1.ipfl.ch/linux/diffserv/ .
+
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 QoS support.
@@ -7054,8 +7366,16 @@ CONFIG_NET_CLS
choice of several different packet classifiers with the following
questions.
+ This will enable you to use Differentiated Services (diffserv) and
+ Resource Reservation Protocol (RSVP) on your Linux router.
+ Documentation and software is at
+ http://icawwww1.ipfl.ch/linux/diffserv/ .
+
+### Add
+#tristate ' TC index classifier' CONFIG_NET_CLS_TCINDEX
+
Routing tables based classifier
-CONFIG_NET_CLS_ROUTE
+CONFIG_NET_CLS_ROUTE4
If you say Y here, you will be able to classify outgoing packets
according to the route table entry they matched. If unsure, say Y.
@@ -7114,7 +7434,7 @@ CONFIG_NET_CLS_RSVP6
here and read Documentation/modules.txt
#
-# Ingres traffic policing
+# Traffic policing (needed for in/egress)
# CONFIG_NET_CLS_POLICE
###
### Some expert please fill these in
@@ -7127,6 +7447,22 @@ CONFIG_NET_PROFILE
performance will be written to /proc/net/profile. If you don't know
what it is about, you don't need it: say N.
+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.
+ Usually, a quite expensive external device called a `WAN router' is
+ needed to connect to a WAN.
+
+ As an alternative, a relatively inexpensive WAN interface card can
+ allow your Linux box to directly connect to a WAN. If you have one
+ of those cards and wish to use it under Linux, say Y here and also
+ to the WAN driver for your card, below.
+
+ If unsure, say N.
+
Comtrol Hostess SV-11 support
CONFIG_HOSTESS_SV11
This is a network card for low speed synchronous serial links, at
@@ -7158,16 +7494,24 @@ CONFIG_COSA
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.
+ Fibre Channel is a high speed serial protocol mainly used to connect
+ large storage devices to the computer; it is compatible with and
+ intended to replace SCSI.
-# Interphase 5526 Tachyon chipset based adaptor support
-# CONFIG_IPHASE5526
+ If you intend to use Fibre Channel, you need to have a Fibre channel
+ adaptor card in your computer; say Y here and to the driver for your
+ adaptor below. You also should have said Y to "SCSI support" and
+ "SCSI generic support".
+Interphase 5526 Tachyon chipset based adaptor support
+CONFIG_IPHASE5526
+ Say Y here if you have a Fibre Channel adaptor of this kind.
+
+ The driver 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 iph5526.o. For general information about
+ modules read Documentation/modules.txt.
+
Red Creek Hardware VPN (EXPERIMENTAL)
CONFIG_RCPCI
This is a driver for hardware which provides a Virtual Private
@@ -7178,43 +7522,46 @@ CONFIG_RCPCI
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
-SBNI Leased Line Adapters
+SBNI12-xx support
CONFIG_SBNI
- This is a driver for ISA SBNI12-xx cards that is a low cost
- alternative to leased line modems. Say Y if you want to insert
- driver into kernel or say M to compile driver as a module.
+ This is a driver for ISA SBNI12-xx cards which are low cost
+ alternatives to leased line modems. Say Y if you want to insert
+ the driver into the kernel or say M to compile it as a module (the
+ module will be called sbni.o).
You can find more information and last versions of drivers and
- utilities at http://www.granch.ru. If you have any question you
- can mail to sbni@granch.ru.
+ utilities at http://www.granch.ru . If you have any question you
+ can send email to sbni@granch.ru.
Say N if unsure.
-
-WAN Drivers
-CONFIG_WAN_DRIVERS
- Say Y to this option if your Linux box contains a WAN card and you
- are planning to use the box as a WAN ( = Wide Area Network) router
- ( = device used to interconnect local area networks over wide area
- communication links, such as leased lines or public data networks,
- e.g. X.25 or frame relay) and you will be offered a list of drivers
- for WAN cards currently available. For more information, read
- Documentation/networking/wan-router.txt.
+
+WAN router drivers
+CONFIG_WAN_ROUTER_DRIVERS
+ If you have a WAN interface card and you want your Linux box to act
+ as a WAN router, thereby connecting you Local Area Network to the
+ outside world over the WAN connection, say Y here and then to the
+ driver for your card below. In addition, you need to say Y to "Wan
+ Router".
+
+ You will need the wan-tools package which is available from
+ ftp://ftp.sangoma.com . Read Documentation/networking/wan-router.txt
+ for more information.
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 WAN card drivers. If unsure, say N.
+ the questions about WAN router drivers. If unsure, say N.
Sangoma WANPIPE(tm) multiprotocol cards
CONFIG_VENDOR_SANGOMA
- WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com ) is a
- family of intelligent multiprotocol WAN adapters with data transfer
- rates up to T1 (1.544 Mbps). They are also known as Synchronous Data
- Link Adapters (SDLA) and designated S502E(A), S503 or S508. These
- cards support the X.25, Frame Relay, and PPP protocols. If you have
- one or more of these cards, say Y to this option; you may then also
- want to read the file Documentation/networking/wanpipe.txt. The next
- questions will ask you about the protocols you want the driver to
- support.
+ WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com ) is
+ a family of intelligent multiprotocol WAN adapters with data
+ transfer rates up to T1 (1.544 Mbps). They are also known as
+ Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
+ or S508. These cards support the X.25, Frame Relay, and PPP
+ protocols. If you have one or more of these cards, say Y to this
+ option; you may then also want to read the file
+ Documentation/networking/wanpipe.txt. The next questions will ask
+ you about the protocols you want the driver to support.
The driver will be compiled as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -7229,6 +7576,13 @@ CONFIG_WANPIPE_CARDS
re-compiling the driver, but remember that in this case you'll waste
some kernel memory (about 1K per card).
+WANPIPE Cisco HDLC support
+CONFIG_WANPIPE_CHDLC
+ Say Y to this option if you are planning to connect a WANPIPE card
+ to a connection which uses the synchronous Cisco HDLC (High-level
+ Data Link Control) protocol. This protocol is often used on
+ high-speed leased lines like T1/E1.
+
WANPIPE X.25 support
CONFIG_WANPIPE_X25
Say Y to this option if you are planning to connect a WANPIPE card
@@ -7255,13 +7609,13 @@ CONFIG_WANPIPE_PPP
MultiGate/COMX support
CONFIG_COMX
- Say Y if you want to use any board from the MultiGate (COMX) family.
- These boards are synchronous serial adapters for the PC, manufactured
- by ITConsult-Pro Co, Hungary.
+ Say Y if you want to use any board from the MultiGate (COMX) family.
+ These boards are synchronous serial adapters for the PC,
+ manufactured by ITConsult-Pro Co, Hungary.
- Read linux/Documentation/networking/comx.txt for help on configuring
- and using COMX interfaces. Further info on these cards can be found at
- http://www.itc.hu or <info@itc.hu>.
+ Read linux/Documentation/networking/comx.txt for help on configuring
+ and using COMX interfaces. Further info on these cards can be found
+ at http://www.itc.hu or <info@itc.hu>.
If you want to compile this as a module, say M and read
Documentation/modules.txt. The module will be called comx.o.
@@ -7279,30 +7633,34 @@ CONFIG_COMX_HW_COMX
LoCOMX board support
CONFIG_COMX_HW_LOCOMX
- Hardware driver for the 'LoCOMX' board from the MultiGate family. Say Y
- if you have a board like this.
+ Hardware driver for the 'LoCOMX' board from the MultiGate family.
+ Say Y if you have a board like this.
If you want to compile this as a module, say M and read
- Documentation/modules.txt. The module will be called comx-hw-locomx.o.
+ Documentation/modules.txt. The module will be called
+ comx-hw-locomx.o.
MixCOM board support
CONFIG_COMX_HW_MIXCOM
- Hardware driver for the 'MixCOM' board from the MultiGate family. Say Y
- if you have a board like this.
+ Hardware driver for the 'MixCOM' board from the MultiGate family.
+ Say Y if you have a board like this.
If you want to use the watchdog device on this card, you should
select it in the Watchdog Cards section of the Character Devices
- configuration. The ISDN interface of this card is Teles 16.3 compatible,
- you should enable it in the ISDN configuration menu. The driver for the
- flash ROM of this card is available separately on ftp://ftp.itc.hu/.
+ configuration. The ISDN interface of this card is Teles 16.3
+ compatible, you should enable it in the ISDN configuration menu. The
+ driver for the flash ROM of this card is available separately on
+ ftp://ftp.itc.hu/.
If you want to compile this as a module, say M and read
- Documentation/modules.txt. The module will be called comx-hw-mixcom.o.
+ Documentation/modules.txt. The module will be called
+ comx-hw-mixcom.o.
MultiGate Cisco-HDLC and synchronous PPP protocol support
CONFIG_COMX_PROTO_PPP
- Cisco-HDLC and synchronous PPP protocol driver for all MultiGate boards.
- Say Y if you want to use either protocol on your MultiGate boards.
+ Cisco-HDLC and synchronous PPP protocol driver for all MultiGate
+ boards. Say Y if you want to use either protocol on your MultiGate
+ boards.
If you want to compile this as a module, say M and read
Documentation/modules.txt. The module will be called
@@ -7314,7 +7672,8 @@ CONFIG_COMX_PROTO_LAPB
want to use this protocol on your MultiGate boards.
If you want to compile this as a module, say M and read
- Documentation/modules.txt. The module will be called comx-proto-lapb.o.
+ Documentation/modules.txt. The module will be called
+ comx-proto-lapb.o.
MultiGate Frame Relay protocol support
CONFIG_COMX_PROTO_FR
@@ -7322,7 +7681,8 @@ CONFIG_COMX_PROTO_FR
want to use this protocol on your MultiGate boards.
If you want to compile this as a module, say M and read
- Documentation/modules.txt. The module will be called comx-proto-fr.o.
+ Documentation/modules.txt. The module will be called
+ comx-proto-fr.o.
Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL)
CONFIG_CYCLADES_SYNC
@@ -7343,7 +7703,7 @@ CONFIG_CYCLADES_SYNC
Feel free to contact me or the cycsyn-devel mailing list at
acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
additional details, I hope to have documentation available as soon
- as possible (Cyclades Brazil is writing the Documentation).
+ as possible. (Cyclades Brazil is writing the Documentation).
The driver will be compiled as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -7383,22 +7743,6 @@ CONFIG_NET_ETHERNET
kernel: saying N will just cause this configure script to skip all
the questions about Ethernet network cards. If unsure, say N.
-Sun LANCE Ethernet support
-CONFIG_SUN_LANCE
- This is support for lance Ethernet cards on Sun workstations such as
- the SPARCstation IPC (any SPARC with a network interface 'le0' under
- SunOS basically).
-
- This driver 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 lance.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
-
-Sun Intel Ethernet support
-CONFIG_SUN_INTEL
- This is support for the Intel Ethernet cards on some Sun
- workstations (all those with a network interface 'ie0' under SunOS).
-
Western Digital/SMC cards
CONFIG_NET_VENDOR_SMC
If you have a network (Ethernet) card belonging to this class, say Y
@@ -7494,19 +7838,6 @@ CONFIG_NE2K_PCI
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
-PCI DM9102(A)/DM9132/DM9801 support
-CONFIG_DM9102
- This driver is for DM9102 compatible PCI cards from Davicom
- (http://www.davicom.com.tw) including models DM9132 & DM9801.
- If you have a PCI DM9102, DM9132 or DM9801 network (Ethernet)
- card, say Y.
-
- This driver 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 dmfe.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt as well as
- Documentation/networking/net-modules.txt.
-
Racal-Interlan (Micom) NI cards
CONFIG_NET_VENDOR_RACAL
If you have a network (Ethernet) card belonging to this class, such
@@ -7570,9 +7901,9 @@ CONFIG_RTL8129
RealTek RTL-8139 PCI Fast Ethernet Adapter support
CONFIG_8139TOO
This is a driver for the Fast Ethernet PCI network cards based on
- the RTL8139 chip. If you have one of those, say Y and
- read the Ethernet-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto .
+ the RTL8139 chips. If you have one of those, say Y and read
+ Documentation/networking/8139too.txt as well as the Ethernet-HOWTO,
+ available from http://www.linuxdoc.org/docs.html#howto .
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -7584,13 +7915,13 @@ CONFIG_SIS900
This is a driver for the Fast Ethernet PCI network cards based on
the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
SiS 630 and SiS 540 chipsets. If you have one of those, say Y and
- read the Ethernet-HOWTO, available via FTP (user: anonymous) in
- ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read
- Documentation/networking/sis900.txt and comments at the beginning
- of drivers/net/sis900.c for more information.
+ read the Ethernet-HOWTO, available at
+ http://www.linuxdoc.org/docs.html#howto . Please read
+ Documentation/networking/sis900.txt and comments at the beginning of
+ drivers/net/sis900.c for more information.
- This driver also supports AMD 79C901 HomePNA such that you can use
- your phone line as network cable.
+ This driver also supports AMD 79C901 HomePNA so that you can use
+ your phone line as a network cable.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -7632,6 +7963,18 @@ CONFIG_NET_SB1000
If you don't have this card, of course say N.
+Adaptec Starfire support (EXPERIMENTAL)
+CONFIG_ADAPTEC_STARFIRE
+ Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
+ adapter. The DuraLAN chip is used on the 64 bit PCI boards from
+ Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
+ driver.
+
+ If you want to compile this driver 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. This is recommended.
+ The module will be called starfile.o.
+
Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
CONFIG_ACENIC
Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
@@ -7682,6 +8025,11 @@ MyriCOM Gigabit Ethernet support
CONFIG_MYRI_SBUS
This driver supports MyriCOM Sbus gigabit ethernet cards.
+ If you want to compile this driver 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. This is recommended.
+ The module will be called myri_sbus.o.
+
AMD LANCE and PCnet (AT1500 and NE2100) support
CONFIG_LANCE
If you have a network (Ethernet) card of this type, say Y and read
@@ -7694,6 +8042,12 @@ CONFIG_LANCE
say M here and read Documentation/modules.txt. This is recommended.
The module will be called lance.o.
+SGI IOC3 Ethernet
+CONFIG_SGI_IOC3_ETH
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ http://www.linuxdoc.org/docs.html#howto .
+
3COM cards
CONFIG_NET_VENDOR_3COM
If you have a network (Ethernet) card belonging to this class, say Y
@@ -7797,6 +8151,18 @@ CONFIG_EL3
Documentation/networking/net-modules.txt. The module will be called
3c509.o.
+3c515 ISA Fast EtherLink
+CONFIG_3C515
+ If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
+ network card, say Y and read the Ethernet-HOWTO, available from
+ http://www.linuxdoc.org/docs.html#howto .
+
+ 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 as well as
+ Documentation/networking/net-modules.txt. The module will be called
+ 3c515.o.
+
3c590 series (592/595/597) "Vortex" support
CONFIG_VORTEX
If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597)
@@ -7858,7 +8224,7 @@ CONFIG_ARCNET_ETH
ARCnet documentation in Documentation/networking/arcnet.txt for more
information about using arc0e and arc0s.
-Enable arc0s (ARCnet RFC1051 packet format)
+Enable old ARCNet packet format (RFC 1051)
CONFIG_ARCNET_1051
This allows you to use RFC1051 with your ARCnet card via the virtual
arc0s device. You only need arc0s if you want to talk to ARCnet
@@ -8178,7 +8544,7 @@ CONFIG_LNE390
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
-Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)
+Novell/Eagle/Microdyne NE3210 EISA support
CONFIG_NE3210
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
@@ -8263,10 +8629,10 @@ CONFIG_EEPRO100
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
-EtherExpress PRO/100 support
-CONFIG_EEPRO100_PM (EXPERIMENTAL)
+Enable Power Management (EXPERIMENTAL)
+CONFIG_EEPRO100_PM
If you want to play around with power management code
- that has reported to lock up some machines, say Y here.
+ that has been reported to lock up some machines, say Y here.
ICL EtherTeam 16i/32 support (EXPERIMENTAL)
CONFIG_ETH16I
@@ -8297,7 +8663,7 @@ CONFIG_TLAN
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
- Please email feedback to torben.mathiasen@compaq.com.
+ Please email feedback to torben.mathiasen@compaq.com.
VIA Rhine support
CONFIG_VIA_RHINE
@@ -8310,6 +8676,19 @@ CONFIG_VIA_RHINE
a module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
+PCI DM9102(A)/DM9132/DM9801 support
+CONFIG_DM9102
+ This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
+ Davicom ( http://www.davicom.com.tw ). If you have such a network
+ (Ethernet) card, say Y. Some information is contained in the file
+ Documentation/networking/dmfe.txt.
+
+ This driver 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 dmfe.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt as well as
+ Documentation/networking/net-modules.txt.
+
Racal-Interlan EISA ES3210 support (EXPERIMENTAL)
CONFIG_ES3210
If you have a network (Ethernet) card of this type, say Y and read
@@ -8347,18 +8726,6 @@ CONFIG_ZNET
by this driver. Read the Ethernet-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto .
-Adaptec Starfire support
-CONFIG_ADAPTEC_STARFIRE
- If you have an Ethernet network card like this, say Y and read the
- Ethernet-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto .
-
- This driver 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 starfire.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt as well as
- Documentation/networking/net-modules.txt.
-
Pocket and portable adapters
CONFIG_NET_POCKET
Cute little network (Ethernet) devices which attach to the parallel
@@ -8386,9 +8753,14 @@ CONFIG_ATP
port. Read drivers/net/atp.c as well as the Ethernet-HOWTO,
available from http://www.linuxdoc.org/docs.html#howto , if you
want to use this. If you intend to use this driver, you should have
- said N to the Parallel Printer support, because the two drivers
+ said N to the "Parallel printer support", because the two drivers
don't like each other.
+ If you want to compile this driver as a module however ( = 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 atp.o.
+
D-Link DE600 pocket adapter support
CONFIG_DE600
This is a network (Ethernet) device which attaches to your parallel
@@ -8459,22 +8831,22 @@ CONFIG_IBMOL
The module will will be called olympic.o. If you want to compile it
as a module, say M here and read Documentation/modules.txt.
- Also read the file Documentation/networking/olympic.txt or check the
+ Also read the file Documentation/networking/olympic.txt or check the
Linux Token Ring Project site for the latest information at
- http://www.linuxtr.net
+ http://www.linuxtr.net .
IBM Lanstreamer chipset PCI adapter support
CONFIG_IBMLS
This is support for IBM Lanstreamer PCI Token Ring Cards.
- If you have such an adapter, say Y and read the Token-Ring mini-HOWTO
- available via FTP (user:anonymous) from
+ If you have such an adapter, say Y and read the Token-Ring
+ mini-HOWTO available via FTP (user:anonymous) from
ftp://metalab.unc/edu/pub/Linux/docs/HOWTO.
This driver is also available as a modules ( = code which can be
inserted in and removed from the running kernel whenever you want).
- The modules will be called lanstreamer.o. If you want to compile it as
- a module, say M here and read Documentation/modules.txt.
+ The modules will be called lanstreamer.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt.
Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support
CONFIG_TMS380TR
@@ -8483,16 +8855,21 @@ CONFIG_TMS380TR
includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect
TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591),
Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several
- Madge adapters. If selected, you will be asked to select
+ Madge adapters. If you say Y here, you will be asked to select
which cards to support below. If you're using modules, each
class of card will be supported by a separate module.
- If you have such an adapter and would like to use it, say Y or M and
+ If you have such an adapter and would like to use it, say Y and
read the Token-Ring mini-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto .
- Also read the file linux/Documentation/networking/tms380tr.txt or check
- http://www.auk.cx/tms380tr/
+ Also read the file Documentation/networking/tms380tr.txt or
+ check http://www.auk.cx/tms380tr/ .
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will will be called tms380tr.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt.
Generic TMS380 PCI support
CONFIG_TMSPCI
@@ -8504,30 +8881,53 @@ CONFIG_TMSPCI
- Thomas-Conrad TC4048 PCI 4/16
- 3Com Token Link Velocity
+ This driver is available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will will be called tmspci.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt.
+
Madge Smart 16/4 PCI Mk2 support
CONFIG_ABYSS
- This tms380 module supports the Madge Smart 16/4 PCI Mk2 cards (51-02).
+ This tms380 module supports the Madge Smart 16/4 PCI Mk2
+ cards (51-02).
+
+ This driver is available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will will be called abyss.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt.
Madge Smart 16/4 Ringode MicroChannel
CONFIG_MADGEMC
This tms380 module supports the Madge Smart 16/4 MC16 and MC32
- MicroChannel adapters
+ MicroChannel adapters.
+
+ This driver is available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will will be called madgemc.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt.
SMC ISA TokenRing adapter support
CONFIG_SMCTR
- This is support for the ISA and MCA SMC Token Ring cards, specifically
- SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A (8115T/A) adapters.
+ This is support for the ISA and MCA SMC Token Ring cards,
+ specifically SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A
+ (8115T/A) adapters.
If you have such an adapter and would like to use it, say Y or M and
read the Token-Ring mini-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto .
+ http://www.linuxdoc.org/docs.html#howto and the file
+ Documentation/networking/smctr.txt.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will will be called smctr.o. If you want to compile it
+ as a module, say M here and read Documentation/modules.txt.
Sun Happy Meal 10/100baseT support
CONFIG_HAPPYMEAL
- This driver supports the "hme" interface present on most Ultra systems
- and as an option on older Sbus systems. This driver supports both PCI
- and Sbus devices. This driver also supports the "qfe" quad 100baseT
- device available in both PCI and Sbus configurations.
+ This driver supports the "hme" interface present on most Ultra
+ systems and as an option on older Sbus systems. This driver supports
+ both PCI and Sbus devices. This driver also supports the "qfe" quad
+ 100baseT device available in both PCI and Sbus configurations.
This support is also available as a module called sunhme.o ( = code
which can be inserted in and removed from the running kernel
@@ -8539,8 +8939,8 @@ CONFIG_SUNLANCE
This driver supports the "le" interface present on all 32-bit Sparc
systems, on some older Ultra systems and as an Sbus option.
- This support is also available as a module called sunlance.o ( = code
- which can be inserted in and removed from the running kernel
+ This support is also available as a module called sunlance.o ( =
+ code which can be inserted in and removed from the running kernel
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
@@ -8620,8 +9020,10 @@ CONFIG_SKFP
- Netelligent 100 FDDI DAS UTP
- Netelligent 100 FDDI SAS UTP
- Netelligent 100 FDDI SAS Fibre MIC
+
Read Documentation/networking/skfp.txt for information about
the driver.
+
WARNING: this driver does currently not support 64 bit systems!
Questions concerning this driver can be addressed to:
linux@syskonnect.de
@@ -8631,14 +9033,6 @@ CONFIG_SKFP
say M here and read Documentation/modules.txt. This is recommended.
The module will be called skfp.o.
-Linux telephony support
-CONFIG_PHONE
- This option enable the kernel to manage telephony cards.
-
- There are very few supported cards at this moment.
-
- If unsure, say N.
-
HIgh Performance Parallel Interface support (EXPERIMENTAL)
CONFIG_HIPPI
HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
@@ -8712,7 +9106,7 @@ CONFIG_CD_NO_IDESCSI
read Documentation/modules.txt.
If you want to use any of these CDROM drivers, you also have to
- answer Y or M to "ISO 9660 CDROM file systems support" below (this
+ answer Y or M to "ISO 9660 CDROM file system support" below (this
answer will get "defaulted" for you if you enable any of the Linux
CDROM drivers).
@@ -8725,11 +9119,10 @@ CONFIG_CDU31A
time as described in Documentation/cdrom/cdu31a or fill in your
parameters into drivers/cdrom/cdu31a.c. Try "man bootparam" or
see the documentation of your boot loader (lilo or loadlin) about
- how to pass options to the kernel. The lilo procedure is also
- explained in the SCSI-HOWTO.
+ how to pass options to the kernel.
If you say Y here, you should also say Y or M to "ISO 9660 CDROM
- file systems support" below, because that's the file systems used on
+ file system support" below, because that's the file system used on
CDROMs.
This driver is also available as a module ( = code which can be
@@ -8751,7 +9144,7 @@ CONFIG_MCD
this. If you want that one, say N here.
If you say Y here, you should also say Y or M to "ISO 9660 CDROM
- file systems support" below, because that's the file systems used on
+ file system support" below, because that's the file system used on
CDROMs.
This driver is also available as a module ( = code which can be
@@ -8784,7 +9177,7 @@ CONFIG_MCDX
Documentation/cdrom/mcdx.
If you say Y here, you should also say Y or M to "ISO 9660 CDROM
- file systems support" below, because that's the file systems used on
+ file system support" below, because that's the file system used on
CDROMs.
This driver is also available as a module ( = code which can be
@@ -8822,7 +9215,7 @@ CONFIG_SBPCD
usable.
If you say Y here, you should also say Y or M to "ISO 9660 CDROM
- file systems support" below, because that's the file systems used on
+ file system support" below, because that's the file system used on
CDROMs.
This driver is also available as a module ( = code which can be
@@ -8835,7 +9228,7 @@ CONFIG_SBPCD2
Say Y here only if you have two CDROM controller cards of this type
(usually only if you have more than four drives). You should enter
the parameters for the second, third and fourth interface card into
- linux/include/linux/sbpcd.h before compiling the new kernel. Read
+ include/linux/sbpcd.h before compiling the new kernel. Read
the file Documentation/cdrom/sbpcd.
Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support
@@ -8847,7 +9240,7 @@ CONFIG_AZTCD
CDA269-031SE. Please read the file Documentation/cdrom/aztcd.
If you say Y here, you should also say Y or M to "ISO 9660 CDROM
- file systems support" below, because that's the file systems used on
+ file system support" below, because that's the file system used on
CDROMs.
This driver is also available as a module ( = code which can be
@@ -8872,8 +9265,8 @@ CONFIG_CDU535
Goldstar R420 CDROM support
CONFIG_GSCD
If this is your CDROM drive, say Y here. As described in the file
- linux/Documentation/cdrom/gscd, you might have to change a setting
- in the file linux/drivers/cdrom/gscd.h before compiling the
+ Documentation/cdrom/gscd, you might have to change a setting
+ in the file drivers/cdrom/gscd.h before compiling the
kernel. Please read the file Documentation/cdrom/gscd.
If you say Y here, you should also say Y or M to "ISO 9660 CDROM
@@ -8929,17 +9322,6 @@ CONFIG_SJCD
The module will be called sjcd.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-Soft configurable cdrom interface card support
-CONFIG_CDI_INIT
- If you want to include boot-time initialization of any cdrom
- interface card that is software configurable, say Y here. Currently
- only the ISP16/MAD16/Mozart sound cards with built-in cdrom
- interfaces are supported.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause this configure script to skip all
- the questions about these CDROM drives.
-
ISP16/MAD16/Mozart soft configurable cdrom interface support
CONFIG_ISP16_CDI
These are sound cards with built-in cdrom interfaces using the OPTi
@@ -8969,8 +9351,8 @@ CONFIG_USB
traditional PC serial port. The bus supplies power to peripherals
and allows for hot swapping. Up to 127 USB peripherals can be
connected to a single USB port in a tree structure. The USB port is
- the root of the tree, the peripherals are the leaves, and the inner
- nodes are special USB devices called hubs. Many newer PCs have USB
+ the root of the tree, the peripherals are the leaves and the inner
+ nodes are special USB devices called hubs. Many newer PC's have USB
ports and newer peripherals such as scanners, keyboards, mice,
modems, and printers support the USB protocol and can be connected
to the PC via those ports.
@@ -8986,6 +9368,12 @@ CONFIG_USB
The module will be called usbcore.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+USB verbose debug messages
+CONFIG_USB_DEBUG
+ Say Y here if you want the USB core drivers to produce a bunch of
+ debug messages to the system log. Select this if you are having a
+ problem with USB support and want to see more of what is going on.
+
UHCI (intel PIIX4, VIA, ...) support?
CONFIG_USB_UHCI
The Universal Host Controller Interface is a standard by Intel for
@@ -9061,17 +9449,37 @@ CONFIG_USB_KBD
USB keyboard and prefer to use the keyboard in its limited Boot
Protocol mode. This driver is much smaller than the HID one.
+ 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 usbkbd.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
+ If unsure, say N.
+
USB HIDBP Mouse support
CONFIG_USB_MOUSE
Say Y here if you don't want to use the generic HID driver for your
USB mouse and prefer to use the mouse in its limited Boot Protocol
mode. This driver is much smaller than the HID one.
+ 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 usbmouse.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
+ If unsure, say N.
+
Wacom Intuos/Graphire tablet support
CONFIG_USB_WACOM
- Say Y here if you want to use the USB version of the Wacom
- Intuos or Graphire tablet. Make sure you select Mouse and Event
- support as well.
+ Say Y here if you want to use the USB version of the Wacom Intuos or
+ Graphire tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ This driver 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 wacom.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
Logitech WingMan Force joystick support
CONFIG_USB_WMFORCE
@@ -9079,42 +9487,65 @@ CONFIG_USB_WMFORCE
on the USB port. No force-feedback support yet, but other than that,
it should work like a normal joystick.
+ This driver 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 wmforce.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
Keyboard support
CONFIG_INPUT_KEYBDEV
Say Y here if you want your USB HID keyboard to be able to serve as
a system keyboard.
+ This driver 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 keybdev.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
Mouse support
CONFIG_INPUT_MOUSEDEV
Say Y here if you want your USB HID mouse to be accessible as
- misc devices 32+ under /dev/, as an emulated PS/2 mouse.
+ misc devices 32+ under /dev/, as an emulated PS/2 mouse. That way,
+ all user space programs will be able to use your mouse.
+
+ If unsure, say Y.
+
+ This driver 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 mousedev.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
Mix all mice into one device
CONFIG_INPUT_MOUSEDEV_MIX
Say Y here if you want input from all your USB HID mice to be mixed
into one misc device. If you say N, you'll have a separate
- device for each your USB mouse.
+ device for each USB mouse.
Support for digitizers
CONFIG_INPUT_MOUSEDEV_DIGITIZER
- Use this if you have a digitizer that doesn't emulate a mouse
+ Say Y here if you have a digitizer that doesn't emulate a mouse
itself, and want to use it as a mouse.
Horizontal screen resolution
CONFIG_INPUT_MOUSEDEV_SCREEN_X
- For the mouse emulation to be correct, the mousedev driver needs
- to know the screen resolution you are using (in X).
+ For the mouse emulation to be correct, the mousedev driver needs to
+ know the screen resolution you are using (in the X window system).
Vertical screen resolution
CONFIG_INPUT_MOUSEDEV_SCREEN_Y
- For the mouse emulation to be correct, the mousedev driver needs
- to know the screen resolution you are using (in X).
+ For the mouse emulation to be correct, the mousedev driver needs to
+ know the screen resolution you are using (in the X window system).
Joystick support
CONFIG_INPUT_JOYDEV
Say Y here if you want your USB HID joystick or gamepad to be
- accessible as /dev/js device. You can't use a normal joystick
- if you select this.
+ accessible as a /dev/js device. You can't use a normal (non-USB)
+ joystick if you say Y here.
+
+ This driver 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 joydev.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
Event interface support
CONFIG_INPUT_EVDEV
@@ -9124,18 +9555,18 @@ CONFIG_INPUT_EVDEV
USB Scanner support
CONFIG_USB_SCANNER
- Say Y here if you want to connect a USB scanner to your
- computer's USB port. Please read Documentation/usb/scanner.txt
- and Documentation/usb/scanner-hp-sane.txt for more information.
+ Say Y here if you want to connect a USB scanner to your computer's
+ USB port. Please read Documentation/usb/scanner.txt and
+ Documentation/usb/scanner-hp-sane.txt for more information.
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 hp_scanner.o. If you want to compile it as
+ The module will be called scanner.o. If you want to compile it as
a module, say M here and read Documentation/modules.txt.
USB Audio support
CONFIG_USB_AUDIO
- Say Y here if you want to connect USB audio equipment such as
+ Say Y here if you want to connect UAB audio equipment such as
speakers to your computer's USB port.
This code is also available as a module ( = code which can be
@@ -9155,11 +9586,16 @@ CONFIG_USB_ACM
USB Serial converter support
CONFIG_USB_SERIAL
- Say Y here if you want to connect a Connect Tech WhiteHEAT
- multi-port USB to serial converter; a FTDI or Keyspan single port
- USB to serial converter; or a Handspring Visor. Please read
- Documentation/usb/usb-serial.txt for more information.
-
+ Say Y here if you have a USB device that provides normal serial
+ ports, and you want to connect it to your USB bus. Supported devices
+ are the Tech WhiteHEAT multi-port USB to serial converter, and the
+ FTDI or Keyspan single port USB to serial converter Handspring
+ Visor. In addition to saying Y here, you need to say Y to the driver
+ for your specific hardware below. Some other devices may also be
+ used if you say Y to "USB Generic Serial Driver", below.
+
+ Please read Documentation/usb/usb-serial.txt for more information.
+
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 usb-serial.o. If you want to compile it
@@ -9167,10 +9603,11 @@ CONFIG_USB_SERIAL
USB Generic Serial Driver
CONFIG_USB_SERIAL_GENERIC
- Say Y here if you want to use the generic USB serial driver.
- Please read Documentation/usb/usb-serial.txt for more information
- on using this driver. It is recommended that the USB Serial
- Driver be compiled as a module for this driver to be used properly.
+ Say Y here if you want to use the generic USB serial driver. Please
+ read Documentation/usb/usb-serial.txt for more information on using
+ this driver. It is recommended that the "USB Serial converter
+ support" be compiled as a module for this driver to be used
+ properly.
USB ConnectTech WhiteHEAT Serial Driver
CONFIG_USB_SERIAL_WHITEHEAT
@@ -9186,7 +9623,10 @@ CONFIG_USB_SERIAL_VISOR
USB FTDI Single Port Serial Driver
CONFIG_USB_SERIAL_FTDI_SIO
Say Y here if you want to use a FTDI SIO single port USB to serial
- converter device.
+ converter device. The implementation I have is called the USC-1000
+
+ See http://reality.sgi.com/bryder_wellington/ftdi_sio for more information
+ on this driver and the device
USB FTDI Single Port Serial Driver
CONFIG_USB_SERIAL_KEYSPAN_PDA
@@ -9203,26 +9643,11 @@ CONFIG_USB_PRINTER
The module will be called printer.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-USB CPiA Camera support
-CONFIG_USB_CPIA
- Say Y here if you want to connect this type of camera to your
- computer's USB port.
-
- This driver uses the Video For Linux API. You must enable
- (Y or M in config) Video For Linux (under Character Devices)
- to use this driver. Information on this API and pointers to
- "v4l" programs may be found on the WWW at
- http://roadrunner.swansea.uk.linux.org/v4l.shtml .
-
- 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 cpia.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
-
USB IBM (Xirlink) C-It Camera support
CONFIG_USB_IBMCAM
- Say Y here if you want to connect this type of camera to your
- computer's USB port.
+ Say Y here if you want to connect a IBM "C-It" camera, also known as
+ "Xirlink PC Camera" to your computer's USB port. For more
+ information, read Documentation/usb/ibmcam.txt.
This driver uses the Video For Linux API. You must enable
(Y or M in config) Video For Linux (under Character Devices)
@@ -9243,11 +9668,10 @@ CONFIG_USB_OV511
computer's USB port. See Documentation/usb/ov511.txt for more
information and for a list of supported cameras.
- This driver uses the Video For Linux API. You must enable
- (Y or M in config) Video For Linux (under Character Devices)
- to use this driver. Information on this API and pointers to
- "v4l" programs may be found on the WWW at
- http://roadrunner.swansea.uk.linux.org/v4l.shtml .
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" (under Character Devices) to use this driver.
+ Information on this API and pointers to "v4l" programs may be found
+ on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml .
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -9256,11 +9680,18 @@ CONFIG_USB_OV511
USB ADMtek Pegasus-based ethernet device support
CONFIG_USB_PEGASUS
- Say Y if you want to use your USB ethernet device. Note that
- the code is still experimental. If you have devices with vendor
- IDs other than ADMtek's, you should change/add them in the
- driver code and send a message to me (petkan@spct.net) for
- update.
+ Say Y if you want to use your USB ethernet device. Supported
+ cards until now are:
+ Accton 10/100
+ Billington USB-100
+ Corega FEter USB-TX
+ MELCO/BUFFALO LUA-TX
+ D-Link DSB-650TX, DSB-650TX-PNA
+ Linksys USB100TX
+ SNC 202
+ If you have devices with vendor IDs other than noted above
+ you should add them in the driver code and send a message
+ to me (petkan@spct.net) for update.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -9285,7 +9716,7 @@ 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
+ To use it create a devicenode with mknod /dev/mustek c 180 32 and
configure it in your software.
This code is also available as a module ( = code which can be
@@ -9293,7 +9724,6 @@ CONFIG_USB_MDC800
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
@@ -9312,8 +9742,9 @@ CONFIG_USB_STORAGE_DEBUG
USS720 parport driver
CONFIG_USB_USS720
This driver is for USB parallel port adapters that use the Lucent
- Technologies USS-720 chip. These adapters provide USB compatibility
- to peripherals designed with parallel port interfaces.
+ Technologies USS-720 chip. These cables are plugged into your USB
+ port and provide USB compatibility to peripherals designed with
+ parallel port interfaces.
The chip has two modes: automatic mode and manual mode. In automatic
mode, it looks to the computer like a standard USB printer. Only
@@ -9338,38 +9769,53 @@ CONFIG_USB_USS720
USB device file system
CONFIG_USB_DEVICEFS
- This file system implements a "devices" file, that lists
- the currently connected to your USB busses, a "drivers" file
- that lists the USB kernel client drivers currently loaded,
- and for every connected device a file named "xxx/yyy", where
- xxx is the bus number and yyy the device number, that can be used
- by userspace drivers to talk to the device.
+ If you say Y here (and to "/proc file system support" below), you
+ will get a file /proc/usb/devices which lists the devices currently
+ connected to your USB busses, a file /proc/usb/drivers file which
+ lists the USB kernel client drivers currently loaded, and for every
+ connected device a file named "/proc/usb/xxx/yyy", where xxx is the
+ bus number and yyy the device number; the latter files can be used
+ by userspace drivers to talk to the device. These files are
+ "virtual", meaning they are generated on the fly and not stored on
+ the hard drive.
+
+ For the format of the /proc/usb/ files, please read
+ Documentation/usb/proc_usb_info.txt.
+
+ Please note that this code is completely unrelated to devfs, the
+ "/dev file system support".
Most users want to say Y here.
DABUSB driver
CONFIG_USB_DABUSB
- A Digital Audio Broadcasting (DAB) Receiver for USB and Linux brought
- to you by the DAB-Team (http://dab.in.tum.de).
- This driver can be taken as an example for URB-based bulk, control, and
- isochronous transactions.
+ A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
+ brought to you by the DAB-Team (http://dab.in.tum.de). This driver
+ can be taken as an example for URB-based bulk, control, and
+ isochronous transactions. URB's are explained in
+ Documentation/usb/URB.txt.
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 dabusb.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-
+
PLUSB driver
CONFIG_USB_PLUSB
- A driver for the Prolific PL-2302 USB-to-USB network device. This 'USB
- cable' connects two hosts via a point-to-point network with bandwidth of
- 5 Mbit/s. Configure this driver after connecting the USB cable via
- ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2
- (and vice versa on the other host).
+ A driver for the Prolific PL-2302 USB-to-USB network device. This
+ 'USB cable' connects two hosts via a point-to-point network with
+ bandwidth of 5 Mbit/s. Configure this driver after connecting the
+ USB cable via ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 (and
+ vice versa on the other host).
+
+ 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 plusb.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
USB Diamond Rio500 support
CONFIG_USB_RIO500
- Say Y here if you want to connect a USB rio500 to your
+ Say Y here if you want to connect a USB Rio500 mp3 player to your
computer's USB port. Please read Documentation/usb/rio.txt
for more information.
@@ -9378,7 +9824,7 @@ CONFIG_USB_RIO500
The module will be called rio500.o. If you want to compile it as
a module, say M here and read Documentation/modules.txt.
-D-Link DSB-R100 FM radio upport
+D-Link DSB-R100 FM radio support
CONFIG_USB_DSBR
Say Y here if you want to connect this type of radio to your
computer's USB port. Note that the audio is not digital, and
@@ -9396,28 +9842,22 @@ CONFIG_USB_DSBR
The module will be called dsbr100.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-ACPI support
-CONFIG_ACPI
- Advanced Configuration and Power Interface (ACPI) is an interface
- specification to support power management of peripherals. If your
- system supports it, say Y here.
-
Minix fs support
CONFIG_MINIX_FS
Minix is a simple operating system used in many classes about OS's.
The minix file system (method to organize files on a hard disk
partition or a floppy disk) was the original file system for Linux,
but has been superseded by the second extended file system ext2fs.
- You don't want to use the minix file system on your hard disk because
- of certain built-in restrictions, but it is sometimes found on older
- Linux floppy disks. This option will enlarge your kernel by about
- 28 kB. If unsure, say N.
+ You don't want to use the minix file system on your hard disk
+ because of certain built-in restrictions, but it is sometimes found
+ on older Linux floppy disks. This option will enlarge your kernel by
+ about 28 KB. If unsure, say N.
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 minix.o. Note that the file system of your root partition (the
- one containing the directory /) cannot be compiled as a module.
+ called minix.o. Note that the file system of your root partition
+ (the one containing the directory /) cannot be compiled as a module.
Second extended fs support
CONFIG_EXT2_FS
@@ -9425,11 +9865,11 @@ CONFIG_EXT2_FS
files on a storage device) for hard disks.
You want to say Y here, unless you intend to use Linux exclusively
- from inside a DOS partition using the umsdos file system. The
+ from inside a DOS partition using the UMSDOS file system. The
advantage of the latter is that you can get away without
repartitioning your hard drive (which often implies backing
everything up and restoring afterwards); the disadvantage is that
- Linux becomes susceptible to DOS viruses and that umsdos is somewhat
+ Linux becomes susceptible to DOS viruses and that UMSDOS is somewhat
slower than ext2fs. Even if you want to run Linux in this fashion,
it might be a good idea to have ext2fs around: it enables you to
read more floppy disks and facilitates the transition to a *real*
@@ -9437,7 +9877,7 @@ CONFIG_EXT2_FS
ext2fs is a diskless Linux box which mounts all files over the
network using NFS (in this case it's sufficient to say Y to "NFS
file system support" below). Saying Y here will enlarge your kernel
- by about 44 kB.
+ by about 44 KB.
The Ext2fs-Undeletion mini-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto , gives information about
@@ -9451,9 +9891,10 @@ CONFIG_EXT2_FS
command line tool package (available via FTP (user: anonymous) from
ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2 ) and from
within Windows NT using the ext2nt command line tool package from
- ftp://metalab.unc.edu/pub/Linux/utils/dos . Explore2fs is a graphical
- explorer for ext2fs partitions which runs on Windows 95 and Windows
- NT and includes experimental write support; it is available from
+ ftp://metalab.unc.edu/pub/Linux/utils/dos . Explore2fs is a
+ graphical explorer for ext2fs partitions which runs on Windows 95
+ and Windows NT and includes experimental write support; it is
+ available from
http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm .
If you want to compile this file system as a module ( = code which
@@ -9467,31 +9908,50 @@ CONFIG_EXT2_FS
BFS file system support (EXPERIMENTAL)
CONFIG_BFS_FS
Boot File System (BFS) is a file system used under SCO UnixWare to
- allow bootloader access the kernel image and other important files
- during the boot process. It is usually mounted under /stand and
- corresponds to the slice marked as "STAND" in the UnixWare
- partition. This is useful if you want to access files on your /stand
- slice from Linux. More information on this file system can be found in
- Documentation/filesystems/bfs.txt file. If you do not know what it is,
- say N.
+ allow the bootloader access to the kernel image and other important
+ files during the boot process. It is usually mounted under /stand
+ and corresponds to the slice marked as "STAND" in the UnixWare
+ partition. You should say Y if you want to read or write
+ the files on your /stand slice from within Linux. You then also
+ need to say Y to "UnixWare slices support", below. More information
+ about the BFS file system is contained in the file
+ Documentation/filesystems/bfs.txt.
+
+ If you don't know what this is about, say N.
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 bfs.o. Note that the file system of your root partition (the
one containing the directory /) cannot be compiled as a module.
-
+
+Compressed ROM file system support
+CONFIG_CRAMFS
+ Saying Y here includes 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), and doesn't support
+ 16/32 bits uid/gid, hard links and timestamps.
+
+ 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.
+
ISO 9660 CDROM file system support
CONFIG_ISO9660_FS
This is the standard file system used on CDROMs. It was previously
- known as "High Sierra File System" and is called "hsfs" on other Unix
- systems. The so-called Rock-Ridge extensions which allow for long
- Unix filenames and symbolic links are also supported by this driver.
- If you have a CDROM drive and want to do more with it than just
- listen to audio CDs and watch its LEDs, say Y (and read
+ known as "High Sierra File System" and is called "hsfs" on other
+ Unix systems. The so-called Rock-Ridge extensions which allow for
+ long Unix filenames and symbolic links are also supported by this
+ driver. If you have a CDROM drive and want to do more with it than
+ just listen to audio CDs and watch its LEDs, say Y (and read
Documentation/filesystems/isofs.txt and the CDROM-HOWTO, available
- from http://www.linuxdoc.org/docs.html#howto ), thereby
- enlarging your kernel by about 27 KB; otherwise say N.
+ from http://www.linuxdoc.org/docs.html#howto ), thereby enlarging
+ your kernel by about 27 KB; otherwise say N.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -9507,17 +9967,21 @@ CONFIG_JOLIET
http://www.unicode.org for more information). Say Y here if you want
to be able to read Joliet CDROMs under Linux.
-UDF file system support (read only)
+UDF File System support (read only)
CONFIG_UDF_FS
- This is the new file system used by some CDROMS and DVD drivers. Say
- Y if you intend to mount DVD discs or CDRW's written in packet mode,
- or if written to by other UDF utilities, such as DirectCD. Please
- read Documentation/filesystems/udf.txt.
-
- This file system support is also available as a module ( = code which
- can be inserted in and removed from the running kernel whenever you
- want). The module is called udf.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
+ This is the new file system used on some CDROMs and DVDs. Say Y if
+ you intend to mount DVD discs or CDRW's written in packet mode, or
+ if written to by other UDF utilities, such as DirectCD. This UDF
+ file system support is read-only. If you want to write to UDF
+ file systems on some media, you need to say Y to "UDF read-write
+ support" below in addition. Please read
+ Documentation/filesystems/udf.txt.
+
+ This file system support is also available as a module ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). The module is called udf.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
If unsure, say N.
@@ -9525,7 +9989,7 @@ UDF write support (DANGEROUS)
CONFIG_UDF_RW
Say Y if you want to test write support for UDF file systems.
Due to lack of support for writing to CDR/CDRW's, this option
- is only supported for Hard Discs, DVD-RAM, and loopback files.
+ is only supported for hard discs, DVD-RAM, and loopback files.
DOS FAT fs support
CONFIG_FAT_FS
@@ -9537,18 +10001,24 @@ CONFIG_FAT_FS
files on them, i.e. MSDOS files will look and behave just like all
other Unix files.
- This FAT support is not a file system in itself, it only provides the
- foundation for the other file systems. You will have to say Y or M to
- at least one of "msdos fs support" or "vfat fs support" in order to
- make use of it.
+ This FAT support is not a file system in itself, it only provides
+ the foundation for the other file systems. You will have to say Y or
+ M to at least one of "MSDOS fs support" or "VFAT fs support" in
+ order to make use of it.
Another way to read and write MSDOS floppies and hard drive
partitions from within Linux (but not transparently) is with the
- mtools ("man mtools") program suite. This doesn't require the FAT
- file system support.
+ mtools ("man mtools") program suite. You don't need to say Y here in
+ order to do that.
+ If you need to move large files on floppies between a DOS and a
+ Linux box, say Y here, mount the floppy under Linux with an MSDOS
+ file system and use GNU tar's M option. GNU tar is a program
+ available for Unix and DOS ("man tar" or "info tar").
+
It is now also becoming possible to read and write compressed FAT
- file systems; read Documentation/filesystems/fat_cvf.txt for details.
+ file systems; read Documentation/filesystems/fat_cvf.txt for
+ details.
The FAT support will enlarge your kernel by about 37 KB. If unsure,
say Y.
@@ -9557,11 +10027,11 @@ CONFIG_FAT_FS
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 fat.o. Note that if you compile the FAT support as a
- module, you cannot compile any of the FAT-based file systems into the
- kernel -- they will have to be modules as well. The file system of
- your root partition (the one containing the directory /) cannot be a
- module, so don't say M here if you intend to use UMSDOS as your root
- file system.
+ module, you cannot compile any of the FAT-based file systems into
+ the kernel -- they will have to be modules as well. The file system
+ of your root partition (the one containing the directory /) cannot
+ be a module, so don't say M here if you intend to use UMSDOS as your
+ root file system.
MSDOS fs support
CONFIG_MSDOS_FS
@@ -9576,36 +10046,37 @@ CONFIG_MSDOS_FS
transparent, i.e. the MSDOS files look and behave just like all
other Unix files.
- If you want to use umsdos, the Unix-like file system on top of DOS,
- which allows you to run Linux from within a DOS partition without
- repartitioning, you'll have to say Y or M here.
+ If you want to use UMSDOS, the Unix-like file system on top of a
+ DOS file system, which allows you to run Linux from within a DOS
+ partition without repartitioning, you'll have to say Y or M here.
If you have Windows 95 or Windows NT installed on your MSDOS
- partitions, you should use the VFAT file system (say Y to "vfat fs
+ partitions, you should use the VFAT file system (say Y to "VFAT fs
support" below), or you will not be able to see the long filenames
generated by Windows 95 / Windows NT.
This option will enlarge your kernel by about 7 KB. If unsure,
- answer Y. This will only work if you said Y to "fat fs support" as
- well. If you want to compile this as a module however ( = 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 msdos.o.
+ answer Y. This will only work if you said Y to "DOS FAT fs support"
+ as well. If you want to compile this as a module however ( = 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 msdos.o.
VFAT (Windows-95) fs support
CONFIG_VFAT_FS
This option provides support for normal Windows file systems with
long filenames. That includes non-compressed FAT-based file systems
- used by Windows 95, Windows 98, Windows NT 4.0, and mtools.
+ used by Windows 95, Windows 98, Windows NT 4.0, and the Unix
+ programs from the mtools package.
You cannot use the VFAT file system for your Linux root partition
(the one containing the directory /); use UMSDOS instead if you
want to run Linux from within a DOS partition (i.e. say Y to
- "umsdos: Unix like fs on top of std MSDOS fs", below).
+ "UMSDOS: Unix like fs on top of std MSDOS fs", below).
The VFAT support enlarges your kernel by about 10 KB and it only
- works if you said Y to the "fat fs support" above. Please read the
- file Documentation/filesystems/vfat.txt for details. If unsure,
+ works if you said Y to the "DOS FAT fs support" above. Please read
+ the file Documentation/filesystems/vfat.txt for details. If unsure,
say Y.
If you want to compile this as a module ( = code which can be
@@ -9613,23 +10084,6 @@ 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
@@ -9642,20 +10096,20 @@ CONFIG_UMSDOS_FS
is to write files with long unix filenames to MSDOS floppies; it
also allows Unix-style soft-links and owner/permissions of files on
MSDOS floppies. You will need a program called umssync in order to
- make use of umsdos; read Documentation/filesystems/umsdos.txt.
+ make use of UMSDOS; read Documentation/filesystems/umsdos.txt.
To get utilities for initializing/checking UMSDOS file system, or
- latest patches and/or information, visit UMSDOS homepage at
+ latest patches and/or information, visit the UMSDOS home page at
http://www.voyager.hr/~mnalis/umsdos/ .
This option enlarges your kernel by about 28 KB and it only works if
- you said Y to both "fat fs support" and "msdos fs support" above. 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
- umsdos.o. Note that the file system of your root partition (the one
- containing the directory /) cannot be a module, so saying M could be
- dangerous. If unsure, say N.
+ you said Y to both "DOS FAT fs support" and "MSDOS fs support"
+ above. 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 umsdos.o. Note that the file system of your root partition
+ (the one containing the directory /) cannot be a module, so saying M
+ could be dangerous. If unsure, say N.
/proc file system support
CONFIG_PROC_FS
@@ -9674,30 +10128,35 @@ CONFIG_PROC_FS
The /proc file system is explained in the file
Documentation/filesystems/proc.txt and on the proc(5) manpage ("man
- 5 proc").
+ 5 proc"). You can also use the program procinfo to display some
+ information about your system gathered from the /proc file system.
This option will enlarge your kernel by about 67 KB. Several
programs depend on this, so everyone should say Y here.
/dev file system support (EXPERIMENTAL)
CONFIG_DEVFS_FS
- This is another virtual file system (like /proc) which provides the
- file system interface to device drivers, normally found in /dev.
- Devfs does not depend on major and minor number allocations. Device
- drivers register entries in /dev which appear automagically. Without
- devfs you need to populate /dev with hundreds, even thousands of
- inodes.
+ This is support for devfs, a virtual file system (like /proc) which
+ provides the file system interface to device drivers, normally found
+ in /dev. Devfs does not depend on major and minor number
+ allocations. Device drivers register entries in /dev which then
+ appear automatically, which means that the system administrator does
+ not have to create character and block special device files in the
+ /dev directory using the mknod command anymore.
+
This is work in progress. If you want to use this you *must* read
- Documentation/filesystems/devfs/README
- In particular, make sure you install devfsd. If you don't, expect to
- spend time patching broken code and updating configuration files.
+ the material in Documentation/filesystems/devfs/, especially the
+ file README there.
+
+ If unsure, say N.
Debug devfs
CONFIG_DEVFS_DEBUG
- This option appears if you have CONFIG_DEVFS_FS enabled. Setting
- this to 'Y' enables devfs debugging output. See the file
+ If you say Y here, then the /dev file system code will generate
+ debugging messages. See the file
Documentation/filesystems/devfs/boot-options for more details.
- The default is 'N'.
+
+ If unsure, say N.
NFS file system support
CONFIG_NFS_FS
@@ -9710,7 +10169,7 @@ CONFIG_NFS_FS
programs nfsd and mountd (but does not need to have NFS file system
support enabled in its kernel). NFS is explained in the Network
Administrator's Guide, available from
- http://metalab.unc.edu/mdw/linux.html#guide , on its man page: "man
+ http://www.linuxdoc.org/docs.html#guide , on its man page: "man
nfs", and in the NFS-HOWTO.
A superior but less widely used alternative to NFS is provided by
@@ -9761,35 +10220,34 @@ CONFIG_NFSD
section.
Please read the NFS-HOWTO, available from
- http://www.linuxdoc.org/HOWTO/NFS-HOWTO.html .
-
+ http://www.linuxdoc.org/docs.html#howto .
The NFS server is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module is called nfsd.o. If you want to compile it as a module,
say M here and read Documentation/modules.txt. If unsure, say N.
-Provide NFSv3 server support (EXPERIMENTAL)
+Provide NFSv3 server support
CONFIG_NFSD_V3
- If you would like to include the NFSv3 server was well as the NFSv2
- server, say Y here. File locking, via the NLMv4 protocol, is also
- supported. If unsure, say N.
+ If you would like to include the NFSv3 server as well as the NFSv2
+ server, say Y here. In unsure, say Y.
OS/2 HPFS file system support
CONFIG_HPFS_FS
OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
is the file system used for organizing files on OS/2 hard disk
- partitions. Say Y if you want to be able to read files from an OS/2
- HPFS partition of your hard drive. OS/2 floppies however are in
- regular MSDOS format, so you don't need this option in order to be
- able to read them. Read Documentation/filesystems/hpfs.txt.
+ partitions. Say Y if you want to be able to read files from and
+ write files to an OS/2 HPFS partition on your hard drive. OS/2
+ floppies however are in regular MSDOS format, so you don't need this
+ option in order to be able to read them. Read
+ Documentation/filesystems/hpfs.txt.
This file system is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module is called hpfs.o. If you want to compile it as a module,
say M here and read Documentation/modules.txt. If unsure, say N.
-NTFS file system support (read only)
+NTFS support (read only)
CONFIG_NTFS_FS
NTFS is the file system of Microsoft Windows NT. Say Y if you want
to get read access to files on NTFS partitions of your hard drive.
@@ -9804,11 +10262,13 @@ CONFIG_NTFS_FS
NTFS write support (DANGEROUS)
CONFIG_NTFS_RW
- If you say Y here, you will (hopefully) be able to write to NTFS
- file systems as well as read from them. The read-write support
- in NTFS is far from being complete and is not well tested. If you
+ If you say Y here, you will (maybe) be able to write to NTFS file
+ systems as well as read from them. The read-write support in
+ NTFS is far from being complete and is not well tested. If you
enable this, back up your NTFS volume first since it may get
- damaged.
+ damaged. Also, make sure to run chkdsk from within Microsoft
+ Windows NT after having performed any writes to a NTFS partition
+ from Linux to detect any problems as early as possible.
If unsure, say N.
@@ -9816,7 +10276,8 @@ System V and Coherent file system support (read only)
CONFIG_SYSV_FS
SCO, Xenix and Coherent are commercial Unix systems for Intel
machines. Saying Y here would allow you to read from their floppies
- and hard disk partitions.
+ and hard disk partitions. If you also want to write to these media,
+ say Y to "SYSV file system write support" below.
If you have floppies or hard disk partitions like that, it is likely
that they contain binaries from those other Unix systems; in order
@@ -9837,7 +10298,7 @@ CONFIG_SYSV_FS
tar" or preferably "info tar"). Note also that this option has
nothing whatsoever to do with the option "System V IPC". Read about
the System V file system in Documentation/filesystems/sysv-fs.txt.
- Saying Y here will enlarge your kernel by about 27 kB.
+ Saying Y here will enlarge your kernel by about 27 KB.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -9848,12 +10309,12 @@ CONFIG_SYSV_FS
SYSV file system write support (DANGEROUS)
CONFIG_SYSV_FS_WRITE
- If you say Y here, you will (hopefully) be able to write to System V
- and Coherent file systems as well as read from them. The read-write
- support in SYSV is not well tested yet. If you enable this, back up
- your SYSV/Coherent volumes first since they may get damaged.
+ If you say Y here, you will be able to write to hard drive
+ partitions and floppy disks which carry a SYSV file system used the
+ commercial Unixes SCO, Xenix and Coherent.
- If unsure, say N.
+ This support is experimental and you may destroy your data. If
+ unsure, say N.
Amiga FFS file system support
CONFIG_AFFS_FS
@@ -9883,10 +10344,11 @@ CONFIG_HFS_FS
Please read fs/hfs/HFS.txt to learn about the available mount
options.
- This file system support is also available as a module ( = code which
- can be inserted in and removed from the running kernel whenever you
- want). The module is called hfs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
+ This file system support is also available as a module ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). The module is called hfs.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
ROM file system support
CONFIG_ROMFS_FS
@@ -9895,10 +10357,11 @@ CONFIG_ROMFS_FS
other read-only media as well. Read
Documentation/filesystems/romfs.txt for details.
- This file system support is also available as a module ( = code which
- can be inserted in and removed from the running kernel whenever you
- want). The module is called romfs.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
+ This file system support is also available as a module ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). The module is called romfs.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
If you don't know whether you need it, then you don't need it:
answer N.
@@ -9907,13 +10370,14 @@ QNX4 file system support (read only) (EXPERIMENTAL)
CONFIG_QNX4FS_FS
This is the file system used by the operating system QNX 4. Say Y if
you intend to mount QNX hard disks or floppies. Unless you say Y to
- "QNX4FS write support" below, you will only be able to read
+ "QNX4FS read-write support" below, you will only be able to read
these file systems.
- This file system support is also available as a module ( = code which
- can be inserted in and removed from the running kernel whenever you
- want). The module is called qnx4.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
+ This file system support is also available as a module ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). The module is called qnx4.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
If you don't know whether you need it, then you don't need it:
answer N.
@@ -9933,6 +10397,10 @@ CONFIG_AUTOFS_FS
ftp://ftp.kernel.org/pub/linux/daemons/autofs ; you also want to
answer Y to "NFS file system support", below.
+ If you want to use the newer version of the automounter with more
+ features, say N here and say Y to "Kernel automounter v4 support",
+ below.
+
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
@@ -9941,10 +10409,7 @@ CONFIG_AUTOFS_FS
If you are not a part of a fairly large, distributed network, you
probably do not need an automounter, and can say N here.
- If you want to use the newer version of autofs with more features,
- say N here and select automounter v4.
-
-Kernel automounter version 4 support (also supports v3)
+Kernel automounter v4 support
CONFIG_AUTOFS4_FS
The automounter is a tool to automatically mount remote file systems
on demand. This implementation is partially kernel-based to reduce
@@ -9961,15 +10426,16 @@ CONFIG_AUTOFS4_FS
called autofs4.o. You will need to add "alias autofs autofs4" to
your modules configuration file.
- If you are not a part of a fairly large, distributed network or don't
- have a laptop which needs to dynamically reconfigure to the local
- network, you probably do not need an automounter, and can say N here.
+ If you are not a part of a fairly large, distributed network or
+ don't have a laptop which needs to dynamically reconfigure to the
+ local network, you probably do not need an automounter, and can say
+ N here.
-EFS file system support (read only) (EXPERIMENTAL)
+EFS file system support (read-only) (EXPERIMENTAL)
CONFIG_EFS_FS
- EFS is an older file system used for non-ISO9660 CDROMs and hard disk
- partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses
- the XFS file system for hard disk partitions however).
+ EFS is an older file system used for non-ISO9660 CDROMs and hard
+ disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer
+ uses the XFS file system for hard disk partitions however).
This implementation only offers read-only access. If you don't know
what all this is about, it's safe to say N. For more information
@@ -9980,12 +10446,7 @@ CONFIG_EFS_FS
whenever you want), say M here and read Documentation/modules.txt.
The module will be called efs.o.
-SGI disklabel support
-CONFIG_SGI_DISKLABEL
- Say Y to this only if you plan on mounting disks with SGI
- disklabels. This is not required to mount EFS-format CDROMs.
-
-UFS file system support (read only)
+UFS file system support (read-only)
CONFIG_UFS_FS
BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
OpenBSD and NeXTstep) use a file system called UFS. Some System V
@@ -10028,7 +10489,7 @@ 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.
+ the questions about foreign partitioning schemes.
If unsure, say N.
@@ -10084,13 +10545,14 @@ CONFIG_SGI_PARTITION
Say Y here if you would like to be able to read the hard disk
partition table format used by SGI machines.
-ADFS file system support (read only) (EXPERIMENTAL)
+ADFS file system support (EXPERIMENTAL)
CONFIG_ADFS_FS
The Acorn Disc Filing System is the standard file system of the
RiscOS operating system which runs on Acorn's ARM-based Risc PC
systems and the Acorn Archimedes range of machines. If you say Y
here, Linux will be able to read from ADFS partitions on hard drives
- and from ADFS-formatted floppy discs.
+ and from ADFS-formatted floppy discs. If you also want to be able to
+ write to those devices, say Y to "ADFS write support" below.
The ADFS partition should be the first partition (i.e.,
/dev/[hs]d?1) on each of your drives. Please read the file
@@ -10103,6 +10565,12 @@ CONFIG_ADFS_FS
If unsure, say N.
+ADFS write support (DANGEROUS)
+CONFIG_ADFS_FS_RW
+ If you say Y here, you will be able to write to ADFS partitions on
+ hard drives and ADFS-formatted floppy disks. This is experimental
+ codes, so if you're unsure, say N.
+
/dev/pts file system for Unix98 PTYs
CONFIG_DEVPTS_FS
You should say Y here if you said Y to "Unix98 PTY support" above.
@@ -10119,7 +10587,8 @@ CONFIG_DEVPTS_FS
mode of operation; you also need client programs that use the Unix98
API.
- Note that CONFIG_DEVFS_FS is a more general facility.
+ Note that the experimental "/dev file system support"
+ (CONFIG_DEVFS_FS) is a more general facility.
UnixWare slices support (EXPERIMENTAL)
CONFIG_UNIXWARE_DISKLABEL
@@ -10127,9 +10596,8 @@ CONFIG_UNIXWARE_DISKLABEL
partition (VTOC - Virtual Table of Contents). Its format is
incompatible with all other OSes. Saying Y here allows you to read
VTOC and further mount UnixWare partitions read-only from within
- Linux if you have also said Y to "UFS file system support", "System
- V and Coherent file system support" or "BFS file system support",
- above.
+ Linux if you have also said Y to "UFS file system support" or
+ "System V and Coherent file system support", above.
This is mainly used to carry data from a UnixWare box to your
Linux box via a removable medium like magneto-optical, ZIP or
@@ -10178,9 +10646,9 @@ CONFIG_CODA_FS
If you say Y here, your Linux box will be able to act as a Coda
*client*. You will need user level code as well, both for the client
- and server. Servers are currently user level, i.e. need no kernel
- support. Please read Documentation/filesystems/coda.txt and check
- out the Coda home page http://www.coda.cs.cmu.edu .
+ and server. Servers are currently user level, i.e. they need no
+ kernel support. Please read Documentation/filesystems/coda.txt and
+ check out the Coda home page http://www.coda.cs.cmu.edu .
If you want to compile the coda client support as a module ( = code
which can be inserted in and removed from the running kernel
@@ -10266,7 +10734,7 @@ CONFIG_NCPFS_MOUNT_SUBDIR
To utilize this feature you must use ncpfs-2.0.12 or newer.
-NDS interserver authentication domains
+NDS authentication support
CONFIG_NCPFS_NDS_DOMAINS
This allows storing NDS private keys in kernel space where they
can be used to authenticate another server as interserver NDS
@@ -10295,7 +10763,7 @@ CONFIG_NCPFS_EXTRAS
nls codepage 437
CONFIG_NLS_CODEPAGE_437
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored
in so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10306,7 +10774,7 @@ CONFIG_NLS_CODEPAGE_437
nls codepage 737
CONFIG_NLS_CODEPAGE_737
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored
in so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10317,7 +10785,7 @@ CONFIG_NLS_CODEPAGE_737
nls codepage 775
CONFIG_NLS_CODEPAGE_775
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored
in so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10328,7 +10796,7 @@ CONFIG_NLS_CODEPAGE_775
nls codepage 850
CONFIG_NLS_CODEPAGE_850
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10343,7 +10811,7 @@ CONFIG_NLS_CODEPAGE_850
nls codepage 852
CONFIG_NLS_CODEPAGE_852
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10357,7 +10825,7 @@ CONFIG_NLS_CODEPAGE_852
nls codepage 855
CONFIG_NLS_CODEPAGE_855
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10367,7 +10835,7 @@ CONFIG_NLS_CODEPAGE_855
nls codepage 857
CONFIG_NLS_CODEPAGE_857
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10377,7 +10845,7 @@ CONFIG_NLS_CODEPAGE_857
nls codepage 860
CONFIG_NLS_CODEPAGE_860
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10387,7 +10855,7 @@ CONFIG_NLS_CODEPAGE_860
nls codepage 861
CONFIG_NLS_CODEPAGE_861
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10397,7 +10865,7 @@ CONFIG_NLS_CODEPAGE_861
nls codepage 862
CONFIG_NLS_CODEPAGE_862
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10407,7 +10875,7 @@ CONFIG_NLS_CODEPAGE_862
nls codepage 863
CONFIG_NLS_CODEPAGE_863
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10418,7 +10886,7 @@ CONFIG_NLS_CODEPAGE_863
nls codepage 864
CONFIG_NLS_CODEPAGE_864
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10428,7 +10896,7 @@ CONFIG_NLS_CODEPAGE_864
nls codepage 865
CONFIG_NLS_CODEPAGE_865
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10439,7 +10907,7 @@ CONFIG_NLS_CODEPAGE_865
nls codepage 866
CONFIG_NLS_CODEPAGE_866
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10450,20 +10918,17 @@ CONFIG_NLS_CODEPAGE_866
nls codepage 869
CONFIG_NLS_CODEPAGE_869
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
DOS/Windows partitions correctly. This does apply to the filenames
only, not to the file contents. You can include several codepages;
say Y here if you want to include the DOS codepage for Greek.
-###
-### Why do we have two codepages for Greek and Cyrillic?
-###
nls codepage 874
CONFIG_NLS_CODEPAGE_874
- The Microsoft fat file system family can deal with filenames in
+ The Microsoft FAT file system family can deal with filenames in
native language character sets. These character sets are stored in
so-called DOS codepages. You need to include the appropriate
codepage if you want to be able to read/write these filenames on
@@ -10474,7 +10939,7 @@ CONFIG_NLS_CODEPAGE_874
nls iso8859-1
CONFIG_NLS_ISO8859_1
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 1 character
set, which covers most West European languages such as Albanian,
@@ -10485,7 +10950,7 @@ CONFIG_NLS_ISO8859_1
nls iso8859-2
CONFIG_NLS_ISO8859_2
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 2 character
set, which works for most Latin-written Slavic and Central European
@@ -10495,7 +10960,7 @@ CONFIG_NLS_ISO8859_2
nls iso8859-3
CONFIG_NLS_ISO8859_3
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 3 character
set, which is popular with authors of Esperanto, Galician, Maltese,
@@ -10504,7 +10969,7 @@ CONFIG_NLS_ISO8859_3
nls iso8859-4
CONFIG_NLS_ISO8859_4
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 4 character
set which introduces letters for Estonian, Latvian, and
@@ -10513,7 +10978,7 @@ CONFIG_NLS_ISO8859_4
nls iso8859-5
CONFIG_NLS_ISO8859_5
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for ISO8859-5, a Cyrillic
character set with which you can type Bulgarian, Byelorussian,
@@ -10523,7 +10988,7 @@ CONFIG_NLS_ISO8859_5
nls iso8859-6
CONFIG_NLS_ISO8859_6
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for ISO8859-6, the Arabic
character set.
@@ -10531,7 +10996,7 @@ CONFIG_NLS_ISO8859_6
nls iso8859-7
CONFIG_NLS_ISO8859_7
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for ISO8859-7, the Modern
Greek character set.
@@ -10539,7 +11004,7 @@ CONFIG_NLS_ISO8859_7
nls iso8859-8
CONFIG_NLS_ISO8859_8
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for ISO8859-8, the Hebrew
character set.
@@ -10547,7 +11012,7 @@ CONFIG_NLS_ISO8859_8
nls iso8859-9
CONFIG_NLS_ISO8859_9
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 5 character
set, and it replaces the rarely needed Icelandic letters in Latin 1
@@ -10556,7 +11021,7 @@ CONFIG_NLS_ISO8859_9
nls iso8859-10
CONFIG_NLS_ISO8859_10
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 6 character
set, which adds the last Inuit (Greenlandic) and Sami (Lappish)
@@ -10566,7 +11031,7 @@ CONFIG_NLS_ISO8859_10
NLS ISO 8859-14 (Latin 8; Celtic)
CONFIG_NLS_ISO8859_14
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 8 character
set, which adds the last accented vowels for Welsh (aka Cymraeg)
@@ -10576,7 +11041,7 @@ CONFIG_NLS_ISO8859_14
nls iso8859-15
CONFIG_NLS_ISO8859_15
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the Latin 9 character
set, which covers most West European languages such as Albanian,
@@ -10591,7 +11056,7 @@ CONFIG_NLS_ISO8859_15
nls koi8-r
CONFIG_NLS_KOI8_R
If you want to display filenames with native language characters
- from the Microsoft fat file system family or from JOLIET CDROMs
+ from the Microsoft FAT file system family or from JOLIET CDROMs
correctly on the screen, you need to include the appropriate
input/output character sets. Say Y here for the preferred Russian
character set.
@@ -10608,7 +11073,12 @@ CONFIG_VT
is done with certain key combinations, usually Alt-<function key>.
The setterm command ("man setterm") can be used to change the
- properties (such as colors) of a virtual terminal.
+ properties (such as colors or beeping) of a virtual terminal. The
+ man page console_codes(4) ("man console_codes") contains the special
+ character sequences that can be used to change those properties
+ directly. The fonts used on virtual terminals can be changed with
+ the setfont ("man setfont") command and the key bindings are defined
+ with the loadkeys ("man loadkeys") command.
You need at least one virtual terminal device in order to make use
of your keyboard and monitor. Therefore, only people configuring an
@@ -10634,20 +11104,10 @@ CONFIG_VT_CONSOLE
that with a kernel command line option such as "console=tty3" which
would use the third virtual terminal as system console. (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 .)
+ loadlin) about how to pass options to the kernel at boot time.)
If unsure, say Y.
-Software generated cursor
-CONFIG_SOFTCURSOR
- If you say Y here, you'll be able to do lots of nice things with the
- cursors of your virtual consoles -- for example turn them into
- non-blinking block cursors which are more visible on laptop screens,
- or change their colors depending on the virtual console they're on.
- See Documentation/VGA-softcursor.txt for more information.
-
Support for PowerMac keyboard
CONFIG_MAC_KEYBOARD
This option allows you to use an ADB keyboard attached to your
@@ -10698,9 +11158,7 @@ CONFIG_SERIAL_CONSOLE
you can alter that using a kernel command line option such as
"console=ttyS1". (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 .)
+ kernel at boot time.)
If you don't have a VGA card installed and you say Y here, the
kernel will automatically use the first serial line, /dev/ttyS0, as
@@ -10766,11 +11224,11 @@ CONFIG_RISCOM8
Computone IntelliPort Plus serial support
CONFIG_COMPUTONE
This driver supports the entire family of Intelliport II/Plus
- controllers with the exception of the MicroChannel controllers. It
- does not support products previous to the Intelliport II. These are
- multiport cards, which give you many serial ports. You would need
- something like this to connect more than two modems to your Linux
- box, for instance in order to become a dial-in server. If you have a
+ controllers with the exception of the MicroChannel controllers and
+ products previous to the Intelliport II. These are multiport cards,
+ which give you many serial ports. You would need something like
+ this to connect more than two modems to your Linux box, for
+ instance in order to become a dial-in server. If you have a
card like that, say Y here and read Documentation/computone.txt.
If you want to compile this as a module ( = code which can be
@@ -10818,13 +11276,13 @@ CONFIG_CYCLADES
Cyclades-Z interrupt mode operation (EXPERIMENTAL)
CONFIG_CYZ_INTR
- The Cyclades-Z family of multiport cards allows 2 (two) driver
- op modes: polling and interrupt. In polling mode, the driver will
- check the status of the Cyclades-Z ports every certain amount of
- time (which is called polling cycle and is configurable). In
- interrupt mode, it will use an interrupt line (IRQ) in order to check
- the status of the Cyclades-Z ports. The default op mode is polling.
- If unsure, say N.
+ The Cyclades-Z family of multiport cards allows 2 (two) driver op
+ modes: polling and interrupt. In polling mode, the driver will check
+ the status of the Cyclades-Z ports every certain amount of time
+ (which is called polling cycle and is configurable). In interrupt
+ mode, it will use an interrupt line (IRQ) in order to check the
+ status of the Cyclades-Z ports. The default op mode is polling. If
+ unsure, say N.
Stallion multiport serial support
CONFIG_STALDRV
@@ -10899,6 +11357,24 @@ CONFIG_ESPSERIAL
and read Documentation/modules.txt. The module will be called esp.o.
If unsure, say N.
+Moxa Intellio support
+CONFIG_MOXA_INTELLIO
+ Say Y here if you have a Moxa Intellio multiport serial card.
+
+ This driver can also be built as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called moxa.o. If you want to do that, say M
+ here.
+
+Moxa SmartIO support
+CONFIG_MOXA_SMARTIO
+ Say Y here if you have a Moxa SmartIO multiport serial card.
+
+ This driver can also be built as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called mxser.o. If you want to do that, say M
+ here.
+
Multi-Tech multiport card support (EXPERIMENTAL)
CONFIG_ISI
This is a driver for the Multi-Tech cards which provide several
@@ -10964,10 +11440,8 @@ CONFIG_PRINTER
If you have several parallel ports, you can specify which ports to
use with the "lp" kernel command line option. (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 .) The syntax of the "lp"
- command line option can be found in drivers/char/lp.c.
+ how to pass options to the kernel at boot time.) The syntax of the
+ "lp" command line option can be found in drivers/char/lp.c.
If you have more than 3 printers, you need to increase the LP_NO
variable in lp.c.
@@ -10980,11 +11454,118 @@ CONFIG_LP_CONSOLE
option "console=lp" to the kernel at boot time.
Note that kernel messages can get lost if the printer is out of
- paper (or off, or unplugged, or too busy..), but this behavior
+ paper (or off, or unplugged, or too busy..), but this behaviour
can be changed. See drivers/char/lp.c (do this at your own risk).
If unsure, say N.
+Support for user-space parallel port device drivers
+CONFIG_PPDEV
+ Saying Y to this adds support for /dev/parport device nodes. This
+ is needed for programs that want portable access to the parallel
+ port, for instance deviceid (which displays Plug-and-Play device
+ IDs).
+
+ This is the parallel port equivalent of SCSI generic support (sg).
+ It is safe to say N to this -- it is not needed for normal printing
+ or parallel port CD-ROM/disk support.
+
+ This support is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called ppdev.o.
+
+ If unsure, say N.
+
+I2C support
+CONFIG_I2C
+ I2C (pronounce: I-square-C) is a slow serial bus protocol used in
+ many micro controller applications and developed by Philips. SMBus,
+ or System Management Bus is a subset of the I2C protocol. More
+ information is contained in the directory Documentation/i2c/,
+ especially in the file called "summary" there.
+
+ Both I2C and SMBus are supported here. You will need this for
+ hardware sensors support, and also for Video for Linux support.
+ Specifically, if you want to use a BT848 based frame grabber/overlay
+ boards under Linux, say Y here and also to "I2C bit-banging
+ interfaces", below.
+
+ If you want I2C support, you should say Y here and also to the
+ specific driver for your bus adapter(s) below. If you say Y to
+ "/proc file system" below, you will then get a /proc interface which
+ is documented in Documentation/i2c/proc-interface.
+
+ This I2C support is also available as a module. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt. The module will be called i2c-core.o.
+
+I2C bit-banging interfaces
+CONFIG_I2C_ALGOBIT
+ This allows you to use a range of I2C adapters called bit-banging
+ adapters. Say Y if you own an I2C adapter belonging to this class
+ and then say Y to the specific driver for you adapter below.
+
+ This support is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called i2c-algo-bit.o.
+
+Philips style parallel port adapter
+CONFIG_I2C_PHILIPSPAR
+ This supports parallel-port I2C adapters made by Philips. Say Y if
+ you own such an adapter.
+
+ This driver is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called i2c-philips-par.o.
+
+ELV adapter
+CONFIG_I2C_ELV
+ This supports parallel-port I2C adapters called ELV. Say Y if you
+ own such an adapter.
+
+ This driver is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called i2c-elv.o.
+
+Velleman K9000 adapter
+CONFIG_I2C_VELLEMAN
+ This supports the Velleman K9000 parallel-port I2C adapter. Say Y if
+ you own such an adapter.
+
+ This driver is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called i2c-velleman.o.
+
+I2C PCF 8584 interfaces
+CONFIG_I2C_ALGOPCF
+ This allows you to use a range of I2C adapters called PCF adapters.
+ Say Y if you own an I2C adapter belonging to this class and then say
+ Y to the specific driver for you adapter below.
+
+ This support is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called i2c-algo-pcf.o.
+
+Elektor ISA card
+CONFIG_I2C_ELEKTOR
+ This supports the PCF8584 ISA bus I2C adapter. Say Y if you own such
+ an adapter.
+
+ This driver is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called i2c-elektor.o.
+
+I2C device interface
+CONFIG_I2C_CHARDEV
+ Say Y here to use i2c-* device files, usually found in the /dev
+ directory on your system. They make it possible to have user-space
+ programs use the I2C bus. Information on how to do this is contained
+ in the file Documentation/i2c/dev-interface.
+
+ This code is also available as a module. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. The
+ module will be called i2c-dev.o.
+
Bus Mouse Support
CONFIG_BUSMOUSE
Say Y here if your machine has a bus mouse as opposed to a serial
@@ -11069,7 +11650,7 @@ CONFIG_82C710_MOUSE
PC110 digitizer pad support
CONFIG_PC110_PAD
- This drives the digitizer pad on the IBM PC110 palmtop. It can turn
+ This drives the digitizer pad on the IBM PC110 palmtop. It can turn
the digitizer pad into a PS/2 mouse emulation with tap gestures or
into an absolute pad.
@@ -11258,11 +11839,10 @@ CONFIG_FT_PROC_FS
kernel driver. Saying Y will enlarge the size of the ftape driver
by approximately 2 KB.
- WARNING: When compiling ftape as a module (i.e. saying M to
- "Floppy tape drive") it is dangerous to use ftape's /proc file
- system interface. Accessing `/proc/ftape' while the module is
- unloaded will result in a kernel Oops. This cannot be fixed from
- inside ftape.
+ WARNING: When compiling ftape as a module (i.e. saying M to "Floppy
+ tape drive") it is dangerous to use ftape's /proc file system
+ interface. Accessing `/proc/ftape' while the module is unloaded will
+ result in a kernel Oops. This cannot be fixed from inside ftape.
Controlling the amount of debugging output of ftape
CONFIG_FT_NORMAL_DEBUG
@@ -11434,50 +12014,52 @@ CONFIG_FT_FDC_MAX_RATE
Direct Rendering Manager (XFree86 DRI support)
CONFIG_DRM
Kernel-level support for the Direct Rendering Infrastructure (DRI)
- introduced in XFree86 4.x. These modules provide support for
- synchronization, security, and DMA transfers. Select the module that
- provides support for your graphics card.
+ introduced in XFree86 4.x. If you say Y here, you need to select
+ the module that's right for your graphics card from the list below.
+ These modules provide support for synchronization, security, and
+ DMA transfers. Please read drivers/char/drm/README.drm for more
+ details.
-tdfx Direct Rendering Manager (XFree86 DRI support)
+3dfx Banshee/Voodoo3
CONFIG_DRM_TDFX
Choose M here if you have a 3dfx Banshee/Voodoo3 graphics card.
+ The module will be called tdfx.o.
3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support)
CONFIG_DRM_GAMMA
Choose M here if you have a 3dlabs GMX 2000 graphics card.
+ The module will be called gamma.o.
MTRR control and configuration
CONFIG_MTRR
On Intel P6 family processors (Pentium Pro, Pentium II and later)
the Memory Type Range Registers (MTRRs) may be used to control
- processor access to memory ranges. This is most useful when you have
+ processor access to memory ranges. This is most useful if you have
a video (VGA) card on a PCI or AGP bus. Enabling write-combining
allows bus write transfers to be combined into a larger transfer
before bursting over the PCI/AGP bus. This can increase performance
- of image write operations 2.5 times or more. This option creates a
- /proc/mtrr file which may be used to manipulate your
- MTRRs. Typically the X server should use this. This should have a
- reasonably generic interface so that similar control registers on
- other processors can be easily supported.
+ of image write operations 2.5 times or more. Saying Y here creates a
+ /proc/mtrr file which may be used to manipulate your processor's
+ MTRRs. Typically the X server should use this.
+
+ This code has a reasonably generic interface so that similar
+ control registers on other processors can be easily supported
+ as well:
The Cyrix 6x86, 6x86MX and M II processors have Address Range
Registers (ARRs) which provide a similar functionality to MTRRs. For
- these, the ARRs are used to emulate the MTRRs, which means that it
- makes sense to say Y here for these processors as well.
-
+ these, the ARRs are used to emulate the MTRRs.
The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing
- write-combining. All of these processors are supported by this code.
-
- The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
- are supported.
+ write-combining. All of these processors are supported by this code
+ and it makes sense to say Y here if you have one of them.
Saying Y here also fixes a problem with buggy SMP BIOSes which only
- set the MTRRs for the boot CPU and not the secondary CPUs. This can
- lead to all sorts of problems.
+ set the MTRRs for the boot CPU and not for the secondary CPUs. This
+ can lead to all sorts of problems, so it's good to say Y here.
You can safely say Y even if your machine doesn't have MTRRs, you'll
- just add about 9K to your kernel.
+ just add about 9 KB to your kernel.
See Documentation/mtrr.txt for more information.
@@ -11487,11 +12069,6 @@ CONFIG_FT_ALPHA_CLOCK
determined automatically, so you need to specify it here ONLY if
running a DEC Alpha, otherwise this setting has no effect.
-Zilog serial support
-CONFIG_SUN_ZS
- This driver does not exist at this point, so you might as well
- say N.
-
Double Talk PC internal speech card support
CONFIG_DTLK
This driver is for the DoubleTalk PC, a speech synthesizer
@@ -11531,26 +12108,54 @@ CONFIG_APPLICOM
Power Management support
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.
+ "Power Management" means that parts of your computer are shut
+ off or put into a power conserving "sleep" mode if they are not
+ being used. There are two competing standards for doing this: APM
+ and ACPI. If you want to use either one, say Y here and then also to
+ the requisite support below.
+
+ Power Management is most important for battery powered laptop
+ computers; if you have a laptop, check out the Linux Laptop home
+ page on the WWW at
+ http://www.cs.utexas.edu/users/kharker/linux-laptop/ and the Battery
+ Powered Linux mini-HOWTO, available from
+ http://www.linuxdoc.org/docs.html#howto .
- 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).
+ Note that, even if you say N here, Linux on the x86 architecture
+ will issue the hlt instruction if nothing is to be done, thereby
+ sending the processor to sleep and saving power.
- Both are supported by the Linux Kernel.
+ACPI support
+CONFIG_ACPI
+ The Advanced Configuration and Power Interface is a standard
+ designed to allow the operating system more control over power
+ management issues, such as suspending a computer in a low power
+ consumption state after a certain time of inaction. It aims to be
+ an improved version of APM (see below). ACPI has to be
+ supported by the motherboard. You can read more about the standard
+ at http://www.teleport.com/~acpi/ .
+
+ If your computer supports ACPI and you want to use it, say Y here.
+ You will then need supporting software; for location and more
+ information, please read Documentation/pm.txt and the Battery
+ Powered Linux mini-HOWTO, available from
+ http://www.linuxdoc.org/docs.html#howto .
- 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.
+ If you say Y here and also to "Advanced Power Management" (APM)
+ below, then ACPI has precedence in the sense that, if your hardware
+ supports ACPI, it will be used and APM won't.
+
+ To compile this driver 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
+ acpi.o.
Enter S1 for sleep (EXPERIMENTAL)
CONFIG_ACPI_S1_SLEEP
- This enable ACPI compliant devices to enter level 1 of ACPI saving
- power levels. Basically, this will let them entering in sleep mode.
+ If you say Y here, ACPI compliant devices can enter level 1 of ACPI
+ saving power levels. Basically, this will let them enter sleep mode.
-Advanced Power Management
+Advanced Power Management BIOS support
CONFIG_APM
APM is a BIOS specification for saving power using several different
techniques. This is mostly useful for battery powered laptops with
@@ -11565,8 +12170,9 @@ CONFIG_APM
Note that the APM support is almost completely disabled for
machines with more than one CPU.
- Supporting software is available; for more information, read the
- Battery Powered Linux mini-HOWTO, available from
+ In order to use APM, you will need supporting software. For location
+ and more information, read Documentation/pm.txt and the Battery
+ Powered Linux mini-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto .
This driver does not spin down disk drives (see the hdparm(8)
@@ -11578,10 +12184,6 @@ CONFIG_APM
desktop machines also don't have compliant BIOSes, and this driver
may cause those machines to panic during the boot phase.
- If you are running Linux on a laptop, you may also want to read the
- Linux Laptop home page on the WWW at
- http://www.cs.utexas.edu/users/kharker/linux-laptop/ .
-
Generally, if you don't have a battery in your machine, there isn't
much point in using this driver and you should say N. If you get
random kernel OOPSes or reboots that don't seem to be related to
@@ -11689,7 +12291,7 @@ CONFIG_APM_ALLOW_INTS
Normally we disable external interrupts while we are making calls to
the APM BIOS as a measure to lessen the effects of a badly behaving
BIOS implementation. The BIOS should reenable interrupts if it
- needs to. Unfortunately, some BIOSes do not - especially those in
+ needs to. Unfortunately, some BIOSes do not -- especially those in
many of the newer IBM Thinkpads. If you experience hangs when you
suspend, try setting this to Y. Otherwise, say N.
@@ -11724,7 +12326,7 @@ CONFIG_WATCHDOG
Disable watchdog shutdown on close
CONFIG_WATCHDOG_NOWAYOUT
- The default watchdog behavior (which you get if you say N here) is
+ The default watchdog behaviour (which you get if you say N here) is
to stop the timer if the process managing it closes the file
/dev/watchdog. It's always remotely possible that this process might
get killed. If you say Y here, the watchdog cannot be stopped once
@@ -11797,34 +12399,47 @@ CONFIG_ACQUIRE_WDT
module, say M here and read Documentation/modules.txt. Most people
will say N.
-Intel P6 CPU Microcode Update Support
+Mixcom Watchdog
+CONFIG_MIXCOMWD
+ This is a driver for the Mixcom hardware watchdog cards. This
+ watchdog simply watches your kernel to make sure it doesn't freeze,
+ and if it does, it reboots your computer after a certain amount of
+ time.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module is called mixcomwd.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt. Most people
+ will say N.
+
+/dev/cpu/microcode - Intel P6 CPU microcode support
CONFIG_MICROCODE
- If you say Y here you will be able to update microcode on
- Intel processors in P6 family, e.g. Pentium Pro, Pentium II,
+ If you say Y here and also to "/dev file system support" in the
+ 'File systems' section, you will be able to update the microcode on
+ Intel processors in the P6 family, e.g. Pentium Pro, Pentium II,
Pentium III, Xeon etc. You will obviously need the actual microcode
- binary data itself which is not shipped with the Linux kernel.
- You also need to say Y to "/dev file system support" in 'File systems'
- section of the kernel configuration menu.
+ binary data itself which is not shipped with the Linux kernel.
- You need to be superuser to do that. For latest news and information
- on obtaining all the required ingredients for this driver, check:
-
- http://www.ocston.org/~tigran/patches/microcode
+ For latest news and information on obtaining all the required
+ ingredients for this driver, check:
+ http://www.ocston.org/~tigran/patches/microcode .
This driver 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 microcode.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
+ The module will be called microcode.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt.
Enhanced Real Time Clock Support
CONFIG_RTC
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
- will get access to the real time clock built into your computer.
+ will get access to the real time clock (or hardware clock) built
+ into your computer.
+
Every PC has such a clock built in. It can be used to generate
signals from as low as 1Hz up to 8192Hz, and can also be used
as a 24 hour alarm. It reports status information via the file
- /proc/driver/rtc and its behavior is set by various ioctls on
+ /proc/driver/rtc and its behaviour is set by various ioctls on
/dev/rtc.
If you run Linux on a multiprocessor machine and said Y to
@@ -11835,6 +12450,15 @@ CONFIG_RTC
sampling), then say Y here, and read Documentation/rtc.txt for
details.
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module is called rtc.o. If you want to compile it as a module,
+ say M here and read Documentation/modules.txt.
+
+### Add
+#EFI Real Time Clock Services
+#CONFIG_EFI_RTC
+
Tadpole ANA H8 Support
CONFIG_H8
The Hitachi H8/337 is a microcontroller used to deal with the power
@@ -11878,6 +12502,11 @@ CONFIG_JOYSTICK
the file Documentation/joystick.txt which contains more information
and the location of the joystick package that you'll need.
+ This driver 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 joystick.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
Classic PC analog
CONFIG_JOY_ANALOG
Say Y here if you have a controller that connects to the PC
@@ -11887,30 +12516,55 @@ CONFIG_JOY_ANALOG
ThrustMaster FCS or 6 and 8 button gamepads. For more information on
how to use the driver please read Documentation/joystick.txt
+ This driver 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 joy-analog.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
FPGaming and MadCatz A3D
CONFIG_JOY_ASSASSIN
Say Y here if you have an FPGaming or MadCatz controller using the
A3D protocol over the PC gameport. For more information on how to
use the driver please read Documentation/joystick.txt
+ This driver 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 joy-assasin.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Gravis GrIP
CONFIG_JOY_GRAVIS
Say Y here if you have a Gravis controller using the GrIP protocol
over the PC gameport. For more information on how to use the driver
please read Documentation/joystick.txt
+ This driver 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 joy-gravis.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Logitech ADI
CONFIG_JOY_LOGITECH
Say Y here if you have a Logitech controller using the ADI
protocol over the PC gameport. For more information on how to use
the driver please read Documentation/joystick.txt
+ This driver 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 joy-logitech.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Microsoft SideWinder
CONFIG_JOY_SIDEWINDER
Say Y here if you have a Microsoft controller using the Digital
Overdrive protocol over PC gameport. For more information on how to
use the driver please read Documentation/joystick.txt
+ This driver 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 joy-sidewinder.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
ThrustMaster DirectConnect
CONFIG_JOY_THRUSTMASTER
Say Y here if you have a ThrustMaster controller using the
@@ -11918,18 +12572,44 @@ CONFIG_JOY_THRUSTMASTER
information on how to use the driver please read
Documentation/joystick.txt
+ This driver 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 joy-thrustmaster.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Creative Labs Blaster
CONFIG_JOY_CREATIVE
Say Y here if you have a Creative Labs controller using the
Blaster protocol over the PC gameport. For more information on how
to use the driver please read Documentation/joystick.txt
-PDPI Lightning 4 card
+ This driver 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 joy-creative.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
+PDPI Lightning 4 cards
CONFIG_JOY_LIGHTNING
Say Y here if you have a PDPI Lightning 4 gamecard and an analog
joystick or gamepad connected to it. For more information on how to
use the driver please read Documentation/joystick.txt
+ This driver 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 joy-lightning.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
+Logitech WingMan Warrior
+CONFIG_JOY_WARRIOR
+ Say Y here if you have a Logitech WingMan Warrior controller
+ connected to your computer's serial port. For more information on
+ how to use the driver please read Documentation/joystick.txt
+
+ This driver 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 joy-warrior.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Trident 4DWave and Aureal Vortex gameport
CONFIG_JOY_PCI
Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
@@ -11937,12 +12617,22 @@ CONFIG_JOY_PCI
with and ordinary analog joystick. For more information on how to
use the driver please read Documentation/joystick.txt
+ This driver 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 joy-pci.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Magellan and Space Mouse
CONFIG_JOY_MAGELLAN
Say Y here if you have a Magellan or Space Mouse 6DOF controller
connected to your computer's serial port. For more information on
how to use the driver please read Documentation/joystick.txt
+ This driver 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 joy-magellan.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
SpaceTec SpaceOrb 360 and SpaceBall Avenger
CONFIG_JOY_SPACEORB
Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
@@ -11950,6 +12640,11 @@ CONFIG_JOY_SPACEORB
information on how to use the driver please read
Documentation/joystick.txt
+ This driver 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 joy-spaceorb.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
SpaceTec SpaceBall 4000 FLX
CONFIG_JOY_SPACEBALL
Say Y here if you have a SpaceTec SpaceBall 4000 FLX
@@ -11957,12 +12652,11 @@ CONFIG_JOY_SPACEBALL
information on how to use the driver please read
Documentation/joystick.txt
-Logitech WingMan Warrior
-CONFIG_JOY_WARRIOR
- Say Y here if you have a Logitech WingMan Warrior controller
- connected to your computer's serial port. For more information on
- how to use the driver please read Documentation/joystick.txt
-
+ This driver 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 joy-spaceball.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
NES, SNES, N64, PSX, Multi
CONFIG_JOY_CONSOLE
Say Y here if you have a Nintendo Entertainment System gamepad,
@@ -11972,15 +12666,25 @@ CONFIG_JOY_CONSOLE
For more information on how to use the driver please read
Documentation/joystick.txt and Documentation/joystick-parport.txt
+ This driver 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 joy-console.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Sega, Multi
CONFIG_JOY_DB9
Say Y here if you have a Sega Master System gamepad, Sega Genesis
gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
- Commodore, Amstrad CPC joystick connected to your parallel port. For
- more information on how to use the driver please read
- Documentation/joystick.txt and Documentation/joystick-parport.txt
+ Commodore, Amstrad CPC joystick connected to your parallel port.
+ For more information on how to use the driver please read
+ Documentation/joystick.txt and Documentation/joystick-parport.txt.
-TurboGraFX interface
+ This driver 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 joy-db9.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
+TurboGraFX Multisystem interface
CONFIG_JOY_TURBOGRAFX
Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
and want to use it with Multiststem -- Atari, Amiga, Commodore,
@@ -11988,12 +12692,22 @@ CONFIG_JOY_TURBOGRAFX
please read Documentation/joystick.txt and
Documentation/joystick-parport.txt
+ This driver 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 joy-turbografx.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Amiga joysticks
CONFIG_JOY_AMIGA
Say Y here if you have an Amiga with a digital joystick connected
to it. For more information on how to use the driver please read
Documentation/joystick.txt
+ This driver 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 joy-amiga.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
Atomwide Serial Support
CONFIG_ATOMWIDE_SERIAL
If you have an Atomwide Serial card for an Acorn system, say Y to
@@ -12017,7 +12731,7 @@ CONFIG_NWBUTTON
row.
Do not hold the button down for too long, as the driver does not
- alter the behavior of the hardware reset circuitry attached to the
+ alter the behaviour of the hardware reset circuitry attached to the
button; it will still execute a hard reset if the button is held
down for longer than approximately five seconds.
@@ -12066,7 +12780,7 @@ CONFIG_SOUND
I'm told that even without a sound card, you can make your computer
say more than an occasional beep, by programming the PC speaker.
Kernel patches and supporting utilities to do that are in the pcsp
- package, available at ftp://ftp.infradead.org/pub/pcsp/.
+ package, available at ftp://ftp.infradead.org/pub/pcsp/ .
OSS sound modules
CONFIG_SOUND_OSS
@@ -12096,24 +12810,25 @@ CONFIG_SOUND_SGALAXY
This module initializes the older non Plug and Play sound galaxy
cards from Aztech. It supports the Waverider Pro 32 - 3D and the
Galaxy Washington 16.
+
If you compile the driver into the kernel, you have to add
- "sgalaxy=<io>,<irq>,<dma>,<dma2>,<sgbase>" to the kernel command line.
+ "sgalaxy=<io>,<irq>,<dma>,<dma2>,<sgbase>" to the kernel command
+ line.
Support for AD1816(A) based cards (EXPERIMENTAL)
CONFIG_SOUND_AD1816
Say M here if you have a sound card based on the Analog Devices
AD1816(A) chip.
+
If you compile the driver into the kernel, you have to add
"ad1816=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
- NOTE: This driver is still EXPERIMENTAL.
- See Documentation/sound/AD1816 for further information.
-
Yamaha OPL3-SA1 audio controller
CONFIG_SOUND_OPL3SA1
Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
usually built into motherboards. Read Documentation/sound/OPL3-SA
for details.
+
If you compile the driver into the kernel, you have to add
"opl3sa=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
command line.
@@ -12124,6 +12839,7 @@ CONFIG_SOUND_PAS
16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
some other card made by Media Vision or Logitech since they are not
PAS16 compatible.
+
If you compile the driver into the kernel, you have to add
"pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
to the kernel command line.
@@ -12138,14 +12854,16 @@ CONFIG_SOUND_SB
Please read the file Documentation/sound/Soundblaster.
You should also say Y here for cards based on the Avance Logic
- ALS-007 chip (read Documentation/sound/ALS007) and for cards based
+ ALS-007 chip (read Documentation/sound/ALS) and for cards based
on ESS chips (read Documentation/sound/ESS1868 and
Documentation/sound/ESS). If you have an SB AWE 32 or SB AWE 64, say
Y here and also to "Additional lowlevel drivers" and to "SB32/AWE
support" below and read Documentation/sound/INSTALL.awe. If you have
an IBM Mwave card, say Y here and read Documentation/sound/mwave.
- If you compile the driver into the kernel and don't want to use isapnp,
- you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
+
+ If you compile the driver into the kernel and don't want to use
+ isapnp, you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel
+ command line.
You can say M here to compile this driver as a module; the module is
called sb.o.
@@ -12161,6 +12879,7 @@ CONFIG_SOUND_GUS
Say Y here for any type of Gravis Ultrasound card, including
the GUS or GUS MAX. See also Documentation/sound/ultrasound for
more information on configuring this card with modules.
+
If you compile the driver into the kernel, you have to add
"gus=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
@@ -12174,6 +12893,7 @@ CONFIG_SOUND_MPU401
was in the list of supported cards, look at the card specific
instructions in the drivers/sound/Readme.cards file. It's safe to
answer Y if you have a true MPU401 MIDI interface card.
+
If you compile the driver into the kernel, you have to add
"mpu401=<io>,<irq>" to the kernel command line.
@@ -12182,14 +12902,10 @@ CONFIG_SOUND_UART6850
This option enables support for MIDI interfaces based on the 6850
UART chip. This interface is rarely found on sound cards. It's safe
to answer N to this question.
+
If you compile the driver into the kernel, you have to add
"uart6850=<io>,<irq>" to the kernel command line.
-VIDC Sound
-CONFIG_VIDC_SOUND
- Say Y here for ARM systems with the VIDC video controller and 16-bit
- Linear sound DACs. If unsure, say N.
-
PSS (AD1848, ADSP-2115, ESC614) support
CONFIG_SOUND_PSS
Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven
@@ -12197,6 +12913,7 @@ CONFIG_SOUND_PSS
ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on
how to compile it into the kernel or as a module see the file
Documentation/sound/PSS.
+
If you compile the driver into the kernel, you have to add
"pss=<io>,<mssio>,<mssirq>,<mssdma>,<mpuio>,<mpuirq>" to the kernel
command line.
@@ -12223,16 +12940,6 @@ CONFIG_PSS_BOOT_FILE
Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file,
starting from /.
-16 bit sampling option of GUS (_NOT_ GUS MAX)
-CONFIG_SOUND_GUS16
- Answer Y if you have installed the 16 bit sampling daughtercard on
- your GUS. Answer N if you have a GUS MAX, since saying Y here
- disables GUS MAX support.
-
-GUS MAX support
-CONFIG_SOUND_GUSMAX
- Answer Y only if you have a Gravis Ultrasound MAX.
-
Microsoft Sound System support
CONFIG_SOUND_MSS
Again think carefully before answering Y to this question. It's safe
@@ -12258,8 +12965,10 @@ CONFIG_SOUND_MSS
specific instructions in drivers/sound/Readme.cards. Some drivers
have their own MSS support and saying Y to this option will cause a
conflict.
+
If you compile the driver into the kernel, you have to add
- "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command line.
+ "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command
+ line.
SGI Visual Workstation on-board audio
CONFIG_SOUND_VWSND
@@ -12272,16 +12981,15 @@ CONFIG_SOUND_SSCAPE
Answer Y if you have a sound card based on the Ensoniq SoundScape
chipset. Such cards are being manufactured at least by Ensoniq, Spea
and Reveal (Reveal makes also other cards).
+
If you compile the driver into the kernel, you have to add
- "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command line.
+ "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
+ line.
MediaTriX AudioTriX Pro support
CONFIG_SOUND_TRIX
Answer Y if you have the AudioTriX Pro sound card manufactured
by MediaTrix.
- If you compile the driver into the kernel, you have to add
- "trix=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<mpuio>,<mpuirq>"
- to the kernel command line.
Have TRXPRO.HEX firmware file
CONFIG_TRIX_HAVE_BOOT
@@ -12306,6 +13014,7 @@ CONFIG_SOUND_MAD16
and Diamond (latest ones). Note however that the Tropez sound cards
have their own driver; if you have one of those, say N here and Y or
M to "Full support for Turtle Beach WaveFront", below.
+
If you compile the driver into the kernel, you have to add
"mad16=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the
kernel command line.
@@ -12329,6 +13038,7 @@ Support for Crystal CS4232 based (PnP) cards
CONFIG_SOUND_CS4232
Say Y here if you have a card based on the Crystal CS4232 chip set,
which uses its own Plug and Play protocol.
+
If you compile the driver into the kernel, you have to add
"cs4232=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
command line.
@@ -12341,6 +13051,7 @@ CONFIG_SOUND_OPL3SA2
Say Y or M if you have a card based on one of these Yamaha
sound chipsets. Read Documentation/sound/OPL3-SA2 for more
information on configuring these cards.
+
If you compile the driver into the kernel, you have to add
"opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>" to the kernel
command line.
@@ -12349,6 +13060,7 @@ Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
CONFIG_SOUND_MAUI
Say Y here if you have a Turtle Beach Wave Front, Maui, or Tropez
sound card.
+
If you compile the driver into the kernel, you have to add
"maui=<io>,<irq>" to the kernel command line.
@@ -12447,15 +13159,11 @@ CONFIG_SOUND_YM3812
cards, however).
Please read the file Documentation/sound/OPL3 if your card has an
OPL3 chip.
+
If you compile the driver into the kernel, you have to add
"opl3=<io>" to the kernel command line.
If unsure, say Y.
-
-Sun Audio support
-CONFIG_SUN_AUDIO
- This is support for the sound cards on Sun workstations. The code
- does not exist yet, so you might as well say N here.
ACI mixer (miroPCM12/PCM20)
CONFIG_SOUND_ACI_MIXER
@@ -12502,6 +13210,7 @@ CONFIG_AEDSP16_SBPRO
You should then say Y to "100% Sound Blaster compatibles
(SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
emulation)".
+
If you compile the driver into the kernel, you have to add
"aedsp16=<io>,<irq>,<dma>,<mssio>,<mpuio>,<mouirq>" to the kernel
command line.
@@ -12590,7 +13299,7 @@ CONFIG_SOUND_TRIDENT
for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018.
This driver differs slightly from OSS/Free, so PLEASE READ the
- comments at of driver/sound/trident.c
+ comments at the top of driver/sound/trident.c
Rockwell WaveArtist
CONFIG_SOUND_WAVEARTIST
@@ -12599,18 +13308,18 @@ CONFIG_SOUND_WAVEARTIST
VIA 82Cxxx Audio Codec
CONFIG_SOUND_VIA82CXXX
- Say Y here to include support for the audio codec found on
- VIA 82Cxxx-based chips. Typically these are built into a motherboard.
- DO NOT select SoundBlaster or Adlib with this driver, unless you have
- a SoundBlaster or Adlib card in addition to your VIA audio chip.
+ Say Y here to include support for the audio codec found on VIA
+ 82Cxxx-based chips. Typically these are built into a motherboard. DO
+ NOT select Sound Blaster or Adlib with this driver, unless you have
+ a Sound Blaster or Adlib card in addition to your VIA audio chip.
NeoMagic 256AV/256ZX sound chipsets
CONFIG_SOUND_NM256
Say M here to include audio support for the NeoMagic 256AV/256ZX
- chipsets. These are the audio chipsets found in the Sony Z505S/SX/DX,
- some Sony F-series, and the Dell Latitude CPi and CPt laptops. It includes
- support for an AC97-compatible mixer and an apparently proprietary sound
- engine.
+ chipsets. These are the audio chipsets found in the Sony
+ Z505S/SX/DX, some Sony F-series, and the Dell Latitude CPi and CPt
+ laptops. It includes support for an AC97-compatible mixer and an
+ apparently proprietary sound engine.
See Documentation/sound/NM256 for further information.
@@ -12627,9 +13336,9 @@ CONFIG_CROSSCOMPILE
Kernel support for Linux/MIPS 32-bit binary compatibility
CONFIG_MIPS32_COMPAT
- Select this option this option if you want Linux/MIPS 32-bit binary
- compatibility. Since all software available available for Linux/MIPS
- is currently 32-bit you should say Y here.
+ Select this option if you want Linux/MIPS 32-bit binary
+ compatibility. Since all software available for Linux/MIPS is
+ currently 32-bit you should say Y here.
Build fp exception handler module
CONFIG_MIPS_FPE_MODULE
@@ -12717,7 +13426,7 @@ CONFIG_ISDN_AUDIO
X.25 PLP on top of ISDN
CONFIG_ISDN_X25
- This feature provides the X.25 protocol over ISDN connections.
+ This feature provides the X.25 protocol over ISDN connections.
See Documentation/isdn/README.x25 for more information
if you are thinking about using this.
@@ -12782,11 +13491,21 @@ CONFIG_ISDN_DRV_HISAX
HiSax Support for EURO/DSS1
CONFIG_HISAX_EURO
- Enable this if you have a EURO ISDN line.
+ Say Y or N according to the D-channel protocol which your local
+ telephone service company provides.
-Support for german chargeinfo
+ NOTE: If you say Y here and you have only one ISDN card installed,
+ you cannot say Y to "HiSax Support for German 1TR6", below. And vice
+ versa.
+
+Support for german charge info
CONFIG_DE_AOC
- If you have german AOC, you can enable this to get the charginfo.
+ If you want that the HiSax hardware driver sends messages to the
+ upper level of the isdn code on each AOCD (Advice Of Charge, During
+ the call -- transmission of the fee information during a call) and
+ on each AOCE (Advice Of Charge, at the End of the call --
+ transmission of fee information at the end of the call), say Y here.
+ This works only in Germany.
Disable sending complete
CONFIG_HISAX_NO_SENDCOMPLETE
@@ -12800,12 +13519,17 @@ CONFIG_HISAX_NO_LLC
Disable keypad protocol option
CONFIG_HISAX_NO_KEYPAD
- If you like to send special dialstrings including * or # without
+ If you like to send special dial strings including * or # without
using the keypad protocol, select this option.
-HiSax Support for german 1TR6
+HiSax Support for German 1TR6
CONFIG_HISAX_1TR6
- Enable this if you have a old german 1TR6 line.
+ Say Y or N according to the D-channel protocol which your local
+ telephone service company provides.
+
+ NOTE: If you say Y here and you have only one ISDN card installed,
+ you cannot say Y to "HiSax Support for EURO/DSS1", above. And vice
+ versa.
Teles 16.0/8.0
CONFIG_HISAX_16_0
@@ -12829,7 +13553,7 @@ Teles PCI
CONFIG_HISAX_TELESPCI
This enables HiSax support for the Teles PCI.
See Documentation/isdn/README.HiSax on how to configure it.
-
+
Teles S0Box
CONFIG_HISAX_S0BOX
This enables HiSax support for the Teles/Creatix parallel port
@@ -12992,8 +13716,8 @@ CONFIG_HISAX_W6692
HFC-S+, HFC-SP, HFC-PCMCIA cards (EXPERIMENTAL)
CONFIG_HISAX_HFC_SX
- This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA cards.
- This code is not finished yet.
+ This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
+ cards. This code is not finished yet.
Am7930 (EXPERIMENTAL)
CONFIG_HISAX_AMD7930
@@ -13049,10 +13773,16 @@ CONFIG_ISDN_TTY_FAX
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/. This is needed for AVM's set of active ISDN
- controllers like B1, T1, M1.
+ 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/ . This is needed for AVM's set of
+ active ISDN controllers like B1, T1, M1.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The modules will be called capi.o and kernelcapi.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
AVM B1 ISA support
CONFIG_ISDN_DRV_AVMB1_B1ISA
@@ -13091,7 +13821,6 @@ CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
disconnecting. This will increase the size of the kernel by 7 KB. If
unsure, say Y.
-
IBM Active 2000 support (EXPERIMENTAL)
CONFIG_ISDN_DRV_ACT2000
Say Y here if you have an IBM Active 2000 ISDN card. In order to use
@@ -13100,12 +13829,12 @@ CONFIG_ISDN_DRV_ACT2000
isdn4k-utils package. Please read the file
Documentation/isdn/README.act2000 for more information.
-Support for AP1000 multicomputer
-CONFIG_AP1000
- This enables support for a SPARC based parallel multi-computer
- called AP1000+. For details on our efforts to port Linux to this
- machine see http://cap.anu.edu.au/cap/projects/linux or mail to
- hackers@cafe.anu.edu.au
+Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)
+CONFIG_HYSDN
+ Say Y here if you have one of Hypercope's active PCI ISDN cards
+ Champ, Ergo and Metro. You will then get a module called hysdn.o.
+ Please read the file Documentation/isdn/README.hysdn for more
+ information.
Support for Sun4 architecture
CONFIG_SUN4
@@ -13127,11 +13856,11 @@ PTI Qlogic, ISP Driver
CONFIG_SCSI_QLOGICPTI
This driver supports SBUS SCSI controllers from PTI or QLogic. These
controllers are known under Solaris as qpti and in the openprom as
- PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are driven
- by a different driver.
+ PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are
+ driven by a different driver.
- This support is also available as a module called qlogicpti.o ( = code
- which can be inserted in and removed from the running kernel
+ This support is also available as a module called qlogicpti.o ( =
+ code which can be inserted in and removed from the running kernel
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
@@ -13147,14 +13876,14 @@ CONFIG_SUN_OPENPROMIO
Openprom tree appears in /proc/openprom
CONFIG_SUN_OPENPROMFS
- If you say Y, the OpenPROM device tree will be available as a virtual
- file system, which you can mount to /proc/openprom by
- "mount -t openpromfs none /proc/openprom".
+ If you say Y, the OpenPROM device tree will be available as a
+ virtual file system, which you can mount to /proc/openprom by "mount
+ -t openpromfs none /proc/openprom".
- If you want to compile the /proc/openprom support 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 openpromfs.o. If unsure, say M.
+ If you want to compile the /proc/openprom support 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 openpromfs.o. If unsure, say M.
Kernel support for Linux/Sparc 32bit binary compatibility
CONFIG_SPARC32_COMPAT
@@ -13195,8 +13924,8 @@ CONFIG_OBP_FLASH
JavaStation OS Flash SIMM (EXPERIMENTAL)
CONFIG_SUN_JSFLASH
- This option enables a driver for JavaStation OS Flash driver.
- Say N unless you want to boot from your Flash SIMM.
+ If you say Y here, you will be able to boot from your JavaStation's
+ Flash memory.
Siemens SAB82532 serial support
CONFIG_SAB82532
@@ -13212,8 +13941,9 @@ Audio support (EXPERIMENTAL)
CONFIG_SPARCAUDIO
This driver provides support for the build-in sound devices on most
Sun machines. If you want to be able to use this, select this option
- and one or more of the lowlevel drivers below. See
- http://www.dementia.org/~shadow/sparcaudio.html for more information.
+ and one or more of the lowlevel drivers below. See
+ http://www.dementia.org/~shadow/sparcaudio.html for more
+ information.
AMD7930 Lowlevel Driver
CONFIG_SPARCAUDIO_AMD7930
@@ -13227,108 +13957,20 @@ CONFIG_SPARCAUDIO_CS4231
DBRI Lowlevel Driver
CONFIG_SPARCAUDIO_DBRI
- This driver supports the DBRI audio interface found on the SS10, SS20,
- Sparcbook 3, and Voyager systems.
+ This driver supports the DBRI audio interface found on the SS10,
+ SS20, Sparcbook 3, and Voyager systems.
Dummy lowlevel Driver
CONFIG_SPARCAUDIO_DUMMY
- This is a pseudo-driver used for debugging and testing the sparcaudio
- subsystem. Say N unless you want to work on this subsystem.
+ This is a pseudo-driver used for debugging and testing the
+ sparcaudio subsystem. Say N unless you want to work on this
+ subsystem.
Sparc hardware (EXPERIMENTAL)
CONFIG_PARPORT_SUNBPP
- This driver provides support for the bidirectional parallel port found
- on many Sun machines. Note that many of the newer Ultras actually have
- pc style hardware instead.
-
-IEEE 1394 (aka FireWire) support
-CONFIG_IEEE1394
- IEEE 1394 describes a high performance serial bus, which is also
- known as FireWire(tm) or i.Link(tm) and is used for connecting all
- sorts of devices (most notably digital video cameras).
-
- If you have FireWire hardware and want to use it, say Y here. This
- is the core support only, you will also need to select a driver for
- your IEEE 1394 adapter.
-
- 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 ieee1394.o.
-
- FireWire is a trademark by Apple Inc. and i.Link is a trademark by
- Sony.
-
-TI PCILynx IEEE 1394 support
-CONFIG_IEEE1394_PCILYNX
- Say Y here if you have a IEEE-1394 controller with the Texas
- Instruments PCILynx chip. Note: this driver is written for revision
- 2 of this chip and may not work with revision 0.
-
- 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 pcilynx.o.
-
-Use local RAM on PCILynx board
-CONFIG_IEEE1394_PCILYNX_LOCALRAM
- This option makes the PCILynx driver use local RAM available on some
- PCILynx setups for Packet Control Lists. Local RAM may speed up
- command processing because no PCI transfers are necessary during
- use of the Packet Control Lists.
-
- Note that there are no known PCILynx systems providing local RAM
- except for the evaluation boards by Texas Instruments and that the
- PCILynx does not reliably report missing RAM.
-
- Unless you are absolutely sure that you have 64kB of local RAM and
- that you want to use it or if you don't know what this is all about,
- say N here.
-
-Adaptec AIC-5800 IEEE 1394 support
-CONFIG_IEEE1394_AIC5800
- Say Y here if you have a IEEE 1394 controller using the Adaptec
- AIC-5800 chip. All Adaptec host adapters (89xx series) use this
- chip, as well as miro's DV boards.
-
- 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 aic5800.o.
-
-OHCI (Open Host Controller Interface) support
-CONFIG_IEEE1394_OHCI1394
- Say Y here if you have a IEEE 1394 controller based on OHCI.
- The current driver was only tested with OHCI chipsets made
- by Texas Instruments. However, most third-party vendors use
- TI chips.
-
- 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 ohci1394.o.
-
-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
- direct communication of user programs to the IEEE 1394 bus.
-
- 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 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.
+ This driver provides support for the bidirectional parallel port
+ found on many Sun machines. Note that many of the newer Ultras
+ actually have pc style hardware instead.
#
# m68k-specific kernel options
@@ -13370,23 +14012,12 @@ CONFIG_HP300
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.
+ 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
- warned that this support is very experimental. You will also want to
- say Y to 68020 support and N to the other processors below.
- Currently, it is not possible to build a kernel with support for the
- Sun 3 and something else, so make sure you have said N to all the
- other machines. This option does not support the sun3x series of
- machines (the Sun 3/80 and 3/460). If you don't want to compile a
- kernel for a Sun 3, say N.
-
68020 support
CONFIG_M68020
If you anticipate running this kernel on a computer with a MC68020
@@ -13444,7 +14075,13 @@ 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
- you are doing. Most users should say N to this question.
+ you are doing.
+
+ 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 these options.
+
+ Most users should say N to this question.
Use read-modify-write instructions
CONFIG_RMW_INSNS
@@ -13465,8 +14102,9 @@ CONFIG_ZORRO
cards that obey the AutoConfig(tm) specification.
Say Y if you want your expansion cards to be identified on bootup;
it will enlarge your kernel by about 10 KB. The identification
- information is also available through /proc/zorro (say Y to
- "/proc file system support"!).
+ information is then also available through /proc/zorro (say Y to
+ "/proc file system support"!). Read Documentation/zorro.txt for more
+ information.
Note that even if you say N here, you can still use your expansion
cards. If in doubt, say Y.
@@ -13476,23 +14114,6 @@ CONFIG_AMIGA_PCMCIA
Include support in the kernel for pcmcia on Amiga 1200 and Amiga
600. If you intend to use pcmcia cards say Y; otherwise say N.
-Amiga GSP (TMS340x0) support
-CONFIG_AMIGA_GSP
- Include support for Amiga graphics cards that use the Texas
- Instruments TMS340x0 GSP (Graphics Signal Processor) chips. Say Y
- if you want to use a DMI Resolver or Commodore A2410 (Lowell)
- graphics card on an Amiga; otherwise, say N.
-
-DMI Resolver support
-CONFIG_GSP_RESOLVER
- Include support in the kernel for the DMI Resolver graphics card. If
- you have one, say Y; otherwise, say N.
-
-A2410 support
-CONFIG_GSP_A2410
- Include support in the kernel for the Commodore/University of Lowell
- A2410 graphics card. If you have one, say Y; otherwise, say N.
-
Amiga Zorro II ramdisk support
CONFIG_AMIGA_Z2RAM
This enables support for using Chip RAM and Zorro II RAM as a
@@ -13591,7 +14212,7 @@ CONFIG_CYBERSTORMII_SCSI
and the optional Cyberstorm SCSI controller, say Y. Otherwise,
answer N.
-Blizzard 2060 SCSI support
+Blizzard 2060 SCSI support (EXPERIMENTAL)
CONFIG_BLZ2060_SCSI
If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
and want to use the onboard SCSI controller, say Y. Otherwise,
@@ -13603,7 +14224,7 @@ CONFIG_BLZ1230_SCSI
1260 accelerator, and the optional SCSI module, say Y. Otherwise,
say N.
-Blizzard PowerUP 603e+ SCSI support (EXPERIMENTAL)
+Blizzard PowerUP 603e+ SCSI support
CONFIG_BLZ603EPLUS_SCSI
If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+
accelerator, say Y. Otherwise, say N.
@@ -13706,16 +14327,6 @@ CONFIG_ATARI_PAMSNET
ACSI port ("ACSI node"). The driver works (has to work...) with a
polled I/O scheme, so it's rather slow :-(
-Multiface Card III parallel support
-CONFIG_MULTIFACE_III_LP
- If you have a Multiface III card for your Amiga, and want to use its
- parallel port in Linux, say Y. Otherwise, say N.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module is called lp_m68k.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
-
Amiga mouse support
CONFIG_AMIGAMOUSE
If you want to be able to use an Amiga mouse in Linux, say Y.
@@ -13725,13 +14336,6 @@ CONFIG_AMIGAMOUSE
The module is called amigamouse.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
-Amiga Copper Console
-CONFIG_COPCON
- This configures the console to use the Amiga's graphics coprocessor
- for scrolling, instead of using the CPU. This option markedly
- improves response times in the high color modes (5 bitplanes and
- up). If you would like to use this, say Y; otherwise, say N.
-
Atari mouse support
CONFIG_ATARIMOUSE
If you want to be able to use an Atari mouse in Linux, say Y.
@@ -13821,12 +14425,44 @@ CONFIG_MULTIFACE_III_TTY
If you want to compile it as a module, say M here and read
Documentation/modules.txt.
-Amiga or Atari DMA sound support
-CONFIG_DMASOUND
- If you want to use the internal audio of your Atari or Amiga in
- Linux, answer Y to this question. This will provide a Sun-like
- /dev/audio, compatible with the Linux/i386 sound system. Otherwise,
- say N.
+Atari DMA sound support
+CONFIG_DMASOUND_ATARI
+ If you want to use the internal audio of your Atari in Linux, answer
+ Y to this question. This will provide a Sun-like /dev/audio,
+ compatible with the Linux/i386 sound system. Otherwise, say N.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you
+ want). If you want to compile it as a module, say M here and read
+ Documentation/modules.txt.
+
+PowerMac DMA sound support
+CONFIG_DMASOUND_AWACS
+ If you want to use the internal audio of your PowerMac in Linux,
+ answer Y to this question. This will provide a Sun-like /dev/audio,
+ compatible with the Linux/i386 sound system. Otherwise, say N.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you
+ want). If you want to compile it as a module, say M here and read
+ Documentation/modules.txt.
+
+Amiga DMA sound support
+CONFIG_DMASOUND_PAULA
+ If you want to use the internal audio of your Amiga in Linux, answer
+ Y to this question. This will provide a Sun-like /dev/audio,
+ compatible with the Linux/i386 sound system. Otherwise, say N.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you
+ want). If you want to compile it as a module, say M here and read
+ Documentation/modules.txt.
+
+Q40 sound support
+CONFIG_DMASOUND_Q40
+ If you want to use the internal audio of your Q40 in Linux, answer
+ Y to this question. This will provide a Sun-like /dev/audio,
+ compatible with the Linux/i386 sound system. Otherwise, say N.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you
@@ -13843,11 +14479,6 @@ CONFIG_HPLANCE
If you want to use the builtin "LANCE" Ethernet controller on an
HP300 machine, say Y here.
-Sun 3 onboard LANCE support
-CONFIG_SUN3LANCE
- If you want to use the onboard AMD "LANCE" (le) Ethernet hardware
- on a Sun 3, you will need to say Y here.
-
DIO bus support
CONFIG_DIO
Say Y here to enable support for the "DIO" expansion bus used in
@@ -13857,10 +14488,10 @@ CONFIG_DIO
Processor Type
CONFIG_6xx
There are three types of PowerPC chips supported. The more common
- types (601, 603, 604, 740, 750), the Motorola embedded versions (821,
- 823, 850, 855, 860), and the IBM embedded versions (403 and 405).
- Unless you are building a kernel for one of the embedded processor
- systems, choose 6xx.
+ types (601, 603, 604, 740, 750), the Motorola embedded versions
+ (821, 823, 850, 855, 860), and the IBM embedded versions (403 and
+ 405). Unless you are building a kernel for one of the embedded
+ processor systems, choose 6xx.
Machine Type
CONFIG_PMAC
@@ -13932,6 +14563,35 @@ CONFIG_BMAC
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
+GMAC (G4/iBook ethernet) support
+CONFIG_GMAC
+ Say Y for support of GMAC Ethernet interfaces. These are used on G4
+ and iBook computers.
+
+ This driver is also available as a module called gmac.o ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). If you want to compile it as a module, say M
+ here and read Documentation/modules.txt.
+
+Symbios 53c885 (Synergy ethernet) support
+CONFIG_NCR885E
+ This is and Ethernet driver for the dual-function NCR 53C885
+ SCSI/Ethernet controller.
+
+ This driver is also available as a module called ncr885e.o ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). If you want to compile it as a module, say M
+ here and read Documentation/modules.txt.
+
+National DP83902AV (Oak ethernet) support
+CONFIG_OAKNET
+ Say Y if your machine has this type of Ethernet network card.
+
+ This driver is also available as a module called oaknet.o ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). If you want to compile it as a module, say M
+ here and read Documentation/modules.txt.
+
Video For Linux
CONFIG_VIDEO_DEV
Support for audio/video capture and overlay devices and FM radio
@@ -14037,10 +14697,6 @@ CONFIG_RADIO_CADET
say M here and read Documentation/modules.txt. The module will be
called radio-cadet.o.
-ADS Cadet AM/FM Radio Tuner Card I/O Port
-CONFIG_RADIO_CADET_PORT
- Enter the I/O address of the card here (most commonly 330).
-
SF16FMI Radio
CONFIG_RADIO_SF16FMI
Choose Y here if you have one of these FM radio cards, and then fill
@@ -14160,7 +14816,9 @@ CONFIG_RADIO_GEMTEK
GemTek i/o port
CONFIG_RADIO_GEMTEK_PORT
Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
- 0x34c, if you haven't changed the jumper setting on the card.
+ 0x34c, if you haven't changed the jumper setting on the card. On
+ Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the i/o
+ port is 0x28c.
PlanB Video-In for PowerMacs
CONFIG_VIDEO_PLANB
@@ -14179,34 +14837,56 @@ CONFIG_RADIO_TERRATEC
Note: This driver is in its early stages. Right now volume and
frequency control and muting works at least for me, but
unfortunately i have not found anybody who wants to use this card
- with linux. So if it is this what YOU are trying to do right now,
+ with Linux. So if it is this what YOU are trying to do right now,
PLEASE DROP ME A NOTE!! Rolf Offermanns (rolf@offermanns.de)
In order to control your radio card, you will need to use programs
that are compatible with the Video for Linux API. Information on
this API and pointers to "v4l" programs may be found on the WWW at
- http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
- you need to have access to a machine on the Internet that has a
- program like lynx or netscape.
+ http://roadrunner.swansea.uk.linux.org/v4l.shtml .
If you want to compile this driver 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 radio-terratec.o.
+Terratec i/o port (normally 0x590)
+CONFIG_RADIO_TERRATEC_PORT
+ Fill in the i/o port of your TerraTec FM radio card. If unsure, go
+ with the default.
+
+### Add these
# Zoran ZR36057/36060 support
# CONFIG_VIDEO_ZORAN
# Include support for Iomega Buz
# CONFIG_VIDEO_BUZ
+Trust FM radio card
+CONFIG_RADIO_TRUST
+ This is a driver for the Trust FM radio cards. Say Y if you have
+ such a card and want to use it under Linux.
+
+ This driver is also available as a module called radio-trust.o ( =
+ code which can be inserted in and removed from the running kernel
+ whenever you want). If you want to compile it as a module, say M
+ here and read Documentation/modules.txt.
+
+Trust i/o port (usually 0x350 or 0x358)
+CONFIG_RADIO_TRUST_PORT
+ Enter the i/o port of your Trust FM radio card. If unsure, try the
+ values "0x350" or "0x358".
+
BT848 Video For Linux
CONFIG_VIDEO_BT848
Support for BT848 based frame grabber/overlay boards. This includes
the Miro, Hauppauge and STB boards. Please read the material in
Documentation/video4linux/bttv for more information.
- This driver is also available as a module called bttv.o ( = code
+ If you say Y or M here, you need to say Y or M to "I2C support" and
+ "I2C bit-banging interfaces" in the character device section.
+
+ This driver is available as a module called bttv.o ( = code
which can be inserted in and removed from the running kernel
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
@@ -14245,11 +14925,12 @@ CONFIG_VIDEO_BWQCAM
Colour QuickCam Video For Linux
CONFIG_VIDEO_CQCAM
- This is the video4linux driver for the color version of the
+ This is the video4linux driver for the colour version of the
Connectix Quickcam. If you have one of these cameras, say Y here,
otherwise say N. This driver does not work with the original
monochrome Quickcam, Quickcam VC or QuickClip. It is also available
- as a module (c-qcam.o).
+ as a module (c-qcam.o). Read Documentation/video4linux/CQcam.txt for
+ more information.
Mediavision Pro Movie Studio Video For Linux
CONFIG_VIDEO_PMS
@@ -14266,114 +14947,9 @@ CONFIG_BLK_CPQ_DA
boards supported by this driver, and for further information
on the use of this driver.
-QuickNet Internet LineJack/PhoneJack support
-CONFIG_PHONE_IXJ
- Say M if you have a telephony card manufactured by Quicknet
- Technologies, Inc. These include the Internet PhoneJACK and
- Internet LineJACK Telephony Cards.
-
- For the ISA versions of these products, you can configure the
- cards using the isapnp tools (pnpdump/isapnp) or you can use the
- isapnp support. Please read:
-
- /usr/src/linux/Documentation/telephony/ixj.txt.
-
- For more information on these cards, see Quicknet's website at:
- http://www.quicknet.net/
-
- If you do not have any Quicknet telephony cards, you can safely
- ignore this option.
-
-/dev/agpgart (AGP Support) (EXPERIMENTAL)
-CONFIG_AGP
- The agpgart kernel module is necessary to use the AGP features
- of your 3D rendering video card. It acts as a sort of "AGP
- driver" for the motherboard's chipset.
- Loading this module into the kernel will allow the glx module to
- program the GART (graphics aperture relocation table) registers
- with appropriate values to transfer commands to the card.
-
- If you need more texture memory than you can get with the AGP GART
- (theoretically up to 256 megs, but in practice usually 64 or 128
- megs due to kernel allocation issues), you could use PCI accesses
- and have up to a couple gigs of texture space.
-
- Note that this is the only mean to have get XFree4/GLX use
- write-combining with MTRR support on AGP bus. Without, OpenGL
- direct rendering will be a lot slower but still faster than PIO.
-
- For the moment, most people should say no, unless you want to
- test the GLX component which can be downloaded from
- http://glx.on.openprojects.net/
-
- or need to use the 810 Xserver in XFree 3.3.6
-
-Intel 440LX/BX/GX support
-CONFIG_AGP_INTEL
- This option give you AGP support for the GLX component of the
- "soon to be released" XFree86-4 on Intel 440LX/BX/GX chipsets.
-
- For the moment, most people should say no, unless you want to
- test the GLX component which can be downloaded from
- http://glx.on.openprojects.net/
-
-Intel I810/I810 DC100/I810e support
-CONFIG_AGP_I810
- This option give you AGP support for the Xserver for the intel
- 810 chipset boards. This is required to do any useful video
- modes.
-
-VIA VP3/MVP3/Apollo Pro support
-CONFIG_AGP_VIA
- This option give you AGP support for the GLX component of the
- "soon to be released" XFree86-4 on VIA MPV3/Apollo Pro chipsets.
-
- For the moment, most people should say no, unless you want to
- test the GLX component which can be downloaded from
- http://glx.on.openprojects.net/
-
-AMD Irongate support
-CONFIG_AGP_AMD
- This option give you AGP support for the GLX component of the
- "soon to be released" XFree86-4 on Intel AMD Irongate chipset.
-
- For the moment, most people should say no, unless you want to
- test the GLX component which can be downloaded from
- http://glx.on.openprojects.net/
-
-Generic SiS support
-CONFIG_AGP_SIS
- This option give you AGP support for the GLX component of the
- "soon to be released" XFree86-4 on Silicon Integrated Systems [SiS]
- chipsets.
-
- Note than 5591/5592 AGP chipsets are NOT supported.
-
- For the moment, most people should say no, unless you want to
- test the GLX component which can be downloaded from
- http://glx.on.openprojects.net/
-
-ALI M1541 support
-CONFIG_AGP_ALI
- This option give you AGP support for the GLX component of the
- "soon to be released" XFree86-4 on ALI M1541 chipset.
-
- For the moment, most people should say no, unless you want to
- test the GLX component which can be downloaded from
- http://glx.on.openprojects.net/
-
#
# ARM options
#
-CPU Optimization
-CONFIG_CPU_ARM2
- This selects the processor type of your CPU. This is only used to
- determine C compiler optimization options, and can affect the
- compatibility of the kernel on other processors. If you specify
- ARM6, the kernel should work on all 32-bit processors. If you
- specify ARM2, ARM250 or ARM3, it should work on all 26-bit
- processors. If you're not sure, set it to "None".
-
ARM System type
CONFIG_ARCH_ARC
This selects what ARM system you wish to build the kernel for. It
@@ -14381,14 +14957,6 @@ CONFIG_ARCH_ARC
to set this option to, please consult any information supplied with
your system.
-Include support for Chalice CATS boards
-CONFIG_CATS
- Say Y here if you intend to run this kernel on a CATS system.
-
-Include support for Intel EBSA285
-CONFIG_ARCH_EBSA285
- board.
-
Include support for the NetWinder
CONFIG_ARCH_NETWINDER
Say Y here if you intend to run this kernel on the NetWinder.
@@ -14412,7 +14980,7 @@ CONFIG_NWFPE
Say Y to include the NWFPE floating point emulator in the kernel.
This is necessary to run most binaries. Linux does not currently
support floating point hardware so you need to say Y here even if
- your machine has an FPA or floating point co-processor module.
+ your machine has an FPA or floating point co-processor podule.
It is also possible to say M to build the emulator as a module
(nwfpe.o) or indeed to leave it out altogether. However, unless you
@@ -14441,12 +15009,6 @@ CONFIG_DEBUG_ERRORS
you are concerned with the code size or don't want to see these
messages.
-Build Tools Selection
-CONFIG_BINUTILS_NEW
- Say Y here if and only if you're using GCC 2.8.1/EGCS with a
- binutils version >= 2.8.1 to compile the kernel (check with "gcc
- --version" and "ld -v").
-
Compile kernel with frame pointer
CONFIG_FRAME_POINTER
If you say Y here, the resulting kernel will be slightly larger and
@@ -14469,12 +15031,12 @@ CONFIG_DEBUG_INFO
time and disk space needed for compilation of the kernel. If in
doubt say N.
-Split initialization functions into discardable section
+Split initialisation functions into discardable section
CONFIG_TEXT_SECTIONS
If you say Y here, kernel code that is only used during
- initialization is collected into a special area of the kernel so
+ initialisation is collected into a special area of the kernel so
that it can be discarded and the memory reclaimed when
- initialization is complete. In addition, if the kernel you wish to
+ initialisation is complete. In addition, if the kernel you wish to
build is able to run on multiple architectures, it allows the unused
code to be discarded. Some versions of binutils, however, have a bug
that causes the kernel to crash during startup when this option is
@@ -14535,7 +15097,7 @@ CONFIG_HOST_FOOTBRIDGE
MFM hard disk support
CONFIG_BLK_DEV_MFM
Support the MFM hard drives on the Acorn Archimedes both
- on-board the A4x0 motherboards and via the Acorn MFM modules.
+ on-board the A4x0 motherboards and via the Acorn MFM podules.
Drives up to 64MB are supported. If you haven't got one of these
machines or drives just say N.
@@ -14553,7 +15115,7 @@ CONFIG_BLK_DEV_MFM_AUTODETECT
sometimes doesn't work and it also does some dodgy stuff which
potentially might damage your drive.
-IrDA Protocols
+IrDA subsystem support
CONFIG_IRDA
Say Y here if you want to build support for the IrDA (TM) protocols.
The Infrared Data Associations (tm) specifies standards for wireless
@@ -14565,8 +15127,9 @@ CONFIG_IRDA
Documentation/networking/irda.txt. You also want to read the
IR-HOWTO, available at http://www.linuxdoc.org/docs.html#howto .
- This support is also available as a module. If you want to compile
- it as a module, say M here and read Documentation/modules.txt.
+ This support is also available as a module called irda.o. If you
+ want to compile it as a module, say M here and read
+ Documentation/modules.txt.
IrDA Cache last LSAP
CONFIG_IRDA_CACHE_LAST_LSAP
@@ -14623,7 +15186,7 @@ CONFIG_IRDA_DEFLATE
IrLAN Protocol
CONFIG_IRLAN
Say Y here if you want to build support for the IrLAN protocol. If
- you want to compile it as a module, say M here and read
+ you want to compile it as a module (irlan.o), say M here and read
Documentation/modules.txt. IrLAN emulates an Ethernet and makes it
possible to put up a wireless LAN using infrared beams.
@@ -14635,19 +15198,20 @@ CONFIG_IRLAN
IrCOMM Protocol
CONFIG_IRCOMM
Say Y here if you want to build support for the IrCOMM protocol. If
- you want to compile it as a module, say M here and read
- Documentation/modules.txt. IrCOMM implements serial port emulation,
- and makes it possible to use all existing applications that
- understands TTY's with an infrared link. Thus you should be able to
- use application like PPP, minicom and others. Enabling this option
- will create two modules called ircomm and ircomm-tty.
+ you want to compile it as a module (you will get ircomm.o and
+ ircomm-tty.o), say M here and read Documentation/modules.txt. IrCOMM
+ implements serial port emulation, and makes it possible to use all
+ existing applications that understands TTY's with an infrared link.
+ Thus you should be able to use application like PPP, minicom and
+ others. Enabling this option will create two modules called ircomm
+ and ircomm_tty.
IrTTY IrDA Device Driver
CONFIG_IRTTY_SIR
Say Y here if you want to build support for the IrTTY line
- discipline. If you want to compile it as a module, say M here and
- read Documentation/modules.txt. IrTTY makes it possible to use
- Linux's own serial driver for all IrDA ports that are 16550
+ discipline. If you want to compile it as a module (irtty.o), say M
+ here and read Documentation/modules.txt. IrTTY makes it possible to
+ use Linux's own serial driver for all IrDA ports that are 16550
compatible. Most IrDA chips are 16550 compatible so you should
probably say Y to this option. Using IrTTY will however limit the
speed of the connection to 115200 bps (IrDA SIR mode)
@@ -14657,50 +15221,62 @@ CONFIG_IRTTY_SIR
IrPORT IrDA Device Driver
CONFIG_IRPORT_SIR
Say Y here if you want to build support for the IrPORT IrDA device
- driver. If you want to compile it as a module, say M here and
- read Documentation/modules.txt. IrPORT can be used instead of
- IrTTY and sometimes this can be better. One example is if your
- IrDA port does not have echo-canceling, which will work OK with
- IrPORT since this driver is working in half-duplex mode only. You
- don't need to use irattach with IrPORT, but you just insert it
- the same way as FIR drivers (insmod irport io=0x3e8 irq=11).
- Notice that IrPORT is a SIR device driver which means that speed
- is limited to 115200 bps.
+ driver. If you want to compile it as a module (irport.o), say M here
+ and read Documentation/modules.txt. IrPORT can be used instead of
+ IrTTY and sometimes this can be better. One example is if your IrDA
+ port does not have echo-canceling, which will work OK with IrPORT
+ since this driver is working in half-duplex mode only. You don't
+ need to use irattach with IrPORT, but you just insert it the same
+ way as FIR drivers (insmod irport io=0x3e8 irq=11). Notice that
+ IrPORT is a SIR device driver which means that speed is limited to
+ 115200 bps.
If unsure, say Y.
-SiS5513 chipset support
-CONFIG_BLK_DEV_SIS5513
- This driver ensures (U)DMA support for SIS5513 chipset based
- mainboards. SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all
- other DMA mode 2 limited chipsets are unsupported to date.
-
- If you say Y here, you need to say Y to "Use DMA by default when
- available" as well.
-
- Please read the comments at the top of drivers/block/sis5513.c
-
Winbond W83977AF IrDA Device Driver
CONFIG_WINBOND_FIR
Say Y here if you want to build IrDA support for the Winbond
- W83977AF super-io chipset. If you want to compile it as a module,
- say M here and read Documentation/modules.txt. This driver should be
- used for the IrDA chipset in the Corel NetWinder. The driver
- supports SIR, MIR and FIR (4Mbps) speeds.
+ W83977AF super-io chipset. This driver should be used for the IrDA
+ chipset in the Corel NetWinder. The driver supports SIR, MIR and FIR
+ (4Mbps) speeds.
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. The module will be called w83977af_ir.o.
NSC PC87108 IrDA Device Driver
CONFIG_NSC_FIR
Say Y here if you want to build support for the NSC PC87108 and
- PC87338 IrDA chipsets. If you want to compile it as a module, say M
- here and read Documentation/modules.txt. This driver supports SIR,
- MIR and FIR (4Mbps) speeds.
+ PC87338 IrDA chipsets. This driver supports SIR,
+ MIR and FIR (4Mbps) speeds.
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. The module will be called nsc-ircc.o.
Toshiba Type-O IR Port Device Driver
CONFIG_TOSHIBA_FIR
Say Y here if you want to build support for the Toshiba Type-O IR
- chipset. If you want to compile it as a module, say M here and
- read Documentation/modules.txt. This chipset is used by the Toshiba
- Libretto 100CT, and many more laptops.
+ chipset. This chipset is used by the Toshiba Libretto 100CT, and
+ many more laptops. If you want to compile it as a module, say M here
+ and read Documentation/modules.txt. The module will be called
+ toshoboe.o.
+
+SMC IrCC (Experimental)
+CONFIG_SMC_IRCC_FIR
+ Say Y here if you want to build support for the SMC Infrared
+ Communications Controller. It is used in the Fujitsu Lifebook 635t
+ and Sony PCG-505TX. If you want to compile it as a module, say M
+ here and read Documentation/modules.txt. The module will be called
+ smc-ircc.o.
+
+Serial dongle support
+CONFIG_DONGLE
+ Say Y here if you have an infrared device that connects to your
+ computer's serial port. These devices are called dongles. Then say Y
+ or M to the driver for your particular dongle below.
+
+ 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 serial dongles.
ESI JetEye PC Dongle
CONFIG_ESI_DONGLE
@@ -14748,6 +15324,14 @@ CONFIG_LITELINK_DONGLE
by IrTTY. To activate support for Parallax dongles you will have to
start irattach like this "irattach -d litelink".
+Old Belkin dongle
+CONFIG_OLD_BELKIN_DONGLE
+ Say Y here if you want to build support for the Adaptec Airport 1000
+ and 2000 dongles. If you want to compile it as a module, say M here
+ and read Documentation/modules.txt. The module will be called
+ old_belkin.o. Some information is contained in the comments at the
+ top of drivers/net/irda/old_belkin.c.
+
VME (Motorola and BVM) support
CONFIG_VME
Say Y here if you want to build a kernel for a 680x0 based VME
@@ -14795,13 +15379,6 @@ CONFIG_BVME6000_SCSI
SCSI controller chip. Almost everyone using one of these boards
will want to say Y to this question.
-Simple 53c710 SCSI support (Compaq, NCR machines)
-CONFIG_SCSI_SIM710
- This is a driver for the NCR53C710 chip commonly found in Compaq and
- NCR machines. If you are looking for 53C710 support for an Amiga or
- some 680x0 based VME card then you probably want the other NCR53C710
- driver.
-
MVME16x Ethernet support
CONFIG_MVME16x_NET
This is the driver for the Ethernet interface on the Motorola
@@ -14916,6 +15493,31 @@ CONFIG_I2C_CHARDEV
files, usually found in the /dev directory on your system. They
make it possible to have user-space programs use the I2C bus.
+CPiA Video For Linux
+CONFIG_VIDEO_CPIA
+ This is the video4linux driver for cameras based on Vision's CPiA
+ (Colour Processor Interface ASIC), such as the Creative Labs Video
+ Blaster Webcam II. If you have one of these cameras, say Y here
+ and select parallel port and/or USB lowlevel support below,
+ otherwise say N. This will not work with the Creative Webcam III.
+ It is also available as a module (cpia.o).
+
+CPiA Parallel Port Lowlevel Support
+CONFIG_VIDEO_CPIA_PP
+ This is the lowlevel parallel port support for cameras based on
+ Vision's CPiA (Colour Processor Interface ASIC), such as the
+ Creative Webcam II. If you have the parallel port version of one
+ of these cameras, say Y here, otherwise say N. It is also available
+ as a module (cpia_pp.o).
+
+CPiA USB Lowlevel Support
+CONFIG_VIDEO_CPIA_USB
+ This is the lowlevel USB support for cameras based on Vision's CPiA
+ (Colour Processor Interface ASIC), such as the Creative Webcam II.
+ If you have the USB version of one of these cameras, say Y here,
+ otherwise say N. This will not work with the Creative Webcam III.
+ It is also available as a module (cpia_usb.o).
+
#
# A couple of things I keep forgetting:
# capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
@@ -14930,7 +15532,7 @@ CONFIG_I2C_CHARDEV
# LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab
# LocalWords: unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz
# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd
-# LocalWords: HD CDROMs IDECD NEC MITSUMI XT XD PCI BIOS cezar ATEN
+# LocalWords: HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN
# LocalWords: ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt
# LocalWords: BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB
# LocalWords: netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP
@@ -14960,11 +15562,11 @@ CONFIG_I2C_CHARDEV
# LocalWords: readprofile diskdrives org com masq EtherTalk tcp netrom sunacm
# LocalWords: misc AIC aic pio scc Portmaster eql GIS PhotoCDs MCDX Perell PG
# LocalWords: mcdx gscd optcd sjcd ISP hdparm Workgroups Lan samba PARIDE PCD
-# LocalWords: smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI
+# LocalWords: filesystems smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI
# LocalWords: chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport
# LocalWords: Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
# LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
-# LocalWords: carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP
+# LocalWords: carleton DECstation SUNFD JENSEN Noname XXXM SLiRP LILO's amifb
# LocalWords: pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd
# LocalWords: RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
# LocalWords: dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
@@ -14977,12 +15579,13 @@ CONFIG_I2C_CHARDEV
# LocalWords: PMAX MILO Alphas Multia Tseng linuxelf endian mipsel mips drv HT
# LocalWords: kerneld callouts AdvanSys advansys Admin WDT DataStor EP verden
# LocalWords: wdt hdb hdc bugfix SiS vlb Acculogic CSA DTC dtc Holtek ht QDI
-# LocalWords: QD qd UMC umc ALI ali oss sgi com azstarnet cdr fb MDA ps esdi
+# LocalWords: QD qd UMC umc ALI ali lena fnet fr azstarnet cdr fb MDA ps esdi
# LocalWords: Avanti XL AlphaStations Jensen DECpc AXPpci UDB Cabriolet MCA RC
# LocalWords: AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm
# LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT
# LocalWords: OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP
-# LocalWords: NOWAYOUT behavior dialin isdn callback BTX Teles ICN EDSS Cisco
+# LocalWords: NOWAYOUT behaviour dialin isdn callback BTX Teles XXXX LVM lvm
+ICN EDSS Cisco
# LocalWords: ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
# LocalWords: ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
# LocalWords: initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
@@ -15052,12 +15655,12 @@ CONFIG_I2C_CHARDEV
# LocalWords: caldera Preload Preloading slowdowns schoebel uni NBD nbd prog
# LocalWords: stuttgart rdist TRANS hostnames mango jukeboxes ESS userland PD
# LocalWords: hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid
-# LocalWords: transname filespace adm Nodename hostname uname Kernelname bootp
+# LocalWords: filespace adm Nodename hostname uname Kernelname bootp nmi DI OV
# LocalWords: KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb
# LocalWords: dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS
# LocalWords: nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
-# LocalWords: Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs HIGHMEM DAC IRQ's
-# LocalWords: IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu
+# LocalWords: Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs BIGMEM DAC IRQ's
+# LocalWords: IDEPCI IDEDMA PDC pdc TRM trm raidtools luthien nuclecu BAGET VR
# LocalWords: unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS
# LocalWords: BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE
# LocalWords: misconfigured autoconfiguration IPGRE ICMP tracert ipautofw PIM
@@ -15073,7 +15676,7 @@ CONFIG_I2C_CHARDEV
# LocalWords: Braam braam Schmidt's freiburg nls codepages codepage Romanian
# LocalWords: Slovak Slovenian Sorbian Nordic iso Catalan Faeroese Galician SZ
# LocalWords: Valencian Slovene Esperanto Estonian Latvian Byelorussian KOI mt
-# LocalWords: charset Inuit Greenlandic Sami Lappish koi SOFTCURSOR softcursor
+# LocalWords: charset Inuit Greenlandic Sami Lappish koi Alexey Kuznetsov's sa
# LocalWords: Specialix specialix DTR RTS RTSCTS cycladesZ Exabyte ftape's inr
# LocalWords: Iomega's LBFM claus ZFTAPE VFS zftape zft William's lzrw DFLT kb
# LocalWords: MTSETBLK MTIOCTOP qft setblk zftape's tar's afio's setdrvbuffer
@@ -15087,7 +15690,7 @@ CONFIG_I2C_CHARDEV
# LocalWords: struct APIC realtime OSs LynxOS CNC tmp cvf HFS hfs ADFS Risc os
# LocalWords: adfs ncpmount namespace SUBDIR reexport NDS kcore FT SPX spx DAT
# LocalWords: interserver BLKSZ NUMBUFFERS apmd Tadpole ANA roestock QuickCam
-# LocalWords: isapnptools Colour CQCAM color Connectix QuickClip prive mentre
+# LocalWords: isapnptools Colour CQCAM colour Connectix QuickClip prive mentre
# LocalWords: KMOD kmod conformant utexas kharker UnixWare Mwave cgi cl ts ibm
# LocalWords: eXchange threepio oakland simtel pre ULTRAMCA EtherLink isa luik
# LocalWords: EtherLink OpenBSD pts DEVPTS devpts ptmx ttyp glibc readback SA
@@ -15103,8 +15706,8 @@ CONFIG_I2C_CHARDEV
# LocalWords: Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs
# LocalWords: EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson CT
# LocalWords: SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT CFB DSY kbps
-# LocalWords: tuwien kkudielk LVD mega lun MAXTAGS Gbps arcnet Olicom SKTR SNA
-# LocalWords: SysKonnect tms380tr sna etherboot ufs NetBEUI MultiSound MSNDCLAS GX
+# LocalWords: tuwien kkudielk LVD mega lun MAXTAGS Gbps arcnet Olicom SNA PAE
+# LocalWords: SysKonnect tms sna etherboot ufs NetBEUI MultiSound MSNDCLAS GX
# LocalWords: MSNDINIT MSNDPERM MSNDPIN PNDSPINI PNDSPERM Ensoniq's RetinaZ SS
# LocalWords: AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA
# LocalWords: swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs
@@ -15141,7 +15744,7 @@ CONFIG_I2C_CHARDEV
# LocalWords: ACTiSYS Dongle dongle dongles esi actisys IrMate tekram BVM MVME
# LocalWords: BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu
# LocalWords: alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid
-# LocalWords: QNX4FS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
+# LocalWords: QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
# LocalWords: IrLPT UIRCC Tecra Strebel jstrebel suse Eichwalder ke INI INIA
# LocalWords: FCP qlogicfc sym isapnp DTLK DoubleTalk rcsys dtlk DMAP SGIVW ar
# LocalWords: dmabuf EcoRadio MUTEFREQ GIrBIL girbil tepkom vol mha diplom PQS
@@ -15151,7 +15754,7 @@ CONFIG_I2C_CHARDEV
# LocalWords: VROOTHUB KBD ARRs MCRs NWBUTTON nwbutton NUM WaveArtist APNE cpu
# LocalWords: apne blackhawke PlanB lu mlan planb NWFPE FPA nwfpe unbootable
# LocalWords: FPEmulator ds vmlinux initialisation discardable pgtable PGT mdw
-# LocalWords: quicklist pagetable arthur StrongARM module modules Autodetect
+# LocalWords: quicklist pagetable arthur StrongARM podule podules Autodetect
# LocalWords: dodgy IrPORT irport Litelink litelink SuSE rtfm internet hda CY
# LocalWords: multmode DriveReady SeekComplete DriveStatusError miscompile AEC
# LocalWords: mainboard's Digital's alim FastTrak aec PIIXn piix Gayle Eyetech
@@ -15173,9 +15776,56 @@ CONFIG_I2C_CHARDEV
# LocalWords: ServeRAID IPS ips ipslinux gzip BSDCOMP LZW RAYCS Interphase app
# LocalWords: Tachyon IPHASE Surfboard NextLevel SURFboard jacksonville Tigon
# LocalWords: fventuri adelphia siglercm linuxpower AceNICs Starfire starfire
-# LocalWords: ISOC CPiA cpia uss ACPI UDF DirectCD udf CDRW's OSF Manx acpi
+# LocalWords: ISOC CPiA cpia uss ACPI UDF DirectCD udf CDRW's OSF Manx acpi DM
# LocalWords: Unixware cymru Computone IntelliPort Intelliport computone SI sx
# LocalWords: adbmouse DRI DRM dlabs GMX PLCs Applicom fieldbus applicom int
# LocalWords: VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU
-# LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator
-# LocalWords: LOGIBUSMOUSE OV511 ov511 Integraphics
+# LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator SBNI tw
+# LocalWords: LOGIBUSMOUSE Granch granch sbni Raylink NOHIGHMEM Athlon SIM sim
+# LocalWords: hpl Tourrilhes DuraLAN starfile Davicom davicom dmfe auk tms tr
+# LocalWords: TokenExpress Belkin Peracom eTek DVDs infradead Cxxx Adlib AV ZX
+# LocalWords: NeoMagic CPi CPt Celeron decapsulation Undeletion BFS bfs nVidia
+# LocalWords: OnStream Irongate Riva phonedev QuickNet LineJack PhoneJack IXJ
+# LocalWords: Quicknet PhoneJACK LineJACK ixj pnpdump Quicknet's Joandi SSID
+# LocalWords: aironet quickconfig adhoc btw bap NONCS cardservices Xircom lin
+# LocalWords: Netwave AirSurfer netwave HomePNA failover MVP iMacs ALi aktual
+# LocalWords: Aladin HIDBP usbkbd KEYBDEV MOUSEDEV JOYDEV EVDEV UAB WhiteHEAT
+# LocalWords: Handspring ov DABUSB URB URB's dabusb CRAMFS NFSv ELV IOAPIC WIP
+# LocalWords: NLMv SMBus ALGOBIT algo PHILIPSPAR philips elv Velleman velleman
+# LocalWords: ALGOPCF Elektor elektor CHARDEV dfx TDFX tdfx Extensa dof gravis
+# LocalWords: assasin logitech Overdrive thrustmaster DWave Aureal magellan db
+# LocalWords: SpaceTec SpaceOrb SpaceBall spaceorb FLX spaceball turbografx zr
+# LocalWords: amiga ESS's WaveWatcher Maxi belkin RW's ata glx GART MPV Baget
+# LocalWords: OpenGL Xserver agpgart HOTPLUG CyberPro Integraphics Netwinder
+# LocalWords: aty FONTWIDTH eni zatm nicstar ForeRunner OC DECstations DEC's
+# LocalWords: PHYsical SUNI reinsertion ChipSAR KVC PHY ClassID iphase iadbg
+# LocalWords: DEVS FireWire PCILynx pcilynx LOCALRAM miro's DV RAWIO GRED Mk
+# LocalWords: Diffserv DSMARK Ingress Qdisc TCINDEX TMSPCI tmspci Ringode JE
+# LocalWords: MADGEMC madgemc TokenRing SMCTR TokenCard smctr Wacom Graphire
+# LocalWords: WMFORCE mousedev ConnectTech HandSpring Xirlink IBMCAM ibmcam SN
+# LocalWords: DEVICEFS yyy userspace Cymraeg Dwave SIMM JSFLASH JavaStation's
+# LocalWords: nsc ircc DDB Vrc CMN TB PROMs Vino rivafb DDC Matroxes MGA TVO
+# LocalWords: MAVEN fbdev crtc maven matroxset NTSC PCA SBA AAL SKFP DAS SAS
+# LocalWords: skfp Intuos ADMtek's pegasus PLUSB plusb pointopoint mp rio Xeon
+# LocalWords: DEVFS devfs dd bs EDSS german TELESPCI FRITZPCI HFC HFCS BDS HST
+# LocalWords: ISURF ISAR Saphir HSTSAPHIR Telekom BKM Scitel Quadro SCT Gazel
+# LocalWords: SP PRI Hypercope HYSDN Hypercope's hysdn IbssJoinNetTimeout FTDI
+# LocalWords: ARCNet Keyspan PDA ADMtek sgalaxy sgbase opl mpuio mpuirq sbio
+# LocalWords: sbirq sbdma gus uart mssio mssirq mssdma sscape maui mouirq iph
+# LocalWords: CHDLC UPS's usbmouse wacom wmforce keybdev joydev fibre Trunking
+# LocalWords: Etherchannel IOC Moxa Intellio moxa SmartIO mxser Mixcom EFI ir
+# LocalWords: MIXCOMWD mixcomwd SENDCOMPLETE GMAC iBook gmac OAKNET oaknet PCG
+# LocalWords: diffserv irlan irtty toshoboe IrCC Lifebook idex AUTODMA FIP Cxx
+# LocalWords: Yenta Databook TCIC FMVJ fmvj NMCLAN LiveWire nmclan XIRC xirc
+# LocalWords: loadkeys setfont shm SuperIO soc SOCAL socal FCAL fc fcal COMX
+# LocalWords: MultiGate ITConsult comx CMX HiCOMX downloadable hw LoCOMX PROTO
+# LocalWords: locomx MixCOM mixcom proto MyriCOM MYRI Sbus myri sbus IBMLS hme
+# LocalWords: lanstreamer baseT HAPPYMEAL qfe sunhme SUNLANCE sunlance BigMAC
+# LocalWords: SUNBMAC sunbmac QuadEthernet SUNQE qe FastEthernet sunqe DSB PTI
+# LocalWords: DSBR dsbr procinfo QLOGICPTI qpti ptisp QLGC qlogicpti se LBA NF
+# LocalWords: OPENPROMFS OpenPROM openpromfs OBP OpenBoot flashable Multiboard
+# LocalWords: SPARCAUDIO SparcClassic Ultras DBRI Sparcbook sparcaudio SUNBPP
+# LocalWords: UltraDMA WDC CRC CONNTRACK IPTABLES iptables nfmark interface's
+# LocalWords: tdfxfb TNTx HGA hgafb VERBOSEDEBUG SunTrunking SunSoft XIRTULIP
+# LocalWords: ethercards PNIC Macronix MXIC ASIX xircom Mustek MDC gphoto mdc
+# LocalWords: CramFs Cramfs uid cramfs AVM's kernelcapi PCIV
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 368f037f7..1b1ce265b 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -1,7 +1,14 @@
-BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml kernel-api.sgml
-
+BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml kernel-api.sgml parportbook.sgml
+
+PS := $(patsubst %.sgml, %.ps, $(BOOKS))
+PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
+
books: docproc $(BOOKS)
+ps: $(PS)
+
+pdf: $(PDF)
+
docproc:
$(MAKE) -C $(TOPDIR)/scripts docproc
@@ -36,11 +43,32 @@ kernel-api.sgml: kernel-api.tmpl
$(TOPDIR)/drivers/net/wan/syncppp.c \
$(TOPDIR)/drivers/net/wan/z85230.c \
$(TOPDIR)/kernel/pm.c \
+ $(TOPDIR)/kernel/ksyms.c \
+ $(TOPDIR)/net/netsyms.c \
<kernel-api.tmpl >kernel-api.sgml
+parportbook.sgml: parportbook.tmpl
+ $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/parport/init.c \
+ <parportbook.tmpl >parportbook.sgml
+
+DVI := $(patsubst %.sgml, %.dvi, $(BOOKS))
+AUX := $(patsubst %.sgml, %.aux, $(BOOKS))
+TEX := $(patsubst %.sgml, %.tex, $(BOOKS))
+LOG := $(patsubst %.sgml, %.log, $(BOOKS))
+
clean:
- rm -f core *~
- rm -f $(BOOKS)
+ $(RM) core *~
+ $(RM) $(BOOKS)
+ $(RM) $(DVI) $(AUX) $(TEX) $(LOG)
+
+mrproper: clean
+ $(RM) $(PS) $(PDF)
+
+%.ps : %.sgml
+ db2ps $<
+
+%.pdf : %.sgml
+ db2pdf $<
include $(TOPDIR)/Rules.make
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index f0013b011..3f886e702 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -34,13 +34,71 @@
</bookinfo>
<toc></toc>
- <chapter id="intfuncs">
- <title>Interrupt Handling</title>
-!Iarch/i386/kernel/irq.c
+ <chapter id="vfs">
+ <title>The Linux VFS</title>
+ <sect1><title>The Directory Cache</title>
+!Efs/dcache.c
+!Iinclude/linux/dcache.h
+ </sect1>
+ <sect1><title>Inode Handling</title>
+!Efs/inode.c
+!Efs/bad_inode.c
+ </sect1>
+ <sect1><title>Registration and Superblocks</title>
+!Efs/super.c
+ </sect1>
+ </chapter>
+
+ <chapter id="netcore">
+ <title>Linux Networking</title>
+ <sect1><title>Socket Buffer Functions</title>
+!Iinclude/linux/skbuff.h
+!Enet/core/skbuff.c
+ </sect1>
+ <sect1><title>Socket Filter</title>
+!Enet/core/filter.c
+ </sect1>
+ </chapter>
+
+ <chapter id="netdev">
+ <title>Network device support</title>
+ <sect1><title>Driver Support</title>
+!Edrivers/net/net_init.c
+!Enet/core/dev.c
+ </sect1>
+ <sect1><title>8390 Based Network Cards</title>
+!Edrivers/net/8390.c
+ </sect1>
+ <sect1><title>Synchronous PPP</title>
+!Edrivers/net/wan/syncppp.c
+ </sect1>
+ </chapter>
+
+ <chapter id="modload">
+ <title>Module Loading</title>
+!Ekernel/kmod.c
</chapter>
- <chapter id="mtrrfuncs">
- <title>MTRR Handling</title>
+
+ <chapter id="hardware">
+ <title>Hardware Interfaces</title>
+ <sect1><title>Interrupt Handling</title>
+!Iarch/i386/kernel/irq.c
+ </sect1>
+
+ <sect1><title>MTRR Handling</title>
!Earch/i386/kernel/mtrr.c
+ </sect1>
+ <sect1><title>PCI Support Library</title>
+!Edrivers/pci/pci.c
+ </sect1>
+ <sect1><title>MCA Architecture</title>
+ <sect2><title>MCA Device Functions</title>
+!Earch/i386/kernel/mca.c
+ </sect2>
+ <sect2><title>MCA Bus DMA</title>
+!Iinclude/asm-i386/mca_dma.h
+ </sect2>
+ </sect1>
</chapter>
<chapter id="pmfuncs">
@@ -58,34 +116,14 @@
!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
!Idrivers/sound/sound_firmware.c
</chapter>
- <chapter id="mcabus">
- <title>MCA Architecture</title>
- <sect1><title>MCA Device Functions</title>
-!Earch/i386/kernel/mca.c
- </sect1>
- <sect1><title>MCA Bus DMA</title>
-!Iinclude/asm-i386/mca_dma.h
- </sect1>
- </chapter>
-
- <chapter id="syncppp">
- <title>Synchronous PPP</title>
-!Edrivers/net/wan/syncppp.c
- </chapter>
- <chapter id="16x50">
+ <chapter id="uart16x50">
<title>16x50 UART Driver</title>
!Edrivers/char/serial.c
</chapter>
@@ -95,9 +133,5 @@
!Edrivers/net/wan/z85230.c
</chapter>
- <chapter id="pcilib">
- <title>PCI Support Library</title>
-!Edrivers/pci/pci.c
- </chapter>
</book>
diff --git a/Documentation/DocBook/parportbook.sgml b/Documentation/DocBook/parportbook.tmpl
index 1644748ad..1644748ad 100644
--- a/Documentation/DocBook/parportbook.sgml
+++ b/Documentation/DocBook/parportbook.tmpl
diff --git a/Documentation/arm/SA1100/Brutus b/Documentation/arm/SA1100/Brutus
index 798f18999..39a8905c7 100644
--- a/Documentation/arm/SA1100/Brutus
+++ b/Documentation/arm/SA1100/Brutus
@@ -23,7 +23,7 @@ Currently supported:
- RS232 serial ports
- audio output
- LCD screen
- - keyboard (needs to be cleaned up badly... any volunteer?)
+ - keyboard
The actual Brutus support may not be complete without extra patches.
If such patches exist, they should be found from
diff --git a/Documentation/arm/SA1100/ThinClient b/Documentation/arm/SA1100/ThinClient
new file mode 100644
index 000000000..c254b74b2
--- /dev/null
+++ b/Documentation/arm/SA1100/ThinClient
@@ -0,0 +1,33 @@
+Thin Client / Single Board Computer
+
+The Thin Client, a low cost high power single board computer, has been
+designed to provide intuitive graphical displays in embedded systems.
+
+For more details, contact Applied Data Systems or see
+http://www.flatpanels.com/products.html
+
+Current Linux support for this product has been provided by Nicolas Pitre
+<nico@cam.org>.
+
+It's currently possible to mount a root filesystem via NFS providing a
+complete Linux environment. Otherwyse a ramdisk image may be used. Use
+'make thinclient_config' before any 'make config'. This will set up
+defaults for ThinClient support.
+
+Supported peripherals:
+- SA1100 LCD frame buffer (only 8bpp yet)
+- on-board SMC 92C94 ethernet NIC
+- SA1100 serial port
+- possibly UCB1200 audio (not tested yet)
+
+To do:
+- touchscreen driver
+- flash memory access
+- 16bpp frame buffer support
+- extra (external) serial port driver
+- pcmcia
+- some console keyboard support (maybe IR?)
+- everything else! :-)
+
+Any contribution can be sent to nico@cam.org and will be greatly welcome!
+
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index d9789eadb..8e7505bd4 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -4,10 +4,13 @@ NTFS Overview
To mount an NTFS volume, use the filesystem type 'ntfs'. The driver
currently works only in read-only mode, with no fault-tolerance
supported. If you enable the experimental write support, make sure
-you can recover from a complete loss of data. For ftdisk support,
-limited success was reported with volume sets on top of the md driver,
-although mirror and stripe sets should work as well - if the md
-driver can be talked into using the same layout as Windows NT.
+you can recover from a complete loss of data and also always run
+chkdsk from within Microsoft Windows NT after performing a write to
+a NTFS partition from Linux to detect any problems as early as
+possible. For ftdisk support, limited success was reported with
+volume sets on top of the md driver, although mirror and stripe
+sets should work as well - if the md driver can be talked into
+using the same layout as Windows NT.
The ntfs driver supports the following mount options:
iocharset=name Character set to use when returning file names.
diff --git a/Documentation/sound/CMI8330 b/Documentation/sound/CMI8330
index 0ca5af70f..8885d3307 100644
--- a/Documentation/sound/CMI8330
+++ b/Documentation/sound/CMI8330
@@ -2,6 +2,9 @@ Documentation for CMI 8330 (SoundPRO)
-------------------------------------
Alessandro Zummo <azummo@ita.flashnet.it>
+( Be sure to read Documentation/sound/SoundPro too )
+
+
This adapter is now directly supported by the sb driver.
The only thing you have to do is to compile the kernel sound
@@ -24,17 +27,6 @@ CONFIG_SOUND_MPU401=m
for MPU401 support.
-CONFIG_SOUND_YM3812=m
-
- for OPL3 support. Please note that there are better ways to play midi files, like
- timidity or the softoss2 module.
-
-
-CONFIG_JOYSTICK=y
-
- to activate the joystick port.
-
-
(I suggest you to use "make menuconfig" or "make xconfig"
for a more comfortable configuration editing)
@@ -51,29 +43,12 @@ You should get something similar in syslog:
sb: CMI8330 detected.
sb: CMI8330 sb base located at 0x220
sb: CMI8330 mpu base located at 0x330
-sb: CMI8330 gameport base located at 0x200
-sb: CMI8330 opl3 base located at 0x388
sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>
sb: ISAPnP reports CMI 8330 SoundPRO at i/o 0x220, irq 7, dma 1,5
-To activate the OPL3 support, you need these lines in /etc/modules.conf
-or in a file in /etc/modutils
-
-alias synth0 opl3
-options opl3 io=0x388
-
-and then you can do:
-
- modprobe opl3
-
-
-
-
-
-
The old documentation file follows for reference
purposes.
diff --git a/Documentation/sound/PAS16 b/Documentation/sound/PAS16
new file mode 100644
index 000000000..5a519df67
--- /dev/null
+++ b/Documentation/sound/PAS16
@@ -0,0 +1,185 @@
+Pro Audio Spectrum 16 for 2.3.99 and later
+=========================================
+by Thomas Molina (tmolina@home.com)
+last modified 26 Mar 2000
+Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken
+from Configure.help, Riccardo Facchetti for stuff from README.OSS,
+and others whose names I could not find.
+
+This documentation is relevant for the PAS16 driver (pas2_card.c and
+friends) under kernel version 2.3.99 and later. If you are
+unfamiliar with configuring sound under Linux, please read the
+Sound-HOWTO, linux/Documentation/sound/Introduction and other
+relevant docs first.
+
+The following information is relevant information from README.OSS
+and legacy docs for the Pro Audio Spectrum 16 (PAS16):
+==================================================================
+
+The pas2_card.c driver supports the following cards --
+Pro Audio Spectrum 16 (PAS16) and compatibles:
+ Pro Audio Spectrum 16
+ Pro Audio Studio 16
+ Logitech Sound Man 16
+ NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
+ and will not be supported by the driver.
+
+The sound driver configuration dialog
+-------------------------------------
+
+Sound configuration starts by making some yes/no questions. Be careful
+when answering to these questions since answering y to a question may
+prevent some later ones from being asked. For example don't answer y to
+the question about (PAS16) if you don't really have a PAS16. Sound
+configuration may also be made modular by answering m to configuration
+options presented.
+
+Note also that all questions may not be asked. The configuration program
+may disable some questions depending on the earlier choices. It may also
+select some options automatically as well.
+
+ "ProAudioSpectrum 16 support",
+ - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
+ Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that
+ you read the above list correctly). Don't answer 'y' if you
+ have some other card made by Media Vision or Logitech since they
+ are not PAS16 compatible.
+ NOTE! Since 3.5-beta10 you need to enable SB support (next question)
+ if you want to use the SB emulation of PAS16. It's also possible to
+ the emulation if you want to use a true SB card together with PAS16
+ (there is another question about this that is asked later).
+ "Sound Blaster support",
+ - Answer 'y' if you have an original SB card made by Creative Labs
+ or a full 100% hardware compatible clone (like Thunderboard or
+ SM Games). If your card was in the list of supported cards (above),
+ please look at the card specific instructions later in this file
+ before answering this question. For an unknown card you may answer
+ 'y' if the card claims to be SB compatible.
+ Enable this option also with PAS16.
+
+ "Generic OPL2/OPL3 FM synthesizer support",
+ - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+ The PAS16 has an OPL3-compatible FM chip.
+
+With PAS16 you can use two audio device files at the same time. /dev/dsp (and
+/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
+/dev/audio1) is connected to the SB emulation (8 bit mono only).
+
+
+The new stuff for 2.3.99 and later
+============================================================================
+The following configuration options from linux/Documentation/Configure.help
+are relevant to configuring the PAS16:
+
+Sound card support
+CONFIG_SOUND
+ If you have a sound card in your computer, i.e. if it can say more
+ than an occasional beep, say Y. Be sure to have all the information
+ about your sound card and its configuration down (I/O port,
+ interrupt and DMA channel), because you will be asked for it.
+
+ You want to read the Sound-HOWTO, available from
+ http://www.linuxdoc.org/docs.html#howto . General information
+ about the modular sound system is contained in the files
+ Documentation/sound/Introduction. The file
+ Documentation/sound/README.OSS contains some slightly outdated but
+ still useful information as well.
+
+OSS sound modules
+CONFIG_SOUND_OSS
+ OSS is the Open Sound System suite of sound card drivers. They make
+ sound programming easier since they provide a common API. Say Y or M
+ here (the module will be called sound.o) if you haven't found a
+ driver for your sound card above, then pick your driver from the
+ list below.
+
+Persistent DMA buffers
+CONFIG_SOUND_DMAP
+ Linux can often have problems allocating DMA buffers for ISA sound
+ cards on machines with more than 16MB of RAM. This is because ISA
+ DMA buffers must exist below the 16MB boundary and it is quite
+ possible that a large enough free block in this region cannot be
+ found after the machine has been running for a while. If you say Y
+ here the DMA buffers (64Kb) will be allocated at boot time and kept
+ until the shutdown. This option is only useful if you said Y to
+ "OSS sound modules", above. If you said M to "OSS sound modules"
+ then you can get the persistent DMA buffer functionality by passing
+ the command-line argument "dmabuf=1" to the sound.o module.
+
+ Say y here for PAS16.
+
+ProAudioSpectrum 16 support
+CONFIG_SOUND_PAS
+ Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
+ 16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
+ some other card made by Media Vision or Logitech since they are not
+ PAS16 compatible.
+ If you compile the driver into the kernel, you have to add
+ "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
+ to the kernel command line.
+
+100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
+CONFIG_SOUND_SB
+ Answer Y if you have an original Sound Blaster card made by Creative
+ Labs or a 100% hardware compatible clone (like the Thunderboard or
+ SM Games). For an unknown card you may answer Y if the card claims
+ to be Sound Blaster-compatible. The PAS16 has 8-bit Soundblaster
+ support, so you can answer Y here for it.
+
+ Please read the file Documentation/sound/Soundblaster.
+
+ If you compile the driver into the kernel and don't want to use isapnp,
+ you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
+
+ You can say M here to compile this driver as a module; the module is
+ called sb.o.
+
+FM Synthesizer (YM3812/OPL-3) support
+CONFIG_SOUND_YM3812
+ Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+ Answering Y is usually a safe and recommended choice, however some
+ cards may have software (TSR) FM emulation. Enabling FM support with
+ these cards may cause trouble (I don't currently know of any such
+ cards, however).
+ Please read the file Documentation/sound/OPL3 if your card has an
+ OPL3 chip.
+ If you compile the driver into the kernel, you have to add
+ "opl3=<io>" to the kernel command line.
+
+ If you compile your drivers into the kernel, you MUST configure
+ OPL3 support as a module for PAS16 support to work properly.
+ You can then get OPL3 functionality by issuing the command:
+ insmod opl3
+ In addition, you must either add the following line to
+ /etc/modules.conf:
+ options opl3 io=0x388
+ or else add the following line to /etc/lilo.conf:
+ opl3=0x388
+
+
+EXAMPLES
+===================================================================
+To use the PAS16 in my computer I have enabled the following sound
+configuration options:
+
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS=y
+CONFIG_SOUND_TRACEINIT=y
+CONFIG_SOUND_DMAP=y
+CONFIG_SOUND_PAS=y
+CONFIG_SOUND_SB=y
+CONFIG_SOUND_YM3812=m
+
+I have also included the following append line in /etc/lilo.conf:
+append="pas2=0x388,10,3,-1,0x220,5,1,-1 sb=0x220,5,1,-1 opl3=0x388"
+
+The io address of 0x388 is default configuration on the PAS16. The
+irq of 10 and dma of 3 may not match your installation. The above
+configuration enables PAS16, 8-bit Soundblaster and OPL3
+functionality. If Soundblaster functionality is not desired, the
+following line would be appropriate:
+append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388"
+
+If sound is built totally modular, the above options may be
+specified in /etc/modules.conf for pas2.o, sb.o and opl3.o
+respectively.
diff --git a/Documentation/sound/SoundPro b/Documentation/sound/SoundPro
index 6e8c69ed2..61b9a9197 100644
--- a/Documentation/sound/SoundPro
+++ b/Documentation/sound/SoundPro
@@ -1,6 +1,8 @@
Documentation for the SoundPro CMI8330 extensions in the WSS driver (ad1848.o)
------------------------------------------------------------------------------
+( Be sure to read Documentation/sound/CMI8330 too )
+
Ion Badulescu, ionut@cs.columbia.edu
February 24, 1999
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index 49faf2dab..b68e71cf9 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -1,7 +1,7 @@
- MAGIC SYSRQ KEY DOCUMENTATION v1.31
+ MAGIC SYSRQ KEY DOCUMENTATION v1.32
------------------------------------
- [Mon Mar 13 21:45:48 EST 2000]
+ [Sat Apr 8 22:15:03 CEST 2000]
* What is the magic SysRQ key?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -113,13 +113,13 @@ virtual console (ALT+Fn) and then back again should also help.
* I hit SysRQ, but nothing seems to happen, what's wrong?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There are some keyboards which do not support 'SysRQ', you can try running
-'showkey -s' and pressing SysRQ or alt-SysRQ to see if it generates any
-0x54 codes. If it doesn't, you may define the magic sysrq sequence to a
-different key. Find the keycode with showkey, and change the define of
-'#define SYSRQ_KEY 0x54' in [/usr/src/linux/]include/asm/keyboard.h to
-the keycode of the key you wish to use, then recompile. Oh, and by the way,
-you exit 'showkey' by not typing anything for ten seconds.
+There are some keyboards that send different scancodes for SysRQ than the
+pre-defined 0x54. So if SysRQ doesn't work out of the box for a certain
+keyboard, run 'showkey -s' to find out the proper scancode sequence. Then
+use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRQ
+code (84 is decimal for 0x54). It's probably best to put this command in a
+boot script. Oh, and by the way, you exit 'showkey' by not typing anything
+for ten seconds.
* I have more questions, who can I ask?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/usb/CREDITS b/Documentation/usb/CREDITS
index b1230f70a..38bdbaee0 100644
--- a/Documentation/usb/CREDITS
+++ b/Documentation/usb/CREDITS
@@ -16,6 +16,7 @@ difficult to maintain, add yourself with a patch if desired.
Paul Mackerras <paulus@cs.anu.edu.au>
David E. Nelson <dnelson@jump.net>
Vojtech Pavlik <vojtech@suse.cz>
+ Bill Ryder <bryder@sgi.com>
Thomas Sailer <sailer@ife.ee.ethz.ch>
Gregory P. Smith <greg@electricrain.com>
Linus Torvalds <torvalds@transmeta.com>
diff --git a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt
index c978974f1..e4fced658 100644
--- a/Documentation/usb/acm.txt
+++ b/Documentation/usb/acm.txt
@@ -1,94 +1,138 @@
-The ACM driver works with modems and ISDN TAs that use the USB Abstract
-Control Model standard.
-
-****************************
-Test it:
-Watch out, the driver is not stable and tested. Sync often, make backups,
-most importand: don't blame me...
-
-Create device files:
-mknod /dev/ttyACM0 c 166 0
-mknod /dev/ttyACM1 c 166 1
-mknod /dev/ttyACM2 c 166 2
-mknod /dev/ttyACM3 c 166 3
-Compile a kernel with support for your host controller (uhci only for now!)
-and support for ACM. Boot this kernel. If you connect your device to the
-USB bus you should see messages like the following:
-
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office last message repeated 2 times
-Jul 19 20:14:29 office kernel: parsed = 39 len = 67
-Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping
-Jul 19 20:14:29 office kernel: 0 09
-Jul 19 20:14:29 office kernel: 1 02
-Jul 19 20:14:29 office kernel: 2 43
-Jul 19 20:14:29 office kernel: 3 00
-Jul 19 20:14:29 office kernel: 4 02
-Jul 19 20:14:29 office kernel: 5 02
-Jul 19 20:14:29 office kernel: 6 04
-Jul 19 20:14:29 office kernel: 7 60
-Jul 19 20:14:29 office kernel: 8 00
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: parsed = 67 len = 0
-Jul 19 20:14:29 office kernel: getstringtable
-Jul 19 20:14:29 office kernel: acm_probe
-Jul 19 20:14:29 office kernel: USB ACM found
-
-Watch out for the line:
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-and the line:
-Jul 19 20:14:29 office kernel: USB ACM found
-These two lines show that the device was seen by the usb host controller and
-then recognized by the acm driver as a valid device.
-
-If you use a terminal emulation software like minicom with /dev/ttyACM0 you
-should be able to send AT commands to your device and get responses. I've
-been able to do zmodem downloads to another pc. However downloads from one
-ISDN TA to another ISDN TA connected to the same PC didn't work. Don't
-know why. Flow control is not finised after all and i'd guess there might
-be problems on heavily loades PCs. I also did some tests with ppp but i'm
-not finised with this. There might be a chance to get it working. However
-i'd like to know if your device is recognized as an ACM device. I'm also
-interested if the thing is stable or if it crashes.
-(should i say how it crases?)
-
-You should be able to add and remove devices from the bus. The driver will
-always try to fill up unused ttys. This means if you hotplug devices their
-order may have changed after reboot. This is not the behaviour Linus liked
-to see but it's ok for now. (I hope ;-)
-
-Please report your experiences to me:
-fuerst@in.tum.de
-
-***************************
-I've tested it with:
-3Com ISDN Pro TA.
-
-It should work with (That means i know these devices conform to ACM):
-3Com Office Connect Modem
-3Com Sportster USB (I think that's what it's called)
-
-***************************
-Many thanks to 3Com which did not only support me with hardware but also
-with technical support in USB questions. They also allowed me to do tests in
-their lab. Great!
-
-***************************
-Known bugs:
-Flow control not tested (likely not to work)
-Some tty function calls not implemented (putchar, etc...)
-Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 )
-Not all mem is freed at close (need terminate irq in hcd)
-
-***************************
-Have fun,
- Armin Fuerst
+ Linux ACM driver v0.16
+ (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+ Sponsored by SuSE
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+ 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., 59
+Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Should you need to contact me, the author, you can do so either by e-mail
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+ For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Usage
+~~~~~~~~
+ The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal
+adapters that conform to the Universal Serial Bus Communication Device Class
+Abstract Control Model (USB CDC ACM) specification.
+
+ Many modems do, here is a list of those I know of:
+
+ 3Com OfficeConnect 56k
+ 3Com Voice FaxModem Pro
+ 3Com Sportster
+ MultiTech MultiModem 56k
+ Zoom 2986L FaxModem
+ Compaq 56k FaxModem
+ ELSA Microlink 56k
+
+ I know of one ISDN TA that does work with the acm driver:
+
+ 3Com USR ISDN Pro TA
+
+ Unfortunately many modems and most ISDN TAs use proprietary interfaces and
+thus won't work with this drivers. Check for ACM compliance before buying.
+
+ The driver (with devfs) creates these devices in /dev/usb/acm:
+
+ crw-r--r-- 1 root root 166, 0 Apr 1 10:49 0
+ crw-r--r-- 1 root root 166, 1 Apr 1 10:49 1
+ crw-r--r-- 1 root root 166, 2 Apr 1 10:49 2
+
+ And so on, up to 31, with the limit being possible to change in acm.c to up
+to 256, so you can use up to 256 USB modems with one computer (you'll need
+three USB cards for that, though).
+
+ If you don't use devfs, then you can create device nodes with the same
+minor/major numbers anywhere you want, but either the above location or
+/dev/usb/ttyACM0 is preferred.
+
+ To use the modems you need these modules loaded:
+
+ usbcore.o
+ usb-[uo]hci.o or uhci.o
+ acm.o
+
+ After that, the modem[s] should be accessible. You should be able to use
+minicom, ppp and mgetty with them.
+
+2. Verifying that it works
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+ The first step would be to check /proc/bus/usb/devices, it should look
+like this:
+
+T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
+B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0
+D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+P: Vendor=0000 ProdID=0000 Rev= 0.00
+S: Product=USB UHCI Root Hub
+S: SerialNumber=6800
+C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
+I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
+E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
+T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2
+P: Vendor=04c1 ProdID=008f Rev= 2.07
+S: Manufacturer=3Com Inc.
+S: Product=3Com U.S. Robotics Pro ISDN TA
+S: SerialNumber=UFT53A49BVT7
+C: #Ifs= 1 Cfg#= 1 Atr=60 MxPwr= 0mA
+I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm
+E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
+E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms
+C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr= 0mA
+I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms
+I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
+E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
+
+The presence of these three lines (and the Cls= 'comm' and 'data' classes)
+is important, it means it's an ACM device. The Driver=acm means the acm
+driver is used for the device. If you see only Cls=ff(vend.) then you're out
+of luck, you have a device with vendor specific-interface.
+
+D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2
+I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+
+In the system log you should see:
+
+usb.c: USB new device connect, assigned device number 2
+usb.c: kmalloc IF c7691fa0, numif 1
+usb.c: kmalloc IF c7b5f3e0, numif 2
+usb.c: skipped 4 class/vendor specific interface descriptors
+usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3
+usb.c: USB device number 2 default language ID 0x409
+Manufacturer: 3Com Inc.
+Product: 3Com U.S. Robotics Pro ISDN TA
+SerialNumber: UFT53A49BVT7
+acm.c: probing config 1
+acm.c: probing config 2
+ttyACM0: USB ACM device
+acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0
+acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7
+usb.c: acm driver claimed interface c7b5f3e0
+usb.c: acm driver claimed interface c7b5f3f8
+usb.c: acm driver claimed interface c7691fa0
+
+If all this seems to be OK, fire up minicom and set it to talk to the ttyACM
+device and try typing 'at'. If it responds with 'OK', then everything is
+working.
diff --git a/Documentation/usb/hid.txt b/Documentation/usb/hid.txt
deleted file mode 100644
index 3cd3373ff..000000000
--- a/Documentation/usb/hid.txt
+++ /dev/null
@@ -1,162 +0,0 @@
- Linux HID driver v0.8
- (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
- (c) 1999 Andreas Gal <agal@uwsp.edu>
- Sponsored by SuSE
-----------------------------------------------------------------------------
-
-0. Disclaimer
-~~~~~~~~~~~~~
- 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., 59
-Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- Should you need to contact me, the author, you can do so either by e-mail
-- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, Prague 8, 182 00 Czech Republic
-
- For your convenience, the GNU General Public License version 2 is included
-in the package: See the file COPYING.
-
-1. Introduction
-~~~~~~~~~~~~~~~
- This is a driver for USB devices conforming to the USB HID (Human Input
-Device) standard. These devices include namely keyboards, mice and
-joysticks.
-
- However many other devices (monitors, speakers, UPSs ...) also communicate
-through the same protocol, which makes its specification somewhat bloated.
-This isn't a problem, though, because the driver doesn't need to know about
-all the possible devices it can control, and can just parse the protocol and
-leave the rest of the job (for example understanding what the UPS wants to
-say) to the userland.
-
- Because of this, the USB HID driver has two interfaces. One is via the
-proc filesystem, allowing userland applications send and read arbitrary
-reports to and from a connected USB device. The other is via a very simple
-yet generic input device driver, which dispatches input events (keystrokes,
-mouse or joystick movements) to specific, backward compatible userland
-interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver
-interface are emulated, and allow applications to immediately work with USB
-mice, USB keyboards and USB joysticks without any changes.
-
- The input driver is aimed for a little more than USB device handling in
-the future, though. It's generic enough so that it can be used for any
-mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a
-serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to
-use this as well as the AT keyboard and Sun keyboard drivers. This will
-hopefully allow conversion of all Linux keyboard and mouse and joystick
-drivers to this scheme.
-
- This effort has it's home page at:
-
- http://www.suse.cz/development/input/
-
-You'll find both the latest HID driver and the complete Input driver there.
-There is also a mailing list for this:
-
- listproc@atrey.karlin.mff.cuni.cz
-
-Send "subscribe linux-joystick Your Name" to subscribe to it.
-
-2. Usage
-~~~~~~~~
- Since the driver comes with recent 2.3 kernels, all that's needed to use
-it is to enable it either as a module or compiled-in into the kernel.
-
- After that, after reboot (and possibly also inserting the USB and HID
-modules) the following will happen:
-
-* If you selected keyboard support, all USB keystrokes will be also routed
- to the Linux keyboard driver as if being input through the ordinary system
- keyboard.
-
-* If you selected mouse support, there will be (one or more) simulated PS/2
- mouse devices on major 10, minor 32, 33 and more. These simulated mice can
- in addition to a standard 3-button PS/2 mouse behave like MS Intellimice,
- with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm
- and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse
- device can be open by any number of processes (unlike the /dev/psaux), and
- for each of them the emulation is separate, each can use a different mode.
- The mousedev driver, which emulates the mice, can also emulate a Genius
- NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2
- mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X
- can decode the 5 buttons yet, so this isn't very useful right now.
-
-* If you selected joystick support, the driver will take over major 15, the
- joystick major number, and will emulate joysticks on it. This means the
- normal joystick driver can't be used together with it (now, after the
- normal joystick drivers are converted to the input scheme, all will work
- nicely together). Also, you'll probably need to calibrate your joystick
- manually ('man jscal') to be able to use it, because the USB
- autocalibration is far from perfect yet.
-
-* If you selected event device support, there will be devices on major 10,
- minors 64, 65 and more for each input device connected through this
- driver. These devices output raw events the input driver dispatches. Each
- has a timestamp. This hopefully will be THE way X will talk to keyboard
- and mice, because it's hardware independent, and not limited by existing
- de-facto standards.
-
-3. Verifying if it works
-~~~~~~~~~~~~~~~~~~~~~~~~
- Typing a couple keys on the keyboard should be enough to check that a USB
-keyboard works and is correctly connected to the kernel keyboard driver.
-
- Doing a cat /dev/hidmouse (c, 10, 32) will verify that a mouse is also
-emulated, characters should appear if you move it.
-
- You can test the joystick emulation with the 'jstest' utility, available
-in the joystick package (see Documentation/joystick.txt).
-
- You can test the event devics with the 'evtest' utitily available on the
-input driver homepage (see the URL above).
-
-4. FAQ
-~~~~~~
-Q: Why aren't any questions here yet?
-A: Because none were frequent enough yet.
-
-5. Event interface
-~~~~~~~~~~~~~~~~~~
- Should you want to add event device support into any application (X, gpm,
-svgalib ...) I (vojtech@suse.cz) will be happy to provide you any help I
-can. Here goes a description of the current state of things, which is going
-to be extended, but not changed incompatibly as time goes:
-
- You can use blocking and nonblocking reads, also select() on the
-/dev/inputX devices, and you'll always get a whole number of input events on
-a read. Their layout is:
-
-struct input_event {
- struct timeval time;
- unsigned short type;
- unsigned short code;
- unsigned int value;
-};
-
- 'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
-release. More types are defined in include/linux/input.h.
-
- 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
-list is in include/linux/input.h.
-
- 'value' is the value the event carries. Either a relative change for
-EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
-release, 1 for keypress and 2 for autorepeat.
-
-6. Proc interface
-~~~~~~~~~~~~~~~~~
- For HID-specific devices there is also the /proc interface. It isn't
-present in this release yet, though, so it's description will appear here
-together with the code in the driver.
diff --git a/Documentation/usb/ibmcam.txt b/Documentation/usb/ibmcam.txt
index 5943227a6..21d07c0ba 100644
--- a/Documentation/usb/ibmcam.txt
+++ b/Documentation/usb/ibmcam.txt
@@ -7,8 +7,7 @@ the IBM camera. However most of needed features work well.
This driver was developed using logs of observed USB traffic
which was produced by standard Windows driver (c-it98.sys).
-I did not have any input from Xirlink. Some people asked about
-data sheets, but nothing came out of that. I didn't try.
+I did not have data sheets from Xirlink.
Video formats:
128x96 [model 1]
@@ -29,14 +28,16 @@ SUPPORTED CAMERAS:
IBM "C-It" camera, also known as "Xirlink PC Camera"
The device uses proprietary ASIC (and compression method);
it is manufactured by Xirlink. See http://www.xirlink.com/
-or http://www.c-itnow.com/ for details and pictures.
+http://www.ibmpccamera.com or http://www.c-itnow.com/ for
+details and pictures.
The Linux driver was developed with camera with following
model number (or FCC ID): KSX-XVP510. This camera has three
interfaces, each with one endpoint (control, iso, iso). This
-type of cameras is referred to as "model 1".
+type of cameras is referred to as "model 1". These cameras are
+no longer manufactured.
-It appears that Xirlink made some changes in their cameras recently.
+Xirlink now manufactures new cameras which are somewhat different.
In particular, following models [FCC ID] belong to that category:
XVP300 [KSX-X9903]
@@ -46,29 +47,20 @@ XVP610 [KSX-X9902]
(see http://www.xirlink.com/ibmpccamera/ for updates, they refer
to these new cameras by Windows driver dated 12-27-99, v3005 BETA)
These cameras have two interfaces, one endpoint in each (iso, bulk).
-Such type of cameras is referred to as "model 2". They are supported.
+Such type of cameras is referred to as "model 2". They are supported
+(with exception of 352x288 native mode).
Quirks of Model 2 cameras:
-------------------------
-These cameras apparently produce only 176x144 native video stream;
-the 352x288 formats are produced from 176x144 RGB stream. In fact,
-Xirlink broke perfectly good Model 1 (which used I420 on all sizes)
-and instead switched to color-separated RGB which is a terrible waste
-of bandwidth and resolution. However it probably allowed to simplify
-the camera and use less RAM. Model 2 camera works visibly worse than
-model 1 even using Xirlink's own driver on Windows. The image quality
-is better on Linux than on Windows, partly thanks to _absence_ of
-annoying automatic color corrections which Windows driver feeds into
-the camera several times per second.
-
Model 2 does not have hardware contrast control. Corresponding V4L
control is not used at the moment. It may be possible to implement
contrast control in software, at cost of extra processor cycles.
-The bandwidth demand imposed by RGB quasi-352x288 mode (800 Kbits per
-frame) essentially limits this mode to 10 frames per second or less, in
-ideal conditions on the bus (USB is shared, after all). The frame rate
+This driver provides 352x288 mode by switching the camera into
+quasi-352x288 RGB mode (800 Kbits per frame) essentially limiting
+this mode to 10 frames per second or less, in ideal conditions on
+the bus (USB is shared, after all). The frame rate
has to be programmed very conservatively. Additional concern is that
frame rate depends on brightness setting; therefore the picture can
be good at one brightness and broken at another! I did not want to fix
@@ -81,24 +73,21 @@ try to adjust brightness - brighter image is slower, so USB will be able
to send all data. However if you regularly use Model 2 cameras you may
prefer videosize=1 which makes perfectly good I420, with no scaling and
lesser demands on USB (300 Kbits per second, or 26 frames per second).
-Remember that model 2 cameras never produce images with resolution
-better than "true" 176x144 - or so it seems.
The camera that I had also has a hardware quirk: if disconnected,
it needs few minutes to "relax" before it can be plugged in again
(poorly designed USB processor reset circuit?)
-Finally, to say something good about Model 2: it is much simpler to program
-than Model 1. Commands are few, and they all are straightforward. This camera
-can be programmed for very high sensitivity (starlight may be enough), this
-makes it convenient for tinkering with. The driver code has enough comments
-to help a programmer to tweak the camera as s/he feels necessary.
+Model 2 camera can be programmed for very high sensitivity (even starlight
+may be enough), this makes it convenient for tinkering with. The driver
+code has enough comments to help a programmer to tweak the camera
+as s/he feels necessary.
WHAT YOU NEED:
- A supported IBM PC (C-it) camera (model 1 or 2)
-- A Linux box with USB support (2.3/2.4 or 2.2 w/backport)
+- A Linux box with USB support (2.3/2.4; 2.2 w/backport may work)
- A Video4Linux compatible frame grabber program such as xawtv.
@@ -179,6 +168,19 @@ flags This is a bit mask, and you can combine any number of
FLAGS_OVERLAY_STATS 8 Shows tiny numbers on screen,
useful only for debugging.
FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+ FLAGS_SEPARATE_FRAMES 32 Shows each frame separately, as
+ it was received from the camera.
+ Default (not set) is to mix the
+ preceding frame in to compensate
+ for occasional loss of Isoc data
+ on high frame rates.
+ FLAGS_CLEAN_FRAMES 64 Forces "cleanup" of each frame
+ prior to use; relevant only if
+ FLAGS_SEPARATE_FRAMES is set.
+ Default is not to clean frames,
+ this is a little faster but may
+ produce flicker if frame rate is
+ too high and Isoc data gets lost.
framerate This setting controls frame rate of the camera. This is
an approximate setting (in terms of "worst" ... "best")
diff --git a/Documentation/usb/input.txt b/Documentation/usb/input.txt
new file mode 100644
index 000000000..ebf9058de
--- /dev/null
+++ b/Documentation/usb/input.txt
@@ -0,0 +1,294 @@
+ Linux Input drivers v0.9
+ (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+ Sponsored by SuSE
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+ 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., 59
+Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Should you need to contact me, the author, you can do so either by e-mail
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+ For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Introduction
+~~~~~~~~~~~~~~~
+ This is a collection of drivers that is designed to support all input
+devices under Linux. However, in the current kernels, although it's
+possibilities are much bigger, it's limited to USB devices only. This is
+also why it resides in the drivers/usb subdirectory.
+
+ The center of the input drivers is the input.o module, which must be
+loaded before any other of the input modules - it serves as a way of
+communication between two groups of modules:
+
+1.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+ These modules talk to the hardware (for example via USB), and provide
+events (keystrokes, mouse movements) to the input.o module.
+
+1.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+ These modules get events from input.o and pass them where needed via
+various interfaces - keystrokes to the kernel, mouse movements via a
+simulated PS/2 interface to GPM and X and so on.
+
+2. Simple Usage
+~~~~~~~~~~~~~~~
+ For the most usual configuration, with one USB mouse and one USB keyboard,
+you'll have to load the following modules (or have them built in to the
+kernel):
+
+ input.o
+ mousedev.o
+ keybdev.o
+ usbcore.o
+ usb-[uo]hci.o
+ hid.o
+
+ After this, the USB keyboard will work straight away, and the USB mouse
+will be available as a character device on major 13, minor 32:
+
+ crw-r--r-- 1 root root 13, 32 Mar 28 22:45 mouse0
+
+ This device, has to be created, unless you use devfs, in which case it's
+created automatically. The commands to do that are:
+
+ cd /dev
+ mkdir input
+ mknod input/mouse0 c 13 32
+
+ After that you have to point GPM (the textmode mouse cut&paste tool) and
+XFree to this device to use it - GPM should be called like:
+
+ gpm -t ps2 -m /dev/input/mouse0
+
+ And in X:
+
+ Section "Pointer"
+ Protocol "ImPS/2"
+ Device "/dev/input/mouse0"
+ ZAxisMapping 4 5
+ EndSection
+
+ When you do all of the above, you can use your USB mouse and keyboard.
+
+3. Detailed Description
+~~~~~~~~~~~~~~~~~~~~~~~
+3.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+ Device drivers are the modules that generate events. The events are
+however not useful without being handled, so you also will need to use some
+of the modules from section 3.2.
+
+3.1.1 hid.c
+~~~~~~~~~~~
+ Hid.c is the largest and most complex driver of the whole suite. It
+handles all HID devices, and because there is a very wide variety of them,
+and because the USB HID specification isn't simple, it needs to be this big.
+
+ Currently, it handles USB mice, joysticks, gamepads, steering wheels
+keyboards, trackballs and digitizers.
+
+ However, USB uses HID also for monitor controls, speaker controls, UPSs,
+LCDs and many other purposes.
+
+ The monitor and speaker controls should be easy to add to the hid/input
+interface, but for the UPSs and LCDs it doesn't make much sense. The driver
+doesn't support these yet, and a new, non-event interface should be designed
+for them. If you have any of these devices (I don't), feel free to design
+something and if it's good, it'll get into the driver.
+
+ The usage of the hid.o module is very simple, it takes no parameters,
+detects everything automatically and when a HID device is inserted, it
+detects it appropriately.
+
+ However, because the devices vary wildly, you might happen to have a
+device that doesn't work well. In that case #define DEBUG at the beginning
+of hid.c and send me the syslog traces.
+
+3.1.2 usbmouse.c
+~~~~~~~~~~~~~~~~
+ For embedded systems, for mice with broken HID descriptors and just any
+other use when the big hid.c wouldn't be a good choice, there is the
+usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP
+protocol. This also means the mice must support this simpler protocol. Not
+all do. If you don't have any strong reason to use this module, use hid.c
+instead.
+
+3.1.3 usbkbd.c
+~~~~~~~~~~~~~~
+ Much like usbmouse.c, this module talks to keyboards with a simpplified
+HIDBP protocol. It's smaller, but doesn't support any extra special keys.
+Use hid.c instead if there isn't any special reason to use this.
+
+3.1.4 wacom.c
+~~~~~~~~~~~~~
+ This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom
+PenPartner, that one is handled by the HID driver. Although the Intuos and
+Graphire tablets claim that they are HID tablets as well, they are not and
+thus need this specific driver.
+
+3.1.5 wmforce.c
+~~~~~~~~~~~~~~~
+ A driver for the Logitech WingMan Force joysticks, when connected via the
+USB port. It works quite well, but there is no force feedback support yet,
+because the interface to do that is a trade secret of Immersion Corp, and
+even Logitech can't disclose it.
+
+ Support for Logitech WingMan Force Wheel isn't present in this driver, but
+if someone has the device, and is willing to cooperate, it should be a
+matter of a couple days to add it.
+
+3.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+ Event handlers distrubite the events from the devices to userland and
+kernel, as needed.
+
+3.2.1 keybdev.c
+~~~~~~~~~~~~~~~
+ Keybdev is currently a rather ugly hack that translates the input events
+into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and
+passes them into the handle_scancode function of the keyboard.c module. This
+works well enough on all architectures that keybdev can generate rawmode on,
+other architectures can be added to it.
+
+ The right way would be to pass the events to keyboard.c directly, best if
+keyboard.c would itself be an event handler. This is done in the input
+patch, available on the webpage mentioned below.
+
+3.2.2 mousedev.c
+~~~~~~~~~~~~~~~~
+ Mousedev is also a hack to make programs that use mouse input work. It
+takes events from either mice or digitizers/tablets and makes a PS/2-style
+(a la /dev/psaux) mouse device available to the userland. Ideally, the
+programs could use a more reasonable interface, for example evdev.c
+
+ Mousedev devices in /dev/input (as shown above) are:
+
+ crw-r--r-- 1 root root 13, 32 Mar 28 22:45 mouse0
+ crw-r--r-- 1 root root 13, 33 Mar 29 00:41 mouse1
+ crw-r--r-- 1 root root 13, 34 Mar 29 00:41 mouse2
+ crw-r--r-- 1 root root 13, 35 Apr 1 10:50 mouse3
+
+and so on, up to mouse31. Each is assigned to a single mouse or digitizer,
+unless CONFIG_INPUT_MOUSEDEV_MIX is set. In that case all mice and
+digitizers share a single character device, mouse0, and even when none are
+connected, mouse0 is present. This is useful for hotplugging USB mice, so
+that programs can open the device even when no mice are present.
+
+ CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
+of your screen (in pixels) in XFree86. This is needed if you want to use
+your digitizer in X, because it's movement is sent to X via a virtual PS/2
+mouse.
+
+ Mousedev.c will generate either PS/2, ImPS/2 (microsoft intellimouse) or
+GenPS/2 (genius netmouse/netscroll) protocols, depending on what the program
+wishes. You can set GPM and X to any of these. You'll need ImPS/2 if you
+want to make use of a wheel on a USB mouse and GenPS/2 if you want to use
+extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported in X,
+though.
+
+3.2.3 joydev.c
+~~~~~~~~~~~~~~
+ Joydev implements v0.x and v1.x Linux joystick api, much like
+drivers/char/joystick/joystick.c. See joystick-api.txt in the Documentation
+subdirectory for details. Joydev does it on top of the input subsystem,
+though. As soon as any USB joystick is connected, it can be accessed in
+/dev/input on:
+
+ crw-r--r-- 1 root root 13, 0 Apr 1 10:50 js0
+ crw-r--r-- 1 root root 13, 1 Apr 1 10:50 js1
+ crw-r--r-- 1 root root 13, 2 Apr 1 10:50 js2
+ crw-r--r-- 1 root root 13, 3 Apr 1 10:50 js3
+
+And so on up to js31.
+
+3.2.4 evdev.c
+~~~~~~~~~~~~~
+ Evdev is the generic input event interface. It passes the events generated
+in the kernel straight to the program, with timestamps. The API is still
+evolving, but should be useable now. It's described in section 5.
+
+ This should be the way for GPM and X to get keyboard and mouse mouse
+events. It allows for multihead in X without any specific multihead kernel
+support. The event codes are the same on all architectures and are hardware
+independent.
+
+ The devices are in /dev/input:
+
+ crw-r--r-- 1 root root 13, 64 Apr 1 10:49 event0
+ crw-r--r-- 1 root root 13, 65 Apr 1 10:50 event1
+ crw-r--r-- 1 root root 13, 66 Apr 1 10:50 event2
+ crw-r--r-- 1 root root 13, 67 Apr 1 10:50 event3
+
+3. Contacts
+~~~~~~~~~~~
+ This effort has it's home page at:
+
+ http://www.suse.cz/development/input/
+
+You'll find both the latest HID driver and the complete Input driver there.
+There is also a mailing list for this:
+
+ majordomo@atrey.karlin.mff.cuni.cz
+
+Send "subscribe linux-input" to subscribe to it.
+
+4. Verifying if it works
+~~~~~~~~~~~~~~~~~~~~~~~~
+ Typing a couple keys on the keyboard should be enough to check that a USB
+keyboard works and is correctly connected to the kernel keyboard driver.
+
+ Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse is also
+emulated, characters should appear if you move it.
+
+ You can test the joystick emulation with the 'jstest' utility, available
+in the joystick package (see Documentation/joystick.txt).
+
+ You can test the event devics with the 'evtest' utitily available on the
+input driver homepage (see the URL above).
+
+5. Event interface
+~~~~~~~~~~~~~~~~~~
+ Should you want to add event device support into any application (X, gpm,
+svgalib ...) I <vojtech@suse.cz> will be happy to provide you any help I
+can. Here goes a description of the current state of things, which is going
+to be extended, but not changed incompatibly as time goes:
+
+ You can use blocking and nonblocking reads, also select() on the
+/dev/inputX devices, and you'll always get a whole number of input events on
+a read. Their layout is:
+
+struct input_event {
+ struct timeval time;
+ unsigned short type;
+ unsigned short code;
+ unsigned int value;
+};
+
+ 'time' is the timestamp, it returns the time at which the event happened.
+Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+release. More types are defined in include/linux/input.h.
+
+ 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
+list is in include/linux/input.h.
+
+ 'value' is the value the event carries. Either a relative change for
+EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
+release, 1 for keypress and 2 for autorepeat.
diff --git a/Documentation/usb/ov511.txt b/Documentation/usb/ov511.txt
index 757f7458f..b4c536ec1 100644
--- a/Documentation/usb/ov511.txt
+++ b/Documentation/usb/ov511.txt
@@ -5,42 +5,17 @@ Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
Author: Mark McClelland
Homepage: http://alpha.dyndns.org/ov511
+NEW IN THIS VERSION:
+ o Support for OV511+
+ o Support for OV7620
+
INTRODUCTION:
This is a preliminary version of my OV511 Linux device driver. Currently, it can
grab a frame in color (YUV420) at 640x480 or 320x240 using either vidcat or
xawtv. Other utilities may work but have not yet been tested.
-NEW IN THIS VERSION:
- o Preliminary snapshot support
- o Experimental red-blue misalignment fixes
- o Better YUV420 color conversion
- o Module options
- o Finer-grained debug message control
- o Support for new cameras (4, 36)
- o Uses initcalls
-
-SUPPORTED CAMERAS:
-_________________________________________________________
-Manufacturer | Model | Custom ID | Status
------------------+-----------------+-----------+---------
-MediaForte | MV300 | 0 | Working
-Aiptek | HyperVCam ? | 0 | Working
-NetView | NV300M | 0 | Working
-D-Link | DSB-C300 | 3 | Working
-Hawking Tech. | ??? | 3 | Working
-??? | Generic | 4 | Untested
-Puretek | PT-6007 | 5 | Working
-Creative Labs | WebCam 3 | 21 | Working
-??? | Koala-Cam | 36 | Untested
-Lifeview | RoboCam | 100 | Untested
-AverMedia | InterCam Elite | 102 | Working
-MediaForte | MV300 | 112 | Working
-Omnivision | OV7110 EV board | 112 | Working*
----------------------------------------------------------
-(*) uses OV7110 (monochrome)
-
-Any camera using the OV511 and the OV7610 CCD should work with this driver. The
+Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. The
driver only detects known cameras though, based on their custom id number. If
you have a currently unsupported camera, the ID number should be reported to you
in the kernel logs. Please send me the model, manufacturer and ID number and I
@@ -140,7 +115,7 @@ MODULE PARAMETERS:
DESC: The camera normally adjusts exposure, gain, and hue automatically. This
can be set to 0 to disable this automatic adjustment. Note that there is
currently no way to set these parameters manually once autoadjust is
- disabled. (This feature is not working yet)
+ disabled.
NAME: debug
TYPE: integer (0-6)
@@ -174,7 +149,8 @@ WORKING FEATURES:
o Color streaming/capture at 640x480 and 320x240
o YUV420 color
o Monochrome
- o Setting/getting of saturation, contrast and brightness (no color yet)
+ o Setting/getting of saturation, contrast and brightness (no hue yet; only
+ works with OV7610, not the OV7620 or OV7620AE)
EXPERIMENTAL FEATURES:
o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
@@ -197,13 +173,13 @@ TODO:
o Get hue (red/blue channel balance) adjustment working (in ov511_get_picture()
and ov511_set_picture())
o Get autoadjust disable working
- o Devise some clean way to support different types of CCDs (based on Custom ID)
- o OV511A support
o V4L2 support (Probably not until it goes into the kernel)
o Fix I2C initialization. Some people are reporting problems with reading the
7610 registers. This could be due to timing differences, an excessive I2C
clock rate, or a problem with ov511_i2c_read().
o Get rid of the memory management functions (put them in videodev.c??)
+ o Setting of contrast and brightness not working with 7620
+ o Driver/camera state save/restore for when USB supports suspend/resume
HOW TO CONTACT ME:
diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt
index 8d1066a9f..84510b950 100644
--- a/Documentation/usb/proc_usb_info.txt
+++ b/Documentation/usb/proc_usb_info.txt
@@ -1,16 +1,17 @@
/proc/bus/usb filesystem output
===============================
-(version 19991218)
+(version 2000.03.24)
The /proc filesystem for USB devices generates
/proc/bus/usb/drivers and /proc/bus/usb/devices.
-/proc/bus/usb/drivers just lists the registered drivers,
-one per line. Not very interesting or pretty.
+/proc/bus/usb/drivers lists the registered drivers,
+one per line, with each driver's USB minor dev node
+number range if applicable.
In /proc/bus/usb/devices, each device's output has multiple
-lines (except for a root hub) of ASCII output.
+lines of ASCII output.
I made it ASCII instead of binary on purpose, so that someone
can obtain some useful data from it without the use of an
auxiliary program. However, with an auxiliary program, the numbers
@@ -22,11 +23,12 @@ different topo/connections and it looked possible.)
Each line is tagged with a one-character ID for that line:
T = Topology (etc.)
-B = Bandwidth
+B = Bandwidth (applies only to USB host controllers, which are
+ virtualized as root hubs)
D = Device descriptor info.
P = Product ID info. (from Device descriptor, but they won't fit
together on one line)
-S = String info
+S = String descriptors.
C = Configuration descriptor info. (* = active configuration)
I = Interface descriptor info.
E = Endpoint descriptor info.
@@ -93,7 +95,17 @@ S: Manufacturer=ssss
|__String info tag
S: Product=ssss
-| |__Product description of this device as read from the device.
+| |__Product description of this device as read from the device,
+| except that it is a generated string for USB host controllers
+| (virtual root hubs), in the form "USB *HCI Root Hub".
+|__String info tag
+
+S: SerialNumber=ssss
+| |__Serial Number of this device as read from the device,
+| except that it is a generated string for USB host controllers
+| (virtual root hubs), and represent's the host controller's
+| unique identification in the system (currently I/O or
+| memory-mapped base address).
|__String info tag
@@ -142,7 +154,7 @@ where the valid characters are TDPCIE. With a slightly more able
script, it can display any selected lines (for example, only T, D,
and P lines) and change their output format. (The "procusb"
Perl script is the beginning of this idea. It will list only
-selected lines [selected from TDPCIE] or "All" lines from
+selected lines [selected from TBDPSCIE] or "All" lines from
/proc/bus/usb/devices.)
The Topology lines can be used to generate a graphic/pictorial
@@ -163,6 +175,13 @@ a serial converter connected to the external hub.
T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
B: Alloc= 28/900 us ( 3%), #Int= 2, #Iso= 0
+D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+P: Vendor=0000 ProdID=0000 Rev= 0.00
+S: Product=USB UHCI Root Hub
+S: SerialNumber=dce0
+C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
+I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
+E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0451 ProdID=1446 Rev= 1.00
diff --git a/Documentation/usb/scanner-hp-sane.txt b/Documentation/usb/scanner-hp-sane.txt
index a1cbcd1b4..c47491765 100644
--- a/Documentation/usb/scanner-hp-sane.txt
+++ b/Documentation/usb/scanner-hp-sane.txt
@@ -1,10 +1,11 @@
Copyright (C) 1999, 2000 David E. Nelson
-Jan. 22, 2000
+Mar. 23, 2000
CHANGES
- Amended for Linux-2.3.40
+- Updated for multiple scanner support
INTRODUCTION
@@ -30,13 +31,13 @@ http://www.mostang.com/sane/. Testing has been performed using
version SANE-1.0.1. For instructions on building and installing SANE,
refer to the various README files within the SANE distribution.
-The latest SANE HP backend available from http://www.kirchgessner.net.
+The latest SANE HP backend is available from http://www.kirchgessner.net.
At the time of this writing, version 0.83 was available.
OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
-NOTE: $INSTALL_DIR is the location where SANE was installed. It may
+NOTE: $INSTALL_DIR is the location where SANE is installed. It may
be /usr/local, /usr, /opt or somewhere else. If you don't know, ask
your system administrator.
@@ -54,6 +55,9 @@ files: dll.conf, hp.conf.
/dev/usbscanner
option connect-device
+NOTE: If you are using multiple scanners, make sure to have the correct
+devince, ie /dev/usbscanner0. See scanner.txt for more info.
+
3) You should now be able to use SANE (xscanimage or scanimage).
Don't forget to read any relevant man pages regarding the usage of
diff --git a/Documentation/usb/scanner.txt b/Documentation/usb/scanner.txt
index 193035085..a750e191d 100644
--- a/Documentation/usb/scanner.txt
+++ b/Documentation/usb/scanner.txt
@@ -1,12 +1,15 @@
Copyright (C) 1999, 2000 David E. Nelson
-Jan. 22, 2000
+Mar. 23, 2000
CHANGES
- Amended for linux-2.3.40
- Appended hp_scan.c to end of this README
- Removed most references to HP
+- Updated uhci/ohci host controller info
+- Updated support for multiple scanner support
+- Updated supported scanners list
OVERVIEW
@@ -28,10 +31,8 @@ http://www.linux-usb.org/
REQUIREMENTS
A host with a USB port. Ideally, either a UHCI (Intel) or OHCI
-(Compaq and others) hardware port should work. However, I've only
-been able to really use an OHCI controller. At the time of this
-writing, both uhci and ohci work with scanner.c *except* for the HP
-4100C which only works with ohci. This problem is being investigated.
+(Compaq and others) hardware port should work. At the time of this
+writing, there are two UHCI drivers and one OHCI.
A Linux development kernel (2.3.x) with USB support enabled or a
backported version to linux-2.2.x. See http://www.linux-usb.org for
@@ -69,12 +70,26 @@ hardware (determined from the steps above), 'USB Scanner support', and
(you may need to execute `depmod -a` to update the module
dependencies). Testing was performed only as modules, YMMV.
-Add a device for the USB scanner:
- `mknod /dev/usbscanner c 180 48`
+Beginning with version 0.4 of the driver, up to 16 scanners can be
+connected/used simultaneously. If you intend to use more than
+one scanner at a time:
-Set appropriate permissions for /dev/usbscanner (don't forget about
-group and world permissions). Both read and write permissions are
-required for proper operation.
+ Add a device for the USB scanner:
+ `mknod /dev/usbscanner0 c 180 48`
+ `mknod /dev/usbscanner1 c 180 49`
+ .
+ .
+ `mknod /dev/usb/scanner15 180 63`
+
+
+If you forsee using only one scanner:
+ `mknod /dev/usbscanner0 c 180 48`
+ `ln -s /dev/usbscanner0 /dev/usbscanner`
+
+
+Set appropriate permissions for /dev/usbscanner[0-15] (don't forget
+about group and world permissions). Both read and write permissions
+are required for proper operation.
Load the appropriate modules (if compiled as modules):
@@ -110,25 +125,49 @@ support the listed USB products.
At the time of this writing, the following scanners were supported by
scanner.c:
+ Acer
+
+ Prisa AcerScan 620U
+
+ Agfa
+
+ SnapScan 1212U, SnapScan Touch
+
+ Genius
+
+ ColorPage Vivid Pro
+
Hewlett Packard
3300, 4100, 4200, 5200, 6200, 6300, PhotoSmart S20
- AGFA
+ Microtek
- SnapScan 1212U
+ ScanMaker X6-X6U, Phantom 336CX - C3, Phantom C6, ScanMaker V6USL,
+ ScanMaker V6UL - SpicyU
- Umax
+ Mustek
+
+ 1200 CU
- Astra 2000U
+ Primax/Colorado
+
+ G2-300, G2-600, G2E-300, G2E-600, ReadyScan 636i, Colorado USB
+ 19200, Colorado 600u, Colorado 1200u
Seiko/Epson
- Perfection 636, Perfection 1200U
+ Perfection Perfection 610, Perfection 636U/636Photo, Perfection
+ 1200U/1200Photo
- Mustek
+ Umax
+
+ Astra 1220U, 1236U, 2000U
+
+ Visioneer
+
+ OneTouch 5300, OneTouch 7600, 6100,
- 1200 CU
User Specified. See MODULE PARAMETERS for details.
@@ -142,11 +181,11 @@ options to the driver. Simply add 'options scanner vendor=0x####
product=0x****' to the conf.modules/modules.conf file replacing the
#'s and the *'s with the correct ID's. The ID's can be retrieved from
the messages file or using `cat /proc/bus/usb/devices` if USB /proc
-support was selected during kernel configuration. In later kernels
-(2.3.38+), a new filesystem was introduced, usbdevfs. To mount the
-filesystem, issue the command `mount -t usbdevfs /proc/bus/usb
-/proc/bus/usb`. You can then issue ` cat /proc/bus/usb/devices` to
-extract USB device information.
+support was selected during kernel configuration. **NOTE**:In later
+kernels (2.3.38+), a new filesystem was introduced, usbdevfs. To
+mount the filesystem, issue the command `mount -t usbdevfs
+/proc/bus/usb /proc/bus/usb`. You can then issue ` cat
+/proc/bus/usb/devices` to extract USB device information.
BUGS
diff --git a/Documentation/usb/usb-help.txt b/Documentation/usb/usb-help.txt
new file mode 100644
index 000000000..9abd4a08b
--- /dev/null
+++ b/Documentation/usb/usb-help.txt
@@ -0,0 +1,16 @@
+usb-help.txt
+2000-March-24
+
+For USB help other than the readme files that are located in
+linux/Documentation/usb/*, see the following:
+
+Linux-USB project: http://www.linux-usb.org
+ mirrors at http://www.suse.cz/development/linux-usb/
+ and http://usb.in.tum.de/linux-usb/
+Linux USB Guide: http://linuxusbguide.sourceforge.net
+Linux-USB device overview (working devices and drivers):
+ http://www.qbik.ch/usb/devices/
+
+The Linux-USB mailing list is linux-usb@suse.com .
+
+###
diff --git a/Documentation/video4linux/README.cpia b/Documentation/video4linux/README.cpia
new file mode 100644
index 000000000..2674d1fd4
--- /dev/null
+++ b/Documentation/video4linux/README.cpia
@@ -0,0 +1,191 @@
+This is a driver for the CPiA PPC2 driven parallel connected
+Camera. For example the Creative WebcamII is CPiA driven.
+
+ ) [1]Peter Pregler, Linz 2000, published under the [2]GNU GPL
+
+---------------------------------------------------------------------------
+
+USAGE:
+
+General:
+========
+
+1) Make sure you have created the video devices (/dev/video*):
+
+- if you have a recent MAKEDEV do a 'cd /dev;./MAKEDEV video'
+- otherwise do a:
+
+cd /dev
+mknod video0 c 81 0
+ln -s video0 video
+
+2) Compile the kernel (see below for the list of options to use),
+ configure your parport and reboot.
+
+3) If all worked well you should get messages similar
+ to the following (your versions may be different) on the console:
+
+V4L-Driver for Vision CPiA based cameras v0.7.4
+parport0: read2 timeout.
+parport0: Multimedia device, VLSI Vision Ltd PPC2
+Parallel port driver for Vision CPiA based camera
+ CPIA Version: 1.20 (2.0)
+ CPIA PnP-ID: 0553:0002:0100
+ VP-Version: 1.0 0100
+ 1 camera(s) found
+
+
+As modules:
+===========
+
+Make sure you have selected the following kernel options (you can
+select all stuff as modules):
+
+The cpia-stuff is in the section 'Character devices -> Video For Linux'.
+
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_1284=y
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+
+For autoloading of all those modules you need to tell kerneld some
+stuff. Add the following line to your kerneld config-file
+(e.g. /etc/modules.conf or wherever your distribution does store that
+stuff):
+
+options parport_pc dma=3 irq=7
+alias char-major-81 cpia_pp
+
+The first line tells the dma/irq channels to use. Those _must_ match
+the settings of your BIOS. Do NOT simply use the values above. See
+Documentation/parport.txt for more information about this. The second
+line associates the video-device file with the driver. Of cause you
+can also load the modules once upon boot (usually done in /etc/modules).
+
+Linked into the kernel:
+=======================
+
+Make sure you have selected the following kernel options. Note that
+you cannot compile the parport-stuff as modules and the cpia-driver
+statically (the other way round is okay though).
+
+The cpia-stuff is in the section 'Character devices -> Video For Linux'.
+
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_1284=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_CPIA=y
+CONFIG_VIDEO_CPIA_PP=y
+
+To use DMA/irq you will need to tell the kernel upon boot time the
+hardware configuration of the parport. You can give the boot-parameter
+at the LILO-prompt or specify it in lilo.conf. I use the following
+append-line in lilo.conf:
+
+ append="parport=0x378,7,3"
+
+See Documentation/parport.txt for more information about the
+configuration of the parport and the values given above. Do not simply
+use the values given above.
+
+---------------------------------------------------------------------------
+FEATURES:
+
+- mmap/read v4l-interface (but no overlay)
+- image formats: CIF/QCIF, SIF/QSIF, various others used by isabel;
+ note: all sizes except CIF/QCIF are implemented by clipping, i.e.
+ pixels are not uploaded from the camera
+- palettes: VIDEO_PALETTE_GRAY, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB555,
+ VIDEO_PALETTE_RGB24, VIDEO_PALETTE_RGB32, VIDEO_PALETTE_YUYV,
+ VIDEO_PALETTE_UYVY, VIDEO_PALETTE_YUV422
+- state information (color balance, exposure, ...) is preserved between
+ device opens
+- complete control over camera via proc-interface (_all_ camera settings are
+ supported), there is also a python-gtk application available for this [3]
+- works under SMP (but the driver is completly serialized and synchronous)
+ so you get no benefit from SMP, but at least it does not crash your box
+- might work for non-Intel architecture, let us know about this
+
+---------------------------------------------------------------------------
+TESTED APPLICATIONS:
+
+- a simple test application based on Xt is available at [3]
+- another test-application based on gqcam-0.4 (uses GTK)
+- gqcam-0.6 should work
+- xawtv-3.x (also the webcam software)
+- xawtv-2.46
+- w3cam (cgi-interface and vidcat, e.g. you may try out 'vidcat |xv
+ -maxpect -root -quit +noresetroot -rmode 5 -')
+- vic, the MBONE video conferencing tool (version 2.8ucl4-1)
+- isabel 3R4beta (barely working, but AFAICT all the problems are on
+ their side)
+- camserv-0.40
+
+See [3] for pointers to v4l-applications.
+
+---------------------------------------------------------------------------
+KNOWN PROBLEMS:
+
+- some applications do not handle the image format correctly, you will
+ see strange horizontal stripes instead of a nice picture -> make sure
+ your application does use a supported image size or queries the driver
+ for the actually used size (reason behind this: the camera cannot
+ provide any image format, so if size NxM is requested the driver will
+ use a format to the closest fitting N1xM1, the application should now
+ query for this granted size, most applications do not).
+- all the todo ;)
+- if there is not enough light and the picture is too dark try to
+ adjust the SetSensorFPS setting, automatic frame rate adjustment
+ has its price
+- do not try out isabel 3R4beta (built 135), you will be disappointed
+
+---------------------------------------------------------------------------
+TODO:
+
+- multiple camera support (struct camera or something) - This should work,
+ but hasn't been tested yet.
+- architecture independence?
+- SMP-safe asynchronous mmap interface
+- nibble mode for old parport interfaces
+- streaming capture, this should give a performance gain
+
+---------------------------------------------------------------------------
+IMPLEMENTATION NOTES:
+
+The camera can act in two modes, streaming or grabbing. Right now a
+polling grab-scheme is used. Maybe interrupt driven streaming will be
+used for a ansychronous mmap interface in the next major release of the
+driver. This might give a better frame rate.
+
+---------------------------------------------------------------------------
+THANKS (in no particular order):
+
+- Scott J. Bertin <sbertin@mindspring.com> for cleanups, the proc-filesystem
+ and much more
+- Henry Bruce <whb@vvl.co.uk> for providing developers information about
+ the CPiA chip, I wish all companies would treat Linux as seriously
+- Karoly Erdei <Karoly.Erdei@risc.uni-linz.ac.at> and RISC-Linz for being
+ my boss ;) resp. my employer and for providing me the hardware and
+ allow me to devote some working time to this project
+- Manuel J. Petit de Gabriel <mpetit@dit.upm.es> for providing help
+ with Isabel (http://isabel.dit.upm.es/)
+- Bas Huisman <bhuism@cs.utwente.nl> for writing the initial parport code
+- Jarl Totland <Jarl.Totland@bdc.no> for setting up the mailing list
+ and maintaining the web-server[3]
+- Chris Whiteford <Chris@informinteractive.com> for fixes related to the
+ 1.02 firmware
+- special kudos to all the tester whose machines crashed and/or
+ will crash. :)
+
+---------------------------------------------------------------------------
+REFERENCES
+
+ 1. http://www.risc.uni-linz.ac.at/people/ppregler
+ mailto:Peter_Pregler@email.com
+ 2. see the file COPYING in the top directory of the kernel tree
+ 3. http://webcam.sourceforge.net/
diff --git a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST
index 495eb7e3d..e41e60edf 100644
--- a/Documentation/video4linux/bttv/CARDLIST
+++ b/Documentation/video4linux/bttv/CARDLIST
@@ -37,6 +37,7 @@ bttv.o
card=35 - Chronos Video Shuttle II
card=36 - Typhoon TView TV/FM Tuner
card=37 - PixelView PlayTV pro
+ card=38 - TView99 CPH063
tuner.o
type=0 - Temic PAL
@@ -53,3 +54,4 @@ tuner.o
type=11 - Alps TSBB5
type=12 - Alps TSBE5
type=13 - Alps TSBC5
+ type=14 - Temic 4006FH5
diff --git a/MAINTAINERS b/MAINTAINERS
index 932d4dd44..04b7177cb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -740,6 +740,12 @@ M: emoenke@gwdg.de
L: linux-kernel@vger.rutgers.edu
S: Maintained
+NTFS FILESYSTEM
+P: Anton Altaparmakov
+M: aia21@cus.cam.ac.uk
+L: linux-kernel@vger.rutgers.edu
+S: Odd Fixes
+
NVIDIA (RIVA) FRAMEBUFFER DRIVER
P: Jeff Garzik
M: jgarzik@mandrakesoft.com
@@ -822,8 +828,8 @@ W: http://www-jcr.lmh.ox.ac.uk/~pnp/
S: Maintained
PPP PROTOCOL DRIVERS AND COMPRESSORS
-P: Al Longyear
-M: longyear@pobox.com
+P: Paul Mackerras
+M: paulus@linuxcare.com
L: linux-ppp@vger.rutgers.edu
S: Maintained
diff --git a/Makefile b/Makefile
index 4c60cd612..a2adc3484 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 3
SUBLEVEL = 99
-EXTRAVERSION = -pre3
+EXTRAVERSION = -pre4
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -84,7 +84,7 @@ CPPFLAGS += -D__SMP__
endif
CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
-AFLAGS := $(CPPFLAGS)
+AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
#
# ROOT_DEV specifies the default root-device when making the image.
@@ -181,9 +181,9 @@ export CPPFLAGS CFLAGS AFLAGS
export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -traditional -o $*.s $<
+ $(CPP) $(AFLAGS) -traditional -o $*.s $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
Version: dummy
@rm -f include/linux/compile.h
@@ -370,6 +370,7 @@ clean: archclean
rm -f net/khttpd/times.h
rm -f submenu*
rm -rf modules
+ $(MAKE) -C Documentation/DocBook clean
mrproper: clean archmrproper
rm -f include/linux/autoconf.h include/linux/version.h
@@ -394,8 +395,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
-
+ $(MAKE) -C Documentation/DocBook mrproper
distclean: mrproper
find . -type f \( -name core -o -name '*.orig' -o -name '*.rej' \
-o -name '*~' -o -name '*.bak' -o -name '#*#' \
@@ -409,6 +409,14 @@ backup: mrproper
sgmldocs:
$(MAKE) -C $(TOPDIR)/Documentation/DocBook books
+psdocs: sgmldocs
+ $(MAKE) -C scripts docproc
+ $(MAKE) -C Documentation/DocBook ps
+
+pdfdocs: sgmldocs
+ $(MAKE) -C scripts docproc
+ $(MAKE) -C Documentation/DocBook pdf
+
sums:
find . -type f -print | sort | env -i xargs sum > .SUMS
@@ -431,7 +439,10 @@ checkconfig:
find * -name '*.[hcS]' -type f -print | grep -v scripts/ | sort | xargs $(PERL) -w scripts/checkconfig.pl
checkhelp:
- $(PERL) -w scripts/checkhelp.pl `find * -name [cC]onfig.in -print`
+ find * -name [cC]onfig.in -print | sort | xargs $(PERL) -w scripts/checkhelp.pl
+
+checkincludes:
+ find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkincludes.pl
ifdef CONFIGURATION
..$(CONFIGURATION):
diff --git a/Rules.make b/Rules.make
index b1dd7c429..d3e51bbec 100644
--- a/Rules.make
+++ b/Rules.make
@@ -48,7 +48,7 @@ first_rule: sub_dirs
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@
%.i: %.c
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -E $< > $@
+ $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) $< > $@
%.o: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -c -o $@ $<
diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
index ee2ac0ac0..6bd6cb03f 100644
--- a/arch/alpha/boot/Makefile
+++ b/arch/alpha/boot/Makefile
@@ -11,9 +11,9 @@
LINKFLAGS = -static -T bootloader.lds #-N -relax
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+ $(CPP) $(AFLAGS) -traditional -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
OBJECTS = head.o main.o
BPOBJECTS = head.o bootp.o
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index d73afb558..6053ae25c 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -65,6 +65,7 @@ unset CONFIG_ALPHA_BROKEN_IRQ_MASK
# Most of these machines have ISA slots; not exactly sure which don't,
# and this doesn't activate hordes of code, so do it always.
define_bool CONFIG_ISA y
+define_bool CONFIG_SBUS n
if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
then
@@ -189,6 +190,8 @@ bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
if [ "$CONFIG_HOTPLUG" = "y" ] ; then
source drivers/pcmcia/Config.in
+else
+ define_bool CONFIG_PCMCIA n
fi
bool 'Networking support' CONFIG_NET
@@ -274,7 +277,6 @@ endmenu
source drivers/char/Config.in
-source drivers/usb/Config.in
#source drivers/misc/Config.in
@@ -300,6 +302,8 @@ if [ "$CONFIG_SOUND" != "n" ]; then
fi
endmenu
+source drivers/usb/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index 03be84794..40676926c 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -46,11 +46,13 @@ CONFIG_ALPHA_GENERIC=y
# CONFIG_ALPHA_SABLE is not set
# CONFIG_ALPHA_TAKARA is not set
CONFIG_ISA=y
+# CONFIG_SBUS is not set
CONFIG_PCI=y
CONFIG_ALPHA_BROKEN_IRQ_MASK=y
# CONFIG_SMP is not set
CONFIG_PCI_NAMES=y
# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
CONFIG_NET=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 9d87b6e0c..3a0a4ec0b 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -8,9 +8,9 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+ $(CPP) $(AFLAGS) -o $*.s $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+ $(CC) $(AFLAGS) -c -o $*.o $<
O_TARGET := kernel.o
O_OBJS := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \
diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
index a47178050..79a1c4fb5 100644
--- a/arch/alpha/kernel/irq_i8259.c
+++ b/arch/alpha/kernel/irq_i8259.c
@@ -146,12 +146,6 @@ isa_device_interrupt(unsigned long vector, struct pt_regs *regs)
*/
int j = *(vuip) IACK_SC;
j &= 0xff;
- if (j == 7) {
- if (!(inb(0x20) & 0x80)) {
- /* It's only a passive release... */
- return;
- }
- }
handle_irq(j, regs);
}
#endif
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index a7110bf23..299a1b338 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -42,7 +42,7 @@
#include <asm/hwrpb.h>
#include <asm/processor.h>
-extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
+extern long do_sys_mount(char *, char *, char *, int, void *);
extern int do_pipe(int *);
extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
@@ -319,20 +319,16 @@ asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long b
asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
{
struct file *file;
- struct dentry *dentry;
int retval;
- lock_kernel();
retval = -EBADF;
file = fget(fd);
- if (!file)
- goto out;
- dentry = file->f_dentry;
- if (dentry)
- retval = do_osf_statfs(dentry, buffer, bufsiz);
- fput(file);
-out:
- unlock_kernel();
+ if (file) {
+ lock_kernel();
+ retval = do_osf_statfs(file->f_dentry, buffer, bufsiz);
+ unlock_kernel();
+ fput(file);
+ }
return retval;
}
@@ -363,32 +359,6 @@ struct procfs_args {
uid_t exroot;
};
-static struct dentry *getdev(const char *name, int rdonly)
-{
- struct dentry *dentry;
- struct inode *inode;
- int retval;
-
- dentry = namei(name);
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- return dentry;
-
- retval = -ENOTBLK;
- inode = dentry->d_inode;
- if (!S_ISBLK(inode->i_mode))
- goto out_dput;
-
- retval = -EACCES;
- if (IS_NODEV(inode))
- goto out_dput;
- return dentry;
-
-out_dput:
- dput(dentry);
- return ERR_PTR(retval);
-}
-
/*
* We can't actually handle ufs yet, so we translate UFS mounts to
* ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
@@ -400,20 +370,18 @@ out_dput:
static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
{
int retval;
- struct dentry *dentry;
struct cdfs_args tmp;
+ char *devname;
retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
goto out;
-
- dentry = getdev(tmp.devname, 0);
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ devname = getname(tmp.devname);
+ retval = PTR_ERR(devname);
+ if (IS_ERR(devname))
goto out;
- retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname,
- "ext2", flags, NULL);
- dput(dentry);
+ retval = do_sys_mount(devname, dirname, "ext2", flags, NULL);
+ putname(devname);
out:
return retval;
}
@@ -421,20 +389,18 @@ out:
static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
{
int retval;
- struct dentry * dentry;
struct cdfs_args tmp;
+ char *devname;
retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
goto out;
-
- dentry = getdev(tmp.devname, 1);
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ devname = getname(tmp.devname);
+ retval = PTR_ERR(devname);
+ if (IS_ERR(devname))
goto out;
- retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname,
- "iso9660", flags, NULL);
- dput(dentry);
+ retval = do_sys_mount(devname, dirname, "iso9660", flags, NULL);
+ putname(devname);
out:
return retval;
}
@@ -445,27 +411,36 @@ static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
if (copy_from_user(&tmp, args, sizeof(tmp)))
return -EFAULT;
- return do_mount(NULL, "", dirname, "proc", flags, NULL);
+
+ return do_sys_mount("", dirname, "proc", flags, NULL);
}
asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
{
int retval = -EINVAL;
+ char *name;
lock_kernel();
+
+ name = getname(path);
+ retval = PTR_ERR(name);
+ if (IS_ERR(name))
+ goto out;
switch (typenr) {
case 1:
- retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
+ retval = osf_ufs_mount(name, (struct ufs_args *) data, flag);
break;
case 6:
- retval = osf_cdfs_mount(path, (struct cdfs_args *) data, flag);
+ retval = osf_cdfs_mount(name, (struct cdfs_args *) data, flag);
break;
case 9:
- retval = osf_procfs_mount(path, (struct procfs_args *) data, flag);
+ retval = osf_procfs_mount(name, (struct procfs_args *) data, flag);
break;
default:
printk("osf_mount(%ld, %x)\n", typenr, flag);
}
+ putname(name);
+out:
unlock_kernel();
return retval;
}
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ff732b8fa..019f2115e 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -100,7 +100,7 @@ endif
LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
-export LIBGCC
+export LIBGCC MACHINE PROCESSOR TEXTADDR
ifeq ($(CONFIG_ARCH_A5K),y)
MACHINE = a5k
@@ -216,7 +216,7 @@ archclean:
@$(MAKEBOOT) clean
$(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds
-archdep:
+archdep: symlinks
@$(MAKEBOOT) dep
# My testing targets (that short circuit a few dependencies)
@@ -256,3 +256,8 @@ victor_config:
empeg_config:
$(RM) arch/arm/defconfig
cp arch/arm/def-configs/empeg arch/arm/defconfig
+
+thinclient_config:
+ $(RM) arch/arm/defconfig
+ cp arch/arm/def-configs/thinclient arch/arm/defconfig
+
diff --git a/arch/arm/boot/compressed/head-sa1100.S b/arch/arm/boot/compressed/head-sa1100.S
index 4464157c3..b6e9dbe64 100644
--- a/arch/arm/boot/compressed/head-sa1100.S
+++ b/arch/arm/boot/compressed/head-sa1100.S
@@ -17,8 +17,9 @@ __SA1100_start:
#error What am I doing here...
#endif
-#ifdef CONFIG_SA1100_BRUTUS
-@ need to enter SVC mode
+#if defined( CONFIG_SA1100_BRUTUS ) || \
+ defined( CONFIG_SA1100_THINCLIENT )
+@ Booting from Angel -- need to enter SVC mode
#define angel_SWIreason_EnterSVC 0x17 /* from arm.h, in angel source */
#define angel_SWI_ARM (0xEF123456 & 0xffffff)
mov r0, #angel_SWIreason_EnterSVC
diff --git a/arch/arm/config.in b/arch/arm/config.in
index cf6312fc1..fa124b5fd 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -53,6 +53,7 @@ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
Itsy CONFIG_SA1100_ITSY \
LART CONFIG_SA1100_LART \
PLEB CONFIG_SA1100_PLEB \
+ ThinClient CONFIG_SA1100_THINCLIENT \
Victor CONFIG_SA1100_VICTOR \
Tifon CONFIG_SA1100_TIFON" Brutus
fi
@@ -136,6 +137,9 @@ else
define_bool CONFIG_ISA_DMA n
fi
+define_bool CONFIG_SBUS n
+define_bool CONFIG_PCMCIA n
+
if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP
fi
@@ -218,7 +222,6 @@ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
fi
fi
-source drivers/usb/Config.in
#source drivers/misc/Config.in
@@ -298,6 +301,8 @@ fi
source fs/Config.in
+source drivers/usb/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/arm/def-configs/brutus b/arch/arm/def-configs/brutus
index aade81639..284c92925 100644
--- a/arch/arm/def-configs/brutus
+++ b/arch/arm/def-configs/brutus
@@ -2,6 +2,12 @@
# Automatically generated make config: don't edit
#
CONFIG_ARM=y
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
#
# System and processor type
@@ -12,25 +18,21 @@ CONFIG_ARM=y
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_FOOTBRIDGE is not set
CONFIG_ARCH_SA1100=y
-CONFIG_CPU_SA1100=y
CONFIG_SA1100_BRUTUS=y
# CONFIG_SA1100_EMPEG is not set
# CONFIG_SA1100_ITSY is not set
# CONFIG_SA1100_LART is not set
# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_THINCLIENT is not set
# CONFIG_SA1100_VICTOR is not set
# CONFIG_SA1100_TIFON is not set
+CONFIG_DISCONTIGMEM=y
# 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_CPU_SA1100=y
# CONFIG_ISA_DMA is not set
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
# CONFIG_ALIGNMENT_TRAP is not set
#
@@ -48,10 +50,16 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
CONFIG_NWFPE=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_ARTHUR is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
CONFIG_CMDLINE=""
@@ -61,7 +69,6 @@ CONFIG_CMDLINE=""
# CONFIG_I2O is not set
# CONFIG_I2O_PCI is not set
# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
# CONFIG_I2O_SCSI is not set
# CONFIG_I2O_PROC is not set
@@ -81,7 +88,6 @@ CONFIG_CMDLINE=""
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD_ONLY is not set
-# CONFIG_BLK_CPQ_DA is not set
#
# Additional Block Devices
@@ -91,7 +97,6 @@ CONFIG_CMDLINE=""
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_IDE_MODES is not set
# CONFIG_BLK_DEV_HD is not set
@@ -100,9 +105,9 @@ CONFIG_PARIDE_PARPORT=y
# Character devices
#
CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
+# CONFIG_VT_CONSOLE is not set
CONFIG_SERIAL_SA1100=y
-# CONFIG_SERIAL_SA1100_CONSOLE is not set
+CONFIG_SERIAL_SA1100_CONSOLE=y
# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
@@ -110,11 +115,25 @@ CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32
#
+# 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
@@ -123,11 +142,6 @@ CONFIG_UNIX98_PTY_COUNT=32
# Video For Linux
#
# CONFIG_VIDEO_DEV is not set
-
-#
-# Joystick support
-#
-# CONFIG_JOYSTICK is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -137,9 +151,11 @@ CONFIG_UNIX98_PTY_COUNT=32
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
#
-# USB drivers - not for the faint of heart
+# USB support
#
# CONFIG_USB is not set
@@ -148,16 +164,22 @@ CONFIG_UNIX98_PTY_COUNT=32
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_FB_SA1100=y
# CONFIG_FB_MATROX is not set
# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_3DFX is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
CONFIG_FBCON_CFB2=y
CONFIG_FBCON_CFB4=y
CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
CONFIG_FBCON_FONTWIDTH8_ONLY=y
CONFIG_FBCON_FONTS=y
CONFIG_FONT_8x8=y
@@ -172,30 +194,35 @@ CONFIG_FONT_8x8=y
# CONFIG_SCSI 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
-# CONFIG_UDF_FS is not set
# 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
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
#
@@ -203,8 +230,6 @@ CONFIG_EXT2_FS=y
#
# CONFIG_PARTITION_ADVANCED is not set
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/arm/def-configs/footbridge b/arch/arm/def-configs/footbridge
index e43a8d2a9..e0ee910b7 100644
--- a/arch/arm/def-configs/footbridge
+++ b/arch/arm/def-configs/footbridge
@@ -2,6 +2,7 @@
# Automatically generated make config: don't edit
#
CONFIG_ARM=y
+CONFIG_UID16=y
#
# Code maturity level options
@@ -19,16 +20,18 @@ 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_DMA=y
-# CONFIG_ALIGNMENT_TRAP is not set
+CONFIG_ALIGNMENT_TRAP=y
#
# Loadable module support
@@ -42,7 +45,7 @@ CONFIG_KMOD=y
#
CONFIG_NET=y
CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BSD_PROCESS_ACCT=y
CONFIG_SYSCTL=y
CONFIG_NWFPE=y
CONFIG_KCORE_ELF=y
@@ -51,10 +54,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 +75,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,64 +99,9 @@ CONFIG_ISAPNP=y
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
-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_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_IDEDMA_PCI_AUTO=y
-CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y
-CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
-CONFIG_BLK_DEV_OFFBOARD=y
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_CMD646 is not set
-CONFIG_BLK_DEV_CY82C693=y
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_PDC202XX=y
-# CONFIG_PDC202XX_FORCE_BURST_BIT is not set
-# CONFIG_PDC202XX_FORCE_MASTER_MODE is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-CONFIG_BLK_DEV_SL82C105=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_IDE_CHIPSETS 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
@@ -172,8 +129,17 @@ CONFIG_PARIDE_KBIC=m
CONFIG_PARIDE_KTTI=m
CONFIG_PARIDE_ON20=m
CONFIG_PARIDE_ON26=m
-CONFIG_BLK_DEV_IDE_MODES=y
-# CONFIG_BLK_DEV_HD is not set
+# 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 is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
#
# Character devices
@@ -183,7 +149,24 @@ CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_SERIAL_CONSOLE=y
# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+CONFIG_SERIAL_21285=y
+CONFIG_SERIAL_21285_CONSOLE=y
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_STALDRV is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
CONFIG_PRINTER=m
@@ -191,6 +174,14 @@ CONFIG_PRINTER=m
# CONFIG_PPDEV is not set
#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_CHARDEV is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
@@ -214,13 +205,14 @@ CONFIG_WATCHDOG=y
CONFIG_SOFT_WATCHDOG=y
# CONFIG_PCWATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_21285_WATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+CONFIG_21285_WATCHDOG=m
CONFIG_977_WATCHDOG=m
CONFIG_DS1620=y
CONFIG_NWBUTTON=y
CONFIG_NWBUTTON_REBOOT=y
CONFIG_NWFLASH=m
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=m
CONFIG_RTC=y
#
@@ -230,25 +222,29 @@ 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
@@ -263,15 +259,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
@@ -279,32 +270,46 @@ 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 is not set
#
# USB Devices
#
-CONFIG_USB_MOUSE=m
-# CONFIG_USB_HP_SCANNER is not set
-CONFIG_USB_KBD=m
-CONFIG_USB_AUDIO=m
-CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=m
+CONFIG_USB_SCANNER=m
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_ACM is not set
# 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_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 is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
#
# Console drivers
@@ -342,10 +347,11 @@ 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
-CONFIG_FONT_8x16=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_6x11 is not set
@@ -356,7 +362,7 @@ CONFIG_FONT_ACORN_8x8=y
# Networking options
#
CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
+CONFIG_PACKET_MMAP=y
# CONFIG_NETLINK is not set
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
@@ -371,12 +377,12 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
#
# (it is safe to leave these untouched)
#
-CONFIG_SKB_LARGE=y
+# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
@@ -409,7 +415,46 @@ CONFIG_SKB_LARGE=y
#
# IrDA (infrared) support
#
-# CONFIG_IRDA is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_OPTIONS=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+# CONFIG_IRDA_COMPRESSION is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+# CONFIG_IRPORT_SIR is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_NSC_FIR is not set
+CONFIG_WINBOND_FIR=m
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
#
# Network device support
@@ -421,6 +466,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
@@ -440,30 +486,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
#
@@ -491,7 +537,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
@@ -504,9 +550,70 @@ CONFIG_SLIP_MODE_SLIP6=y
# CONFIG_WAN is not set
#
-# PCMCIA network device support
+# 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=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
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
#
-# CONFIG_NET_PCMCIA is not set
+# 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=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_OFFBOARD=y
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
+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=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_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+CONFIG_BLK_DEV_IDE_MODES=y
#
# SCSI support
@@ -527,8 +634,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=m
+# 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
@@ -539,9 +650,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
@@ -549,24 +662,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_ADFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_ADFS_FS=m
+# 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
@@ -575,12 +682,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
@@ -606,7 +716,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
@@ -614,13 +731,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/arm/def-configs/thinclient b/arch/arm/def-configs/thinclient
new file mode 100644
index 000000000..01829e71f
--- /dev/null
+++ b/arch/arm/def-configs/thinclient
@@ -0,0 +1,379 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_FOOTBRIDGE is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_EMPEG is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_PLEB is not set
+CONFIG_SA1100_THINCLIENT=y
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_TIFON is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_ARCH_ACORN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+CONFIG_CPU_32v4=y
+CONFIG_CPU_SA1100=y
+# CONFIG_ISA_DMA is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_NWFPE=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_ARTHUR is not set
+# CONFIG_PARPORT is not set
+CONFIG_CMDLINE="root=nfs"
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# 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 is not set
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_ONLY 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=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# 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 is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV 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_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Misc devices
+#
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_SA1100=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+# CONFIG_FONT_8x8 is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (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 is not set
+# CONFIG_DECNET is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# 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
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_WD80x3 is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRA32 is not set
+CONFIG_SMC9194=y
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring driver support
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# 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
+# 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
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# 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_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_LL is not set
diff --git a/arch/arm/defconfig b/arch/arm/defconfig
index 79cac7fa3..c5b389476 100644
--- a/arch/arm/defconfig
+++ b/arch/arm/defconfig
@@ -32,6 +32,8 @@ CONFIG_PCI=y
CONFIG_PCI_NAMES=y
CONFIG_ISA=y
CONFIG_ISA_DMA=y
+# CONFIG_SBUS is not set
+# CONFIG_PCMCIA is not set
# CONFIG_ALIGNMENT_TRAP is not set
#
@@ -537,6 +539,7 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
# CONFIG_BLK_DEV_AEC6210 is not set
# CONFIG_AEC6210_TUNING is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD7409 is not set
# CONFIG_AMD7409_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index c454c1350..6cc5652e0 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -59,12 +59,12 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
all: kernel.o $(HEAD_OBJ) init_task.o
$(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
+ $(CC) $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
include $(TOPDIR)/Rules.make
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $<
+ $(CC) $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $<
# Spell out some dependencies that `make dep' doesn't spot
entry-armv.o: calls.S ../lib/constants.h
diff --git a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c
index 536e614ff..e9cca7748 100644
--- a/arch/arm/kernel/arch.c
+++ b/arch/arm/kernel/arch.c
@@ -23,6 +23,9 @@ unsigned int memc_ctrl_reg;
unsigned int number_mfm_drives;
#endif
+extern void setup_initrd(unsigned int start, unsigned int size);
+extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
+
/*
* Architecture specific fixups. This is where any
* parameters in the params struct are fixed up, or
@@ -157,11 +160,15 @@ fixup_sa1100(struct machine_desc *desc, struct param_struct *params,
#if defined(CONFIG_SA1100_BRUTUS)
ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
setup_ramdisk( 1, 0, 0, 8192 );
- setup_initrd( __phys_to_virt(0xd8000000), 0x00400000 );
+ setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 );
#elif defined(CONFIG_SA1100_EMPEG)
ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */
setup_ramdisk( 1, 0, 0, 4096 );
setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) );
+#elif defined(CONFIG_SA1100_THINCLIENT)
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ setup_ramdisk( 1, 0, 0, 8192 );
+ setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
#elif defined(CONFIG_SA1100_TIFON)
ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0);
setup_ramdisk(1, 0, 0, 4096);
@@ -198,7 +205,7 @@ static struct machine_desc machine_desc[] __attribute__ ((__section__ (".arch.in
"EBSA110", /* RMK */
0x00000400,
NO_VIDEO,
- 1, 0, 1, 1, 1,
+ 1, 0, 1, 0, 1,
NULL
},
#endif
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 5a1b4ed31..02a4f6cf0 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -190,6 +190,8 @@ EXPORT_SYMBOL(uaccess_kernel);
EXPORT_SYMBOL(uaccess_user);
#endif
+ /* consistent area handling */
+EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(consistent_alloc);
EXPORT_SYMBOL(consistent_free);
EXPORT_SYMBOL(consistent_sync);
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 109e2f96d..c4ccd64e3 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -504,6 +504,10 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size
{
}
+void pcibios_set_master(struct pci_dev *dev)
+{
+}
+
int pcibios_enable_device(struct pci_dev *dev)
{
u16 cmd, old_cmd;
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index fe3939888..182b1c3b4 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -201,6 +201,38 @@ irq_prio_ebsa110:
.byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2
.endm
+#elif defined(CONFIG_ARCH_SHARK)
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base
+ mov r4, #0xe0000000
+ orr r4, r4, #0x20
+
+ mov \irqstat, #0x0C
+ strb \irqstat, [r4] @outb(0x0C, 0x20) /* Poll command */
+ ldrb \irqnr, [r4] @irq = inb(0x20) & 7
+ and \irqstat, \irqnr, #0x80
+ teq \irqstat, #0
+ beq 43f
+ and \irqnr, \irqnr, #7
+ teq \irqnr, #2
+ bne 44f
+43: mov \irqstat, #0x0C
+ strb \irqstat, [r4, #0x80] @outb(0x0C, 0xA0) /* Poll command */
+ ldrb \irqnr, [r4, #0x80] @irq = (inb(0xA0) & 7) + 8
+ and \irqstat, \irqnr, #0x80
+ teq \irqstat, #0
+ beq 44f
+ and \irqnr, \irqnr, #7
+ add \irqnr, \irqnr, #8
+44: teq \irqstat, #0
+ .endm
+
+ .macro irq_prio_table
+ .endm
+
#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
#include <asm/dec21285.h>
@@ -295,9 +327,12 @@ irq_prio_ebsa110:
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base
- ldr r4, =0xffe00000
- ldr \irqstat, [r4, #0x180] @ get interrupts
+ ldr \irqstat, =INTCONT_BASE
+ ldr \base, =soft_irq_mask
+ ldr \irqstat, [\irqstat] @ get interrupts
+ ldr \base, [\base]
mov \irqnr, #0
+ and \irqstat, \irqstat, \base @ mask out disabled ones
1001: tst \irqstat, #1
addeq \irqnr, \irqnr, #1
moveq \irqstat, \irqstat, lsr #1
@@ -307,6 +342,39 @@ irq_prio_ebsa110:
.endm
.macro irq_prio_table
+ .ltorg
+ .bss
+ENTRY(soft_irq_mask)
+ .word 0
+ .text
+ .endm
+
+#elif defined(CONFIG_ARCH_TBOX)
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base
+ ldr \irqstat, =0xffff7000
+ ldr \irqstat, [\irqstat] @ get interrupts
+ ldr \base, =soft_irq_mask
+ ldr \base, [\base]
+ mov \irqnr, #0
+ and \irqstat, \irqstat, \base @ mask out disabled ones
+1001: tst \irqstat, #1
+ addeq \irqnr, \irqnr, #1
+ moveq \irqstat, \irqstat, lsr #1
+ tsteq \irqnr, #32
+ beq 1001b
+ teq \irqnr, #32
+ .endm
+
+ .macro irq_prio_table
+ .ltorg
+ .bss
+ENTRY(soft_irq_mask)
+ .word 0
+ .text
.endm
#elif defined(CONFIG_ARCH_SA1100)
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 6ea7916ef..c7ace10b5 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -28,15 +28,24 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <asm/arch/system.h>
#include <asm/io.h>
+/*
+ * Values for cpu_do_idle()
+ */
+#define IDLE_WAIT_SLOW 0
+#define IDLE_WAIT_FAST 1
+#define IDLE_CLOCK_SLOW 2
+#define IDLE_CLOCK_FAST 3
+
extern char *processor_modes[];
extern void setup_mm_for_reboot(char mode);
asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
-static int hlt_counter;
+static volatile int hlt_counter;
+
+#include <asm/arch/system.h>
void disable_hlt(void)
{
@@ -64,7 +73,9 @@ __setup("nohlt", nohlt_setup);
__setup("hlt", hlt_setup);
/*
- * The idle loop on an ARM...
+ * The idle thread. We try to conserve power, while trying to keep
+ * overall latency low. The architecture specific idle is passed
+ * a value to indicate the level of "idleness" of the system.
*/
void cpu_idle(void)
{
@@ -72,15 +83,13 @@ void cpu_idle(void)
init_idle();
current->priority = 0;
current->counter = -100;
+
while (1) {
- if (!hlt_counter)
- arch_do_idle();
- if (current->need_resched) {
- schedule();
+ arch_idle();
+ schedule();
#ifndef CONFIG_NO_PGT_CACHE
- check_pgt_cache();
+ check_pgt_cache();
#endif
- }
}
}
@@ -89,7 +98,7 @@ static char reboot_mode = 'h';
int __init reboot_setup(char *str)
{
reboot_mode = str[0];
- return 0;
+ return 1;
}
__setup("reboot=", reboot_setup);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 6a3429bdd..f04b422b4 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -228,7 +228,7 @@ parse_cmdline(struct meminfo *mi, char **cmdline_p, char *from)
*cmdline_p = command_line;
}
-static void __init
+void __init
setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
{
#ifdef CONFIG_BLK_DEV_RAM
@@ -246,7 +246,7 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
/*
* initial ram disk
*/
-static void __init setup_initrd(unsigned int start, unsigned int size)
+void __init setup_initrd(unsigned int start, unsigned int size)
{
#ifdef CONFIG_BLK_DEV_INITRD
if (start == 0)
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 510a38451..5f48f951a 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -37,7 +37,7 @@ L_OBJS += $(L_OBJS_$(MACHINE))
include $(TOPDIR)/Rules.make
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
constants.h: getconsdata.o extractconstants.pl
$(PERL) extractconstants.pl $(OBJDUMP) > $@
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 1c02473bb..26d7f1058 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -34,7 +34,7 @@ endif
include $(TOPDIR)/Rules.make
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $<
# Special dependencies
fault-armv.o: fault-common.c
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index cb29618a3..5d46369eb 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -293,10 +293,15 @@ static void __init create_mapping(struct map_desc *md)
*/
void setup_mm_for_reboot(char mode)
{
- pgd_t *pgd = current->mm->pgd;
+ pgd_t *pgd;
pmd_t pmd;
int i;
+ if (current->mm && current->mm->pgd)
+ pgd = current->mm->pgd;
+ else
+ pgd = init_mm.pgd;
+
for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++) {
pmd_val(pmd) = (i << PGDIR_SHIFT) |
PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
diff --git a/arch/arm/mm/mm-sa1100.c b/arch/arm/mm/mm-sa1100.c
index c6f9f2e8b..1cb1a3b58 100644
--- a/arch/arm/mm/mm-sa1100.c
+++ b/arch/arm/mm/mm-sa1100.c
@@ -36,10 +36,8 @@ struct mem_desc {
#if defined(CONFIG_SA1100_BRUTUS)
{ 0xc0000000, 0x00400000 }, /* 4MB */
{ 0xc8000000, 0x00400000 }, /* 4MB */
-#if 0 /* only two banks until the bootmem stuff is fixed... */
{ 0xd0000000, 0x00400000 }, /* 4MB */
{ 0xd8000000, 0x00400000 } /* 4MB */
-#endif
#elif defined(CONFIG_SA1100_EMPEG)
{ 0xc0000000, 0x00400000 }, /* 4MB */
{ 0xc8000000, 0x00400000 } /* 4MB */
@@ -50,6 +48,8 @@ struct mem_desc {
{ 0xc9000000, 0x00800000 } /* 8MB */
#elif defined(CONFIG_SA1100_VICTOR)
{ 0xc0000000, 0x00400000 } /* 4MB */
+#elif defined(CONFIG_SA1100_THINCLIENT)
+ { 0xc0000000, 0x01000000 } /* 16MB */
#elif defined(CONFIG_SA1100_TIFON)
{ 0xc0000000, 0x01000000 }, /* 16MB */
{ 0xc8000000, 0x01000000 } /* 16MB */
@@ -67,12 +67,24 @@ struct map_desc io_desc[] __initdata = {
{ 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
#elif defined(CONFIG_SA1100_EMPEG)
{ EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+#elif defined(CONFIG_SA1100_THINCLIENT)
+#if 1
+ /* ThinClient: only one of those... */
+// { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */
+ { 0xd0000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */
+#else
+ /* GraphicsClient: */
+ { 0xd0000000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+ { 0xd0800000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */
+#endif
#elif defined(CONFIG_SA1100_TIFON)
{ 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
{ 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
#endif
-#ifdef CONFIG_SA1101
+#if defined( CONFIG_SA1101 )
{ 0xdc000000, SA1101_BASE, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1101 */
+#elif defined( CONFIG_SA1100_THINCLIENT )
+ { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
#endif
{ 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
{ 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
diff --git a/arch/arm/mm/mm-shark.c b/arch/arm/mm/mm-shark.c
new file mode 100644
index 000000000..dc8e6e12b
--- /dev/null
+++ b/arch/arm/mm/mm-shark.c
@@ -0,0 +1,25 @@
+/*
+ * arch/arm/mm/mm-shark.c
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+#include "map.h"
+
+struct map_desc io_desc[] __initdata = {
+ { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
+ { FB_BASE , FB_START , FB_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
+ { FBREG_BASE , FBREG_START , FBREG_SIZE , DOMAIN_IO, 0, 1, 0, 0 }
+};
+
+
+#define SIZEOFMAP (sizeof(io_desc) / sizeof(io_desc[0]))
+
+unsigned int __initdata io_desc_size = SIZEOFMAP;
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index 9800643d9..13c1f2773 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -435,17 +435,35 @@ ENTRY(cpu_sa1100_proc_fin)
ldmfd sp!, {r1, pc}
.align 5
+idle: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt
+ mov r0, r0 @ safety
+ mov pc, lr
+/*
+ * Function: *_do_idle
+ * Params : r0 = call type:
+ * 0 = slow idle
+ * 1 = fast idle
+ * 2 = switch to slow processor clock
+ * 3 = switch to fast processor clock
+ */
ENTRY(cpu_sa110_do_idle)
ENTRY(cpu_sa1100_do_idle)
- mov r0, #0
- mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching
- ldr r1, =FLUSH_BASE+FLUSH_OFFSET*2 @ load from uncacheable loc
- ldr r1, [r1, #0]
- b 1f
+ mov ip, #0
+ cmp r0, #4
+ addcc pc, pc, r0, lsl #2
+ mov pc, lr
- .align 5
-1: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt
- mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching
+ b idle
+ b idle
+ b slow_clock
+ b fast_clock
+
+fast_clock: mcr p15, 0, ip, c15, c1, 2 @ enable clock switching
+ mov pc, lr
+
+slow_clock: mcr p15, 0, ip, c15, c2, 2 @ disable clock switching
+ ldr r1, =UNCACHEABLE_ADDR @ load from uncacheable loc
+ ldr r1, [r1, #0] @ force switch to MCLK
mov pc, lr
/*
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
index 102850b74..f016493ba 100644
--- a/arch/i386/boot/compressed/head.S
+++ b/arch/i386/boot/compressed/head.S
@@ -23,7 +23,6 @@
*/
.text
-#define __ASSEMBLY__
#include <linux/linkage.h>
#include <asm/segment.h>
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 36f1aafda..664b77800 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -6,6 +6,7 @@ mainmenu_name "Linux Kernel Configuration"
define_bool CONFIG_X86 y
define_bool CONFIG_ISA y
+define_bool CONFIG_SBUS n
define_bool CONFIG_UID16 y
@@ -43,11 +44,17 @@ 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
+if [ "$CONFIG_M586TSC" = "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_MK6" = "y" ]; then
+ define_bool CONFIG_X86_ALIGNMENT_16 y
+ define_bool CONFIG_X86_TSC y
+ define_bool CONFIG_X86_USE_3DNOW y
+ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+fi
if [ "$CONFIG_M686" = "y" ]; then
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
@@ -136,6 +143,8 @@ bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
if [ "$CONFIG_HOTPLUG" = "y" ] ; then
source drivers/pcmcia/Config.in
+else
+ define_bool CONFIG_PCMCIA n
fi
bool 'System V IPC' CONFIG_SYSVIPC
@@ -252,7 +261,6 @@ endmenu
source drivers/char/Config.in
-source drivers/usb/Config.in
#source drivers/misc/Config.in
@@ -279,6 +287,8 @@ if [ "$CONFIG_SOUND" != "n" ]; then
fi
endmenu
+source drivers/usb/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 15e23d91a..80f68ec31 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -3,6 +3,7 @@
#
CONFIG_X86=y
CONFIG_ISA=y
+# CONFIG_SBUS is not set
CONFIG_UID16=y
#
@@ -22,11 +23,14 @@ CONFIG_M686=y
# CONFIG_MK7 is not set
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
+CONFIG_X86_CMPXCHG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
+CONFIG_X86_L1_CACHE_BYTES=32
CONFIG_X86_TSC=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_PGE=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
# CONFIG_MICROCODE is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
@@ -104,7 +108,10 @@ CONFIG_BLK_DEV_FD=y
# 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 is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
# Networking options
@@ -185,6 +192,7 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_AEC6210 is not set
# CONFIG_AEC6210_TUNING is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD7409 is not set
# CONFIG_AMD7409_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
@@ -248,6 +256,7 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
@@ -375,6 +384,7 @@ CONFIG_PCMCIA_PCNET=y
# CONFIG_PCMCIA_SMC91C92 is not set
# CONFIG_PCMCIA_XIRC2PS is not set
# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
# CONFIG_PCMCIA_3C575 is not set
# CONFIG_PCMCIA_XIRTULIP is not set
CONFIG_NET_PCMCIA_RADIO=y
@@ -467,17 +477,13 @@ CONFIG_PCMCIA_SERIAL=y
# CONFIG_PCMCIA_SERIAL_CB is not set
#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
# File systems
#
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
CONFIG_AUTOFS4_FS=y
# CONFIG_ADFS_FS is not set
+# 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
@@ -487,27 +493,34 @@ CONFIG_AUTOFS4_FS=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW 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_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -515,6 +528,16 @@ CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -535,6 +558,11 @@ CONFIG_VGA_CONSOLE=y
# CONFIG_SOUND is not set
#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
# Kernel hacking
#
# CONFIG_MAGIC_SYSRQ is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 525bb2c07..64b3d0951 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
all: kernel.o head.o init_task.o
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
index f9410f3fd..aa09400fc 100644
--- a/arch/i386/kernel/acpi.c
+++ b/arch/i386/kernel/acpi.c
@@ -103,13 +103,57 @@ static int acpi_p_lvl3_tested = 0;
enum
{
- ACPI_ENABLED,
- ACPI_TABLES_ONLY,
- ACPI_CHIPSET_ONLY,
- ACPI_DISABLED,
+ ACPI_ENABLED = 0x00000000, // use ACPI if present
+ ACPI_DISABLED = 0x00000001, // never use ACPI
+ ACPI_TABLES_ONLY = 0x00000002, // never use chipset-specific driver
+ ACPI_CHIPSET_ONLY = 0x00000004, // always use chipset-specific driver
+ ACPI_IGNORE_ERRATA = 0x00000008, // ignore any listed platform errata
+ ACPI_COPY_TABLES = 0x00000010, // copy ACPI tables before use
+ ACPI_TRUST_TABLES = 0x00000020, // use tables even after ioremap fails
+ ACPI_SCI_DISABLED = 0x00000040, // never enable ACPI (info. only)
+ ACPI_C2_DISABLED = 0x00000080, // never enter C2
+ ACPI_C3_DISABLED = 0x00000100, // never enter C3
+ ACPI_S1_DISABLED = 0x00000200, // never enter S1
+ ACPI_S5_DISABLED = 0x00000400, // never enter S5
};
-static int acpi_enabled = ACPI_ENABLED;
+struct acpi_option_info
+{
+ const char *name;
+ unsigned long value;
+};
+
+static struct acpi_option_info acpi_options[] =
+{
+ {"on", ACPI_ENABLED},
+ {"off", ACPI_DISABLED},
+ {"tables", ACPI_TABLES_ONLY},
+ {"chipset", ACPI_CHIPSET_ONLY},
+ {"no-errata", ACPI_IGNORE_ERRATA},
+ {"copy-tables", ACPI_COPY_TABLES},
+ {"trust-tables", ACPI_TRUST_TABLES},
+ {"no-sci", ACPI_SCI_DISABLED},
+ {"no-c2", ACPI_C2_DISABLED},
+ {"no-c3", ACPI_C3_DISABLED},
+ {"no-s1", ACPI_S1_DISABLED},
+ {"no-s5", ACPI_S5_DISABLED},
+ {NULL, 0},
+};
+
+static unsigned long acpi_opts = ACPI_ENABLED;
+
+struct acpi_errata_info
+{
+ const char *oem;
+ const char *oem_table;
+ u32 oem_rev;
+ unsigned long options;
+};
+
+struct acpi_errata_info acpi_errata[] =
+{
+ {NULL, NULL, 0, 0},
+};
// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
static unsigned long acpi_slp_typ[] =
@@ -171,7 +215,7 @@ static struct ctl_table acpi_table[] =
&acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat),
0644, NULL, &acpi_do_ulong},
- {ACPI_P_LVL2_LAT, "enter_lvl2_lat",
+ {ACPI_ENTER_LVL2_LAT, "enter_lvl2_lat",
&acpi_enter_lvl2_lat, sizeof(acpi_enter_lvl2_lat),
0644, NULL, &acpi_do_ulong},
@@ -405,6 +449,16 @@ static struct acpi_table *__init acpi_map_table(u32 addr)
printk(KERN_ERR
"ACPI: unreserved table memory @ 0x%p!\n",
(void*) addr);
+
+ if (acpi_opts & ACPI_TRUST_TABLES) {
+ /* OK, trust that the table is there
+ * if it isn't you'll get an OOPS here
+ */
+ static u32 sig;
+ table = (struct acpi_table *)
+ phys_to_virt(addr);
+ sig = table->signature;
+ }
}
}
return table;
@@ -423,14 +477,33 @@ static void acpi_unmap_table(struct acpi_table *table)
/*
* Initialize an ACPI table
*/
-static void acpi_init_table(struct acpi_table_info *info,
- void *data,
- int mapped)
+static int acpi_init_table(struct acpi_table_info *info,
+ void *data,
+ int mapped)
{
struct acpi_table *table = (struct acpi_table*) data;
+
+ info->table = NULL;
+ info->size = 0;
+ info->mapped = 0;
+
+ if (!table || table->signature != info->expected_signature)
+ return -EINVAL;
+
+ if (mapped && (acpi_opts & ACPI_COPY_TABLES)) {
+ struct acpi_table *copy
+ = kmalloc(table->length, GFP_KERNEL);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(copy, table, table->length);
+ table = copy;
+ mapped = 0;
+ }
+
info->table = table;
- info->size = (size_t)(table ? table->length:0);
+ info->size = (size_t) table->length;
info->mapped = mapped;
+ return 0;
}
/*
@@ -502,22 +575,13 @@ static int __init acpi_find_tables(void)
rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2);
while (rsdt_entry_count) {
struct acpi_table *dt = acpi_map_table(*rsdt_entry);
- if (dt && dt->signature == ACPI_FACP_SIG) {
- struct acpi_facp *facp = (struct acpi_facp*) dt;
- acpi_init_table(&acpi_facp, dt, 1);
+ if (!acpi_init_table(&acpi_facp, dt, 1)) {
+ struct acpi_facp *facp
+ = (struct acpi_facp*) acpi_facp.table;
// map DSDT if it exists
dt = acpi_map_table(facp->dsdt);
- if (dt && dt->signature == ACPI_DSDT_SIG)
- acpi_init_table(&acpi_dsdt, dt, 1);
- else
- acpi_unmap_table(dt);
-
- // map FACS if it exists
- dt = acpi_map_table(facp->facs);
- if (dt && dt->signature == ACPI_FACS_SIG)
- acpi_init_table(&acpi_facs, dt, 1);
- else
+ if (acpi_init_table(&acpi_dsdt, dt, 1))
acpi_unmap_table(dt);
}
else {
@@ -769,6 +833,15 @@ static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
}
/*
+ * Is SCI to be enabled?
+ */
+static inline int
+acpi_sci_enabled(void)
+{
+ return !(acpi_opts & ACPI_SCI_DISABLED);
+}
+
+/*
* Is ACPI enabled or not?
*/
static inline int acpi_is_enabled(struct acpi_facp *facp)
@@ -781,7 +854,7 @@ static inline int acpi_is_enabled(struct acpi_facp *facp)
*/
static int acpi_enable(struct acpi_facp *facp)
{
- if (facp->smi_cmd)
+ if (facp->smi_cmd && acpi_sci_enabled())
outb(facp->acpi_enable, facp->smi_cmd);
return (acpi_is_enabled(facp) ? 0:-1);
}
@@ -791,16 +864,20 @@ static int acpi_enable(struct acpi_facp *facp)
*/
static int acpi_disable(struct acpi_facp *facp)
{
- // disable and clear any pending events
- acpi_write_gpe_enable(facp, 0);
- while (acpi_read_gpe_status(facp))
- acpi_write_gpe_status(facp, acpi_read_gpe_status(facp));
- acpi_write_pm1_enable(facp, 0);
- acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
-
- /* writing acpi_disable to smi_cmd would be appropriate
- * here but this causes a nasty crash on many systems
- */
+ if (facp->smi_cmd && acpi_sci_enabled()) {
+ // disable and clear any pending events
+ acpi_write_gpe_enable(facp, 0);
+ while (acpi_read_gpe_status(facp)) {
+ acpi_write_gpe_status(facp,
+ acpi_read_gpe_status(facp));
+ }
+ acpi_write_pm1_enable(facp, 0);
+ acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
+
+ /* writing acpi_disable to smi_cmd would be appropriate
+ * here but this causes a nasty crash on many systems
+ */
+ }
return 0;
}
@@ -860,7 +937,7 @@ static void acpi_idle(void)
sleep3:
sleep_level = 3;
if (!acpi_p_lvl3_tested) {
- printk("ACPI C3 works\n");
+ printk(KERN_INFO "ACPI C3 works\n");
acpi_p_lvl3_tested = 1;
}
wake_on_busmaster(facp);
@@ -916,7 +993,7 @@ sleep3_with_arbiter:
sleep2:
sleep_level = 2;
if (!acpi_p_lvl2_tested) {
- printk("ACPI C2 works\n");
+ printk(KERN_INFO "ACPI C2 works\n");
acpi_p_lvl2_tested = 1;
}
wake_on_busmaster(facp); /* Required to track BM activity.. */
@@ -1006,47 +1083,52 @@ static void acpi_update_clock(void)
}
}
-
/*
* Enter system sleep state
*/
-static void acpi_enter_sx(acpi_sstate_t state)
+static int acpi_enter_sx(acpi_sstate_t state)
{
- unsigned long slp_typ = acpi_slp_typ[(int) state];
- if (slp_typ != ACPI_SLP_TYP_DISABLED) {
- struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table;
- u16 typa, typb, value;
-
- // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
- typa = (slp_typ >> 8) & 0xff;
- typb = slp_typ & 0xff;
-
- typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
- typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
+ unsigned long slp_typ;
+ u16 typa, typb, value;
+ struct acpi_facp *facp;
- acpi_sleep_start = get_cmos_time();
- acpi_enter_dx(ACPI_D3);
- acpi_sleep_state = state;
+ slp_typ = acpi_slp_typ[(int) state];
+ if (slp_typ == ACPI_SLP_TYP_DISABLED)
+ return -EPERM;
- // clear wake status
- acpi_write_pm1_status(facp, ACPI_WAK);
+ // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
+ typa = (slp_typ >> 8) & 0xff;
+ typb = slp_typ & 0xff;
+
+ typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
+ typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
- // set SLP_TYPa/b and SLP_EN
- if (facp->pm1a_cnt) {
- value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
- outw(value | typa | ACPI_SLP_EN, facp->pm1a_cnt);
- }
- if (facp->pm1b_cnt) {
- value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
- outw(value | typb | ACPI_SLP_EN, facp->pm1b_cnt);
- }
+ acpi_sleep_start = get_cmos_time();
+ acpi_enter_dx(ACPI_D3);
+ acpi_sleep_state = state;
- // wait until S1 is entered
- while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) ;
- // finished sleeping, update system time
- acpi_update_clock();
- acpi_enter_dx(ACPI_D0);
+ facp = (struct acpi_facp*) acpi_facp.table;
+
+ // clear wake status
+ acpi_write_pm1_status(facp, ACPI_WAK);
+
+ // set SLP_TYPa/b and SLP_EN
+ if (facp->pm1a_cnt) {
+ value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
+ outw(value | typa | ACPI_SLP_EN, facp->pm1a_cnt);
}
+ if (facp->pm1b_cnt) {
+ value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
+ outw(value | typb | ACPI_SLP_EN, facp->pm1b_cnt);
+ }
+
+ // wait until S1 is entered
+ while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) ;
+ // finished sleeping, update system time
+ acpi_update_clock();
+ acpi_enter_dx(ACPI_D0);
+
+ return 0;
}
/*
@@ -1113,6 +1195,42 @@ static int acpi_release_ioports(struct acpi_facp *facp)
}
/*
+ * Determine if modification of value is permitted
+ */
+static int
+acpi_verify_mod(int ctl_name)
+{
+ switch (ctl_name) {
+ case ACPI_PM1_ENABLE:
+ case ACPI_GPE_ENABLE:
+ case ACPI_GPE_LEVEL:
+ if (!acpi_sci_enabled())
+ return -EPERM;
+ break;
+ case ACPI_P_LVL2_LAT:
+ case ACPI_ENTER_LVL2_LAT:
+ if (acpi_opts & ACPI_C2_DISABLED)
+ return -EPERM;
+ break;
+ case ACPI_P_LVL3_LAT:
+ case ACPI_ENTER_LVL3_LAT:
+ if (acpi_opts & ACPI_C3_DISABLED)
+ return -EPERM;
+ break;
+ case ACPI_S1_SLP_TYP:
+ case ACPI_SLEEP:
+ if (acpi_opts & ACPI_S1_DISABLED)
+ return -EPERM;
+ break;
+ case ACPI_S5_SLP_TYP:
+ if (acpi_opts & ACPI_S5_DISABLED)
+ return -EPERM;
+ break;
+ }
+ return 0;
+}
+
+/*
* Examine/modify value
*/
static int acpi_do_ulong(ctl_table *ctl,
@@ -1141,6 +1259,9 @@ static int acpi_do_ulong(ctl_table *ctl,
*len = 0;
}
else {
+ if (acpi_verify_mod(ctl->ctl_name))
+ return -EPERM;
+
size = sizeof(str) - 1;
if (size > *len)
size = *len;
@@ -1313,6 +1434,9 @@ static int acpi_do_event_reg(ctl_table *ctl,
}
else
{
+ if (acpi_verify_mod(ctl->ctl_name))
+ return -EPERM;
+
// fetch user value
size = sizeof(str) - 1;
if (size > *len)
@@ -1443,24 +1567,71 @@ static int acpi_do_sleep(ctl_table *ctl,
}
else
{
-#ifdef CONFIG_ACPI_S1_SLEEP
- acpi_enter_sx(ACPI_S1);
-#endif
+ if (acpi_verify_mod(ctl->ctl_name) || acpi_enter_sx(ACPI_S1))
+ return -EPERM;
}
file->f_pos += *len;
return 0;
}
+/*
+ * Parse command line options
+ */
+static int __init acpi_setup(char *str)
+{
+ while (str && *str) {
+ struct acpi_option_info *opt = acpi_options;
+ while (opt->name) {
+ if (!strncmp(str, opt->name, strlen(opt->name))) {
+ acpi_opts |= opt->value;
+ break;
+ }
+ opt++;
+ }
+ str = strpbrk(str, ",");
+ if (str)
+ str += strspn(str, ",");
+ }
+
+ if (acpi_opts)
+ printk(KERN_INFO "ACPI: options 0x%08lx\n", acpi_opts);
+
+ return 1;
+}
+
+/*
+ * kernel/module command line interfaces are both "acpi=OPTION,OPTION,..."
+ */
+__setup("acpi=", acpi_setup);
+
+static char * __initdata acpi = NULL;
+
+MODULE_DESCRIPTION("ACPI driver");
+MODULE_PARM(acpi, "s");
+MODULE_PARM_DESC(acpi, "ACPI driver command line");
/*
* Initialize and enable ACPI
*/
-static int __init acpi_init(void)
+int __init acpi_init(void)
{
struct acpi_facp *facp = NULL;
- switch (acpi_enabled) {
- case ACPI_ENABLED:
+ if (acpi)
+ acpi_setup(acpi);
+
+ if (acpi_opts & ACPI_DISABLED) {
+ return -ENODEV;
+ }
+ else if (acpi_opts & ACPI_TABLES_ONLY) {
+ if (acpi_find_tables())
+ return -ENODEV;
+ }
+ else if (acpi_opts & ACPI_CHIPSET_ONLY) {
+ if (acpi_find_chipset())
+ return -ENODEV;
+ }
+ else {
switch (acpi_find_tables()) {
case 0:
// found valid ACPI tables
@@ -1474,17 +1645,6 @@ static int __init acpi_init(void)
// found broken ACPI tables
return -ENODEV;
}
- break;
- case ACPI_TABLES_ONLY:
- if (acpi_find_tables())
- return -ENODEV;
- break;
- case ACPI_CHIPSET_ONLY:
- if (acpi_find_chipset())
- return -ENODEV;
- break;
- case ACPI_DISABLED:
- return -ENODEV;
}
facp = (struct acpi_facp*) acpi_facp.table;
@@ -1502,12 +1662,14 @@ static int __init acpi_init(void)
* control in the /proc interfaces.
*/
if (facp->p_lvl2_lat
- && facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
+ && facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT
+ && !acpi_verify_mod(ACPI_P_LVL2_LAT)) {
acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl2_lat);
acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
}
if (facp->p_lvl3_lat
- && facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
+ && facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT
+ && !acpi_verify_mod(ACPI_P_LVL3_LAT)) {
acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat);
acpi_enter_lvl3_lat
= ACPI_uS_TO_TMR_TICKS(facp->p_lvl3_lat * 5);
@@ -1519,6 +1681,7 @@ static int __init acpi_init(void)
}
if (facp->sci_int
+ && acpi_sci_enabled()
&& request_irq(facp->sci_int,
acpi_irq,
SA_INTERRUPT | SA_SHIRQ,
@@ -1529,6 +1692,10 @@ static int __init acpi_init(void)
goto err_out;
}
+#ifndef CONFIG_ACPI_S1_SLEEP
+ acpi_opts |= ACPI_S1_DISABLED;
+#endif
+
acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
pm_power_off = acpi_power_off;
@@ -1559,7 +1726,7 @@ err_out:
/*
* Disable and deinitialize ACPI
*/
-static void __exit acpi_exit(void)
+void __exit acpi_exit(void)
{
struct acpi_facp *facp = (struct acpi_facp*) acpi_facp.table;
@@ -1570,7 +1737,7 @@ static void __exit acpi_exit(void)
acpi_disable(facp);
acpi_release_ioports(facp);
- if (facp->sci_int)
+ if (facp->sci_int && acpi_sci_enabled())
free_irq(facp->sci_int, &acpi_facp);
acpi_destroy_tables();
@@ -1581,29 +1748,5 @@ static void __exit acpi_exit(void)
pm_active = 0;
}
-/*
- * Parse kernel command line options
- */
-static int __init acpi_setup(char *str)
-{
- while (str && *str) {
- if (strncmp(str, "on", 2) == 0)
- acpi_enabled = ACPI_ENABLED;
- else if (strncmp(str, "tables", 6) == 0)
- acpi_enabled = ACPI_TABLES_ONLY;
- else if (strncmp(str, "chipset", 7) == 0)
- acpi_enabled = ACPI_CHIPSET_ONLY;
- else if (strncmp(str, "off", 3) == 0)
- acpi_enabled = ACPI_DISABLED;
- str = strpbrk(str, ",");
- if (str)
- str += strspn(str, ",");
- }
- return 1;
-}
-
-__setup("acpi=", acpi_setup);
-
module_init(acpi_init);
module_exit(acpi_exit);
-
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 7a8a17b63..ee759f2bc 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -70,22 +70,28 @@ startup_32:
*/
#define cr4_bits mmu_cr4_features-__PAGE_OFFSET
cmpl $0,cr4_bits
- je 1f
- movl %cr4,%eax # Turn on 4Mb pages
+ je 3f
+ movl %cr4,%eax # Turn on paging options (PSE,PAE,..)
orl cr4_bits,%eax
movl %eax,%cr4
+ jmp 3f
+1:
#endif
/*
- * Setup paging (intialize tables, then switch them on)
+ * Initialize page tables
*/
-1:
movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */
movl $007,%eax /* "007" doesn't mean with right to kill, but
PRESENT+RW+USER */
-1: stosl
+2: stosl
add $0x1000,%eax
cmp $empty_zero_page-__PAGE_OFFSET,%edi
- jne 1b
+ jne 2b
+
+/*
+ * Enable paging
+ */
+3:
movl $swapper_pg_dir-__PAGE_OFFSET,%eax
movl %eax,%cr3 /* set the page table pointer.. */
movl %cr0,%eax
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index d2ba2fd9c..a96540d6e 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -862,7 +862,7 @@ unsigned long probe_irq_on(void)
*/
/**
- * probe_irq_mask
+ * probe_irq_mask - scan a bitmap of interrupt lines
* @val: mask of interrupts to consider
*
* Scan the ISA bus interrupt lines and return a bitmap of
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 1d6203f65..f5a035cc7 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -1281,7 +1281,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
} /* End Function mtrr_add */
/**
- * mtrr_del
+ * mtrr_del - delete a memory type region
* @reg: Register returned by mtrr_add
* @base: Physical base address
* @size: Size of region
diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c
index 942de9c79..cc3f8e1da 100644
--- a/arch/i386/kernel/pci-i386.c
+++ b/arch/i386/kernel/pci-i386.c
@@ -228,7 +228,7 @@ static void __init pcibios_allocate_resources(int pass)
if (!pr || request_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
/* We'll assign a new address later */
- r->start -= r->end;
+ r->end -= r->start;
r->start = 0;
}
}
@@ -317,6 +317,8 @@ int pcibios_enable_resources(struct pci_dev *dev)
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ cmd |= PCI_COMMAND_MEMORY;
if (cmd != old_cmd) {
printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index b588642cc..fb5d6b75f 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -1188,7 +1188,7 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r
} else if (newirq) {
DBG(" -> [VIA] set to %02x\n", newirq);
x = (pirq & 1) ? ((x & 0x0f) | (newirq << 4)) : ((x & 0xf0) | newirq);
- pci_write_config_byte(router, reg, y);
+ pci_write_config_byte(router, reg, x);
msg = "VIA-NEW";
} else DBG(" -> [VIA] sink\n");
break;
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 46292496d..71407c0ea 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -727,7 +727,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE && INITRD_START) {
- if (INITRD_START + INITRD_SIZE < (max_low_pfn << PAGE_SHIFT)) {
+ if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start =
INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
@@ -863,7 +863,7 @@ static int __init amd_model(struct cpuinfo_x86 *c)
rdmsr(0xC0000082, l, h);
if((l&0x0000FFFF)==0)
{
- l=(1<<0)|(mbytes/4);
+ l=(1<<0)|((mbytes/4)<<1);
save_flags(flags);
__cli();
__asm__ __volatile__ ("wbinvd": : :"memory");
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
index 5c824c08c..2394245a6 100644
--- a/arch/i386/lib/Makefile
+++ b/arch/i386/lib/Makefile
@@ -3,7 +3,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
L_TARGET = lib.a
L_OBJS = checksum.o old-checksum.o delay.o \
diff --git a/arch/i386/math-emu/Makefile b/arch/i386/math-emu/Makefile
index 68b327a2a..5564d8712 100644
--- a/arch/i386/math-emu/Makefile
+++ b/arch/i386/math-emu/Makefile
@@ -10,7 +10,7 @@ PARANOID = -DPARANOID
CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) $(PARANOID) -c $<
+ $(CC) $(AFLAGS) $(PARANOID) -c $<
# From 'C' language sources:
C_OBJS =fpu_entry.o errors.o \
diff --git a/arch/ia64/boot/Makefile b/arch/ia64/boot/Makefile
index cba4fad66..5228d6c57 100644
--- a/arch/ia64/boot/Makefile
+++ b/arch/ia64/boot/Makefile
@@ -11,9 +11,9 @@
LINKFLAGS = -static -T bootloader.lds
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+ $(CPP) $(AFLAGS) -traditional -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
OBJECTS = bootloader.o
TARGETS =
diff --git a/arch/ia64/config.in b/arch/ia64/config.in
index b0d924d14..b7cce3d73 100644
--- a/arch/ia64/config.in
+++ b/arch/ia64/config.in
@@ -4,6 +4,8 @@ mainmenu_option next_comment
comment 'General setup'
define_bool CONFIG_IA64 y
+define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
choice 'IA-64 system type' \
"Generic CONFIG_IA64_GENERIC \
@@ -50,7 +52,12 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
bool 'PCI support' CONFIG_PCI
source drivers/pci/Config.in
-source drivers/pcmcia/Config.in
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+if [ "$CONFIG_HOTPLUG" = "y" ]; then
+ source drivers/pcmcia/Config.in
+else
+ define_bool CONFIG_PCMCIA n
+fi
mainmenu_option next_comment
comment 'Code maturity level options'
@@ -134,7 +141,6 @@ fi
endmenu
source drivers/char/Config.in
-source drivers/usb/Config.in
#source drivers/misc/Config.in
source fs/Config.in
@@ -161,6 +167,8 @@ if [ "$CONFIG_SOUND" != "n" ]; then
fi
endmenu
+source drivers/usb/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 1618d5401..12854f121 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -6,6 +6,8 @@
# General setup
#
CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
# CONFIG_IA64_GENERIC is not set
CONFIG_IA64_HP_SIM=y
# CONFIG_IA64_SGI_SN1_SIM is not set
@@ -25,10 +27,7 @@ CONFIG_KCORE_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_PCI=y
CONFIG_PCI_NAMES=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
#
@@ -119,6 +118,7 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
# CONFIG_BLK_DEV_AEC6210 is not set
# CONFIG_AEC6210_TUNING is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD7409 is not set
# CONFIG_AMD7409_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
diff --git a/arch/ia64/dig/Makefile b/arch/ia64/dig/Makefile
index cfc48eec1..8d0544ee5 100644
--- a/arch/ia64/dig/Makefile
+++ b/arch/ia64/dig/Makefile
@@ -6,9 +6,9 @@
#
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+ $(CPP) $(AFLAGS) -o $*.s $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+ $(CC) $(AFLAGS) -c -o $*.o $<
all: dig.a
diff --git a/arch/ia64/ia32/Makefile b/arch/ia64/ia32/Makefile
index 674a6eb6e..82017941c 100644
--- a/arch/ia64/ia32/Makefile
+++ b/arch/ia64/ia32/Makefile
@@ -3,9 +3,9 @@
#
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+ $(CPP) $(AFLAGS) -o $*.s $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+ $(CC) $(AFLAGS) -c -o $*.o $<
all: ia32.o
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 8d4e4a8fd..00eca716d 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -2298,7 +2298,9 @@ copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
return 0;
}
-extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
+extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
+ unsigned long new_flags, void *data);
+extern long do_sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void *data);
#define SMBFS_NAME "smbfs"
@@ -2328,7 +2330,6 @@ sys32_mount(char *dev_name, char *dir_name, char *type,
(void *)AA(data));
} else {
unsigned long dev_page, dir_page, data_page;
- mm_segment_t old_fs;
err = copy_mount_stuff_to_kernel((const void *)dev_name,
&dev_page);
@@ -2348,13 +2349,9 @@ sys32_mount(char *dev_name, char *dir_name, char *type,
do_smb_super_data_conv((void *)data_page);
else
panic("The problem is here...");
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_mount((char *)dev_page, (char *)dir_page,
+ err = do_sys_mount((char *)dev_page, (char *)dir_page,
(char *)type_page, new_flags,
(void *)data_page);
- set_fs(old_fs);
-
if(data_page)
free_page(data_page);
dir_out:
diff --git a/arch/ia64/kdb/Makefile b/arch/ia64/kdb/Makefile
index 0b29d6b35..2e8db3fc4 100644
--- a/arch/ia64/kdb/Makefile
+++ b/arch/ia64/kdb/Makefile
@@ -13,7 +13,7 @@ MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS)
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
L_TARGET = kdb.a
L_OBJS = kdbsupport.o kdb_io.o kdb_bt.o kdb_traps.o
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 7a2fcd214..6631d33c3 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -8,9 +8,9 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+ $(CPP) $(AFLAGS) -o $*.s $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+ $(CC) $(AFLAGS) -c -o $*.o $<
all: kernel.o head.o init_task.o
diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile
index 88a4aadd4..376d0d6d4 100644
--- a/arch/ia64/lib/Makefile
+++ b/arch/ia64/lib/Makefile
@@ -3,7 +3,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@
+ $(CC) $(AFLAGS) -c $< -o $@
OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \
__moddi3.o __modsi3.o __umoddi3.o __umodsi3.o \
diff --git a/arch/ia64/sn/Makefile b/arch/ia64/sn/Makefile
index 3c8810967..b35ce21ff 100644
--- a/arch/ia64/sn/Makefile
+++ b/arch/ia64/sn/Makefile
@@ -10,9 +10,9 @@ CFLAGS := $(CFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSN -DSOFTSDV \
AFLAGS := $(AFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSOFTSDV
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+ $(CPP) $(AFLAGS) -o $*.s $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+ $(CC) $(AFLAGS) -c -o $*.o $<
all: sn.a
diff --git a/arch/ia64/sn/sn1/Makefile b/arch/ia64/sn/sn1/Makefile
index 23758c473..fbb8e83ab 100644
--- a/arch/ia64/sn/sn1/Makefile
+++ b/arch/ia64/sn/sn1/Makefile
@@ -10,9 +10,9 @@ CFLAGS := $(CFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSN -DSOFTSDV \
AFLAGS := $(AFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSOFTSDV
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
+ $(CPP) $(AFLAGS) -o $*.s $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
+ $(CC) $(AFLAGS) -c -o $*.o $<
all: sn1.a
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index edcbeb98a..bc6eec37a 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -16,16 +16,15 @@ mainmenu_option next_comment
comment 'Platform dependent setup'
define_bool CONFIG_ISA n
+define_bool CONFIG_PCMCIA n
+
bool 'Amiga support' CONFIG_AMIGA
bool 'Atari support' CONFIG_ATARI
-if [ "$CONFIG_ATARI" = "y" ]; then
- bool ' Hades support' CONFIG_HADES
- if [ "$CONFIG_HADES" = "y" ]; then
- define_bool CONFIG_PCI y
- fi
-fi
-if [ "$CONFIG_HADES" != "y" ]; then
- define_bool CONFIG_PCI n
+dep_bool ' Hades support' CONFIG_HADES $CONFIG_ATARI
+if [ "$CONFIG_HADES" = "y" ]; then
+ define_bool CONFIG_PCI y
+else
+ define_bool CONFIG_PCI n
fi
bool 'Macintosh support' CONFIG_MAC
if [ "$CONFIG_MAC" = "y" ]; then
@@ -421,19 +420,21 @@ fi
if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
tristate 'HP DCA serial support' CONFIG_HPDCA
fi
-if [ "$CONFIG_SUN3X" = "y" ]; then
- bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS
- if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
- bool ' Sun keyboard support' CONFIG_SUN_KEYBOARD
- bool ' Sun mouse support' CONFIG_SUN_MOUSE
- if [ "$CONFIG_SUN_MOUSE" != "n" ]; then
- define_bool CONFIG_BUSMOUSE y
- fi
- define_bool CONFIG_SBUS y
- define_bool CONFIG_SBUSCHAR y
- define_bool CONFIG_SUN_SERIAL y
- fi
+
+dep_bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS $CONFIG_SUN3X
+dep_bool ' Sun keyboard support' CONFIG_SUN_KEYBOARD $CONFIG_SUN3X_ZS
+dep_bool ' Sun mouse support' CONFIG_SUN_MOUSE $CONFIG_SUN3X_ZS
+if [ "$CONFIG_SUN_MOUSE" = "y" ]; then
+ define_bool CONFIG_BUSMOUSE y
+fi
+if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
+ define_bool CONFIG_SBUS y
+ define_bool CONFIG_SBUSCHAR y
+ define_bool CONFIG_SUN_SERIAL y
+else
+ define_bool CONFIG_SBUS n
fi
+
if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
"$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
"$CONFIG_SUN3X" = "y" ]; then
@@ -483,7 +484,7 @@ comment 'Sound support'
tristate 'Sound support' CONFIG_SOUND
if [ "$CONFIG_SOUND" != "n" ]; then
- dep_tristate ' Amiga or Atari DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND
+ source drivers/sound/dmasound/Config.in
fi
endmenu
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
index d7261f600..400e38961 100644
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -12,8 +12,10 @@ CONFIG_EXPERIMENTAL=y
# Platform dependent setup
#
# CONFIG_ISA is not set
+# CONFIG_PCMCIA is not set
CONFIG_AMIGA=y
# CONFIG_ATARI is not set
+# CONFIG_HADES is not set
# CONFIG_PCI is not set
# CONFIG_MAC is not set
# CONFIG_APOLLO is not set
@@ -195,6 +197,10 @@ CONFIG_AMIGA_BUILTIN_SERIAL=y
# CONFIG_GVPIOEXT_LP is not set
# CONFIG_GVPIOEXT_PLIP is not set
# CONFIG_MULTIFACE_III_TTY is not set
+# CONFIG_SUN3X_ZS is not set
+# CONFIG_SUN_KEYBOARD is not set
+# CONFIG_SUN_MOUSE is not set
+# CONFIG_SBUS is not set
# CONFIG_SERIAL_CONSOLE is not set
# CONFIG_USERIAL is not set
# CONFIG_WATCHDOG is not set
diff --git a/arch/m68k/fpsp040/Makefile b/arch/m68k/fpsp040/Makefile
index bbfc0b174..acd06e79a 100644
--- a/arch/m68k/fpsp040/Makefile
+++ b/arch/m68k/fpsp040/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
OS_TARGET := fpsp.o
diff --git a/arch/m68k/ifpsp060/Makefile b/arch/m68k/ifpsp060/Makefile
index 7836197a6..9dce0a568 100644
--- a/arch/m68k/ifpsp060/Makefile
+++ b/arch/m68k/ifpsp060/Makefile
@@ -5,7 +5,7 @@
# for more details.
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
OS_TARGET := ifpsp.o
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index c51e43802..afd9e4040 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
ifndef CONFIG_SUN3
all: head.o kernel.o
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index 22fe6cb6d..b9480aeb6 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -3,7 +3,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@
+ $(CC) $(AFLAGS) -traditional -c $< -o $@
L_TARGET = lib.a
L_OBJS = ashrdi3.o lshrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o
diff --git a/arch/m68k/math-emu/Makefile b/arch/m68k/math-emu/Makefile
index 0e22edc96..78d295d6b 100644
--- a/arch/m68k/math-emu/Makefile
+++ b/arch/m68k/math-emu/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(EXTRA_CFLAGS) $(AFLAGS) -traditional -c $< -o $*.o
#EXTRA_CFLAGS=-DFPU_EMU_DEBUG
diff --git a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile
index 9a34b3034..577667e5c 100644
--- a/arch/m68k/sun3/Makefile
+++ b/arch/m68k/sun3/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -Wa,-m68020 -c $< -o $*.o
+ $(CC) $(AFLAGS) -traditional -Wa,-m68020 -c $< -o $*.o
O_TARGET := sun3.o
O_OBJS := config.o idprom.o mmu_emu.o sun3ints.o leds.o dvma.o sbus.o intersil.o
diff --git a/arch/mips/config.in b/arch/mips/config.in
index d0bc594ff..9e6e664d2 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -32,6 +32,8 @@ unset CONFIG_ISA
unset CONFIG_MIPS_JAZZ
unset CONFIG_VIDEO_G364
+define_bool CONFIG_SBUS n
+
if [ "$CONFIG_ALGOR_P4032" = "y" ]; then
define_bool CONFIG_PCI y
fi
@@ -154,8 +156,10 @@ if [ "$CONFIG_ISA" = "y" ]; then
source drivers/pnp/Config.in
fi
-if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
- source drivers/pcmcia/Config.in
+if [ "$CONFIG_HOTPLUG" = "y" ] ; then
+ source drivers/pcmcia/Config.in
+else
+ define_bool CONFIG_PCMCIA n
fi
source drivers/block/Config.in
@@ -242,15 +246,7 @@ if [ "$CONFIG_NET" = "y" ]; then
endmenu
fi
-if [ "$CONFIG_SGI_IP22" != "y" -a \
- "$CONFIG_DECSTATION" != "y" -a \
- "$CONFIG_BAGET_MIPS" != "y" ]; then
-
- mainmenu_option next_comment
- comment 'AX.25 network device drivers'
- source drivers/net/hamradio/Config.in
- endmenu
-
+if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
mainmenu_option next_comment
comment 'ISDN subsystem'
@@ -324,9 +320,6 @@ if [ "$CONFIG_SGI_IP22" = "y" ]; then
endmenu
fi
-#The ones having USB should include it
-#source drivers/usb/Config.in
-
source fs/Config.in
if [ "$CONFIG_VT" = "y" ]; then
@@ -356,6 +349,8 @@ if [ "$CONFIG_SGI_IP22" = "y" ]; then
source drivers/sgi/Config.in
fi
+source drivers/usb/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 85385be9e..d4570eb4e 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -19,6 +19,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_OLIVETTI_M700 is not set
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_SBUS is not set
CONFIG_ARC32=y
# CONFIG_ISA is not set
# CONFIG_PCI is not set
@@ -61,6 +62,7 @@ CONFIG_SYSCTL=y
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
+# CONFIG_PCMCIA is not set
#
# Block devices
@@ -68,6 +70,8 @@ CONFIG_KMOD=y
# 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
@@ -75,7 +79,10 @@ CONFIG_KMOD=y
# 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 is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
# Networking options
@@ -160,12 +167,12 @@ CONFIG_SCSI_SGIWD93=y
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
@@ -173,18 +180,19 @@ CONFIG_SCSI_SGIWD93=y
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_DEBUG is not set
#
@@ -213,6 +221,7 @@ CONFIG_FONT_8x16=y
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
# CONFIG_ADFS_FS is not set
+# 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
@@ -222,27 +231,34 @@ CONFIG_AUTOFS4_FS=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW 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_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -250,6 +266,16 @@ CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -294,6 +320,11 @@ CONFIG_SGI_DS1286=y
# CONFIG_SGI_NEWPORT_GFX is not set
#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation
index 64b06c4d8..852319984 100644
--- a/arch/mips/defconfig-decstation
+++ b/arch/mips/defconfig-decstation
@@ -19,6 +19,7 @@ CONFIG_DECSTATION=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_SBUS is not set
# CONFIG_ISA is not set
# CONFIG_PCI is not set
@@ -47,32 +48,19 @@ CONFIG_ELF_KERNEL=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_NET=y
-
-#
-# PCMCIA/CardBus support
-#
-# CONFIG_PCMCIA is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
#
-# Loadable module support
+# Parallel port support
#
+# CONFIG_PARPORT is not set
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
-
-#
-# TURBOchannel support
-#
CONFIG_TC=y
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+# CONFIG_PCMCIA is not set
#
# Block devices
@@ -80,6 +68,8 @@ CONFIG_TC=y
# 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
@@ -87,7 +77,10 @@ CONFIG_TC=y
# 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 is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
# Networking options
@@ -139,19 +132,6 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_SCHED is not set
#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-# CONFIG_PHONE_IXJ 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
#
CONFIG_SCSI=y
@@ -178,20 +158,18 @@ CONFIG_SCSI_CONSTANTS=y
#
CONFIG_SCSI_DECNCR=y
# CONFIG_SCSI_DECSII is not set
-CONFIG_SCSI_DECNCR=y
-# CONFIG_SCSI_DECSII is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
@@ -199,33 +177,22 @@ CONFIG_SCSI_DECNCR=y
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_DEBUG 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_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
# Network device support
#
CONFIG_NETDEVICES=y
@@ -235,7 +202,7 @@ CONFIG_NETDEVICES=y
CONFIG_DECLANCE=y
#
-# DECstation Character devices
+# DECStation Character devices
#
# CONFIG_VT is not set
CONFIG_SERIAL=y
@@ -248,17 +215,13 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_RTC is not set
#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
# 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_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -268,33 +231,51 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS 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_NTFS_RW 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_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
# CONFIG_ROOT_NFS is not set
# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
# CONFIG_SUNRPC is not set
# CONFIG_LOCKD is not set
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -315,6 +296,11 @@ CONFIG_ULTRIX_PARTITION=y
# CONFIG_NLS is not set
#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22
index 85385be9e..d4570eb4e 100644
--- a/arch/mips/defconfig-ip22
+++ b/arch/mips/defconfig-ip22
@@ -19,6 +19,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_OLIVETTI_M700 is not set
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_SBUS is not set
CONFIG_ARC32=y
# CONFIG_ISA is not set
# CONFIG_PCI is not set
@@ -61,6 +62,7 @@ CONFIG_SYSCTL=y
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
+# CONFIG_PCMCIA is not set
#
# Block devices
@@ -68,6 +70,8 @@ CONFIG_KMOD=y
# 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
@@ -75,7 +79,10 @@ CONFIG_KMOD=y
# 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 is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
# Networking options
@@ -160,12 +167,12 @@ CONFIG_SCSI_SGIWD93=y
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
@@ -173,18 +180,19 @@ CONFIG_SCSI_SGIWD93=y
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_DEBUG is not set
#
@@ -213,6 +221,7 @@ CONFIG_FONT_8x16=y
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
# CONFIG_ADFS_FS is not set
+# 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
@@ -222,27 +231,34 @@ CONFIG_AUTOFS4_FS=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW 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_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -250,6 +266,16 @@ CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -294,6 +320,11 @@ CONFIG_SGI_DS1286=y
# CONFIG_SGI_NEWPORT_GFX is not set
#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index eca74b629..742cc9b9d 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -696,7 +696,7 @@ asmlinkage int irix_pause(void)
return -EINTR;
}
-extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
+extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data);
/* XXX need more than this... */
diff --git a/arch/mips64/config.in b/arch/mips64/config.in
index 7f22687c8..b2454b8cc 100644
--- a/arch/mips64/config.in
+++ b/arch/mips64/config.in
@@ -58,6 +58,8 @@ if [ "$CONFIG_PCI" != "y" ]; then
define_bool CONFIG_PCI n
fi
+define_bool CONFIG_SBUS n
+
mainmenu_option next_comment
comment 'CPU selection'
@@ -81,7 +83,14 @@ bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
bool 'Networking support' CONFIG_NET
source drivers/pci/Config.in
-source drivers/pcmcia/Config.in
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
+if [ "$CONFIG_HOTPLUG" = "y" ] ; then
+ source drivers/pcmcia/Config.in
+else
+ define_bool CONFIG_PCMCIA n
+fi
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
@@ -194,7 +203,6 @@ endmenu
source drivers/char/Config.in
-source drivers/usb/Config.in
#source drivers/misc/Config.in
@@ -231,6 +239,8 @@ if [ "$CONFIG_SGI_IP22" = "y" ]; then
source drivers/sgi/Config.in
fi
+source drivers/usb/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index 4f555127e..410152c15 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -21,6 +21,7 @@ CONFIG_COHERENT_IO=y
CONFIG_PCI=y
CONFIG_QL_ISP_A64=y
# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
#
# CPU selection
@@ -39,10 +40,7 @@ CONFIG_CPU_R10000=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_NET=y
CONFIG_PCI_NAMES=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
@@ -75,7 +73,10 @@ CONFIG_PCI_NAMES=y
# 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 is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
# Networking options
@@ -154,12 +155,12 @@ CONFIG_SD_EXTRA_DEVS=40
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
@@ -185,11 +186,9 @@ CONFIG_SD_EXTRA_DEVS=40
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
# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
#
# I2O device support
@@ -327,17 +326,13 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_DRM_TDFX is not set
#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
# 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_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -347,33 +342,51 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS 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_NTFS_RW 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_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -397,6 +410,11 @@ CONFIG_KCORE_ELF=y
# CONFIG_SOUND is not set
#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22
index c0973c4d0..b4ccf3abd 100644
--- a/arch/mips64/defconfig-ip22
+++ b/arch/mips64/defconfig-ip22
@@ -18,6 +18,7 @@ CONFIG_BOARD_SCACHE=y
CONFIG_ARC_MEMORY=y
# CONFIG_ISA is not set
# CONFIG_PCI is not set
+# CONFIG_SBUS is not set
#
# CPU selection
@@ -34,10 +35,7 @@ CONFIG_CPU_R5000=y
#
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_NET=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
@@ -57,6 +55,8 @@ CONFIG_BINFMT_ELF=y
# 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
@@ -64,7 +64,10 @@ CONFIG_BINFMT_ELF=y
# 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 is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
# Networking options
@@ -244,17 +247,13 @@ CONFIG_VT_CONSOLE=y
# CONFIG_DRM_TDFX is not set
#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
# 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_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -264,33 +263,51 @@ CONFIG_VT_CONSOLE=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS 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_NTFS_RW 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_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -318,6 +335,11 @@ CONFIG_KCORE_ELF=y
CONFIG_SGI_DS1286=y
#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index 4f555127e..410152c15 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -21,6 +21,7 @@ CONFIG_COHERENT_IO=y
CONFIG_PCI=y
CONFIG_QL_ISP_A64=y
# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
#
# CPU selection
@@ -39,10 +40,7 @@ CONFIG_CPU_R10000=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_NET=y
CONFIG_PCI_NAMES=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
@@ -75,7 +73,10 @@ CONFIG_PCI_NAMES=y
# 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 is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
# Networking options
@@ -154,12 +155,12 @@ CONFIG_SD_EXTRA_DEVS=40
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
@@ -185,11 +186,9 @@ CONFIG_SD_EXTRA_DEVS=40
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
# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
#
# I2O device support
@@ -327,17 +326,13 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_DRM_TDFX is not set
#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
# 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_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -347,33 +342,51 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS 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_NTFS_RW 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_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -397,6 +410,11 @@ CONFIG_KCORE_ELF=y
# CONFIG_SOUND is not set
#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips64/sgi-ip27/ip27-memory.c b/arch/mips64/sgi-ip27/ip27-memory.c
index 60881d60a..063fb5a41 100644
--- a/arch/mips64/sgi-ip27/ip27-memory.c
+++ b/arch/mips64/sgi-ip27/ip27-memory.c
@@ -277,7 +277,7 @@ void __init paging_init(void)
zones_size[ZONE_DMA] = end_pfn + 1 - start_pfn;
free_area_init_node(node, NODE_DATA(node), zones_size,
- start_pfn << PAGE_SHIFT);
+ start_pfn << PAGE_SHIFT, 0);
if ((PLAT_NODE_DATA_STARTNR(node) +
PLAT_NODE_DATA_SIZE(node)) > pagenr)
pagenr = PLAT_NODE_DATA_STARTNR(node) +
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 26beffc40..f6b37dcb4 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -63,13 +63,13 @@
* Like the LANCE driver:
* 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.
+ * cep->tx_busy 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 'lp->tx_full' flag.
+ * The send packet thread has partial control over the Tx ring and the
+ * 'cep->tx_busy' flag. It sets the tx_busy flag whenever it's queuing a Tx
+ * packet. If the next queue slot is empty, it clears the tx_busy flag when
+ * finished otherwise it sets the 'lp->tx_full' flag.
*
* The MBX has a control register external to the MPC8xx that has some
* control of the Ethernet interface. Control Register 1 has the
@@ -149,8 +149,10 @@ struct cpm_enet_private {
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
scc_t *sccp;
struct net_device_stats stats;
- char tx_full;
+ uint tx_full;
+ uint tx_busy;
unsigned long lock;
+ int interrupt;
};
static int cpm_enet_open(struct net_device *dev);
@@ -190,10 +192,7 @@ cpm_enet_open(struct net_device *dev)
* a simple way to do that.
*/
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
return 0; /* Always succeed */
}
@@ -205,7 +204,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
/* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
+ if (cep->tx_busy) {
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 200)
return 1;
@@ -233,22 +232,23 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
#endif
- dev->tbusy=0;
+ cep->tx_busy=0;
dev->trans_start = jiffies;
return 0;
}
/* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+ * done with atomic_swap(1, cep->tx_busy), but set_bit() works as well.
+ */
+ if (test_and_set_bit(0, (void*)&cep->tx_busy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
if (test_and_set_bit(0, (void*)&cep->lock) != 0) {
printk("%s: tx queue lock!.\n", dev->name);
- /* don't clear dev->tbusy flag. */
+ /* don't clear cep->tx_busy flag. */
return 1;
}
@@ -258,7 +258,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
#ifndef final_version
if (bdp->cbd_sc & BD_ENET_TX_READY) {
/* Ooops. All transmit buffers are full. Bail out.
- * This should not happen, since dev->tbusy should be set.
+ * This should not happen, since cep->tx_busy should be set.
*/
printk("%s: tx queue full!.\n", dev->name);
cep->lock = 0;
@@ -314,7 +314,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (bdp->cbd_sc & BD_ENET_TX_READY)
cep->tx_full = 1;
else
- dev->tbusy=0;
+ cep->tx_busy=0;
restore_flags(flags);
cep->cur_tx = (cbd_t *)bdp;
@@ -335,10 +335,10 @@ cpm_enet_interrupt(void *dev_id)
int must_restart;
cep = (struct cpm_enet_private *)dev->priv;
- if (dev->interrupt)
+ if (cep->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
+ cep->interrupt = 1;
/* Get the interrupt events that caused us to be here.
*/
@@ -399,7 +399,7 @@ cpm_enet_interrupt(void *dev_id)
/* Free the sk buffer associated with this last transmit.
*/
- dev_kfree_skb(cep->tx_skbuff[cep->skb_dirty]/*, FREE_WRITE*/);
+ dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
/* Update pointer to next buffer descriptor to be transmitted.
@@ -421,10 +421,10 @@ cpm_enet_interrupt(void *dev_id)
/* Since we have freed up a buffer, the ring is no longer
* full.
*/
- if (cep->tx_full && dev->tbusy) {
+ if (cep->tx_full && cep->tx_busy) {
cep->tx_full = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ cep->tx_busy = 0;
+ netif_wake_queue(dev);
}
cep->dirty_tx = (cbd_t *)bdp;
@@ -455,7 +455,7 @@ cpm_enet_interrupt(void *dev_id)
printk("CPM ENET: BSY can't happen.\n");
}
- dev->interrupt = 0;
+ cep->interrupt = 0;
return;
}
@@ -564,6 +564,7 @@ cpm_enet_close(struct net_device *dev)
{
/* Don't know what to do yet.
*/
+ netif_stop_queue(dev);
return 0;
}
diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
index 94e900ceb..575f68a28 100644
--- a/arch/ppc/8xx_io/uart.c
+++ b/arch/ppc/8xx_io/uart.c
@@ -28,6 +28,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
+#include <linux/serialP.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
@@ -1937,6 +1938,7 @@ static int rs_8xx_open(struct tty_struct *tty, struct file * filp)
printk("rs_open returning after block_til_ready with %d\n",
retval);
#endif
+ MOD_DEC_USE_COUNT;
return retval;
}
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 7c3f13822..4b578da45 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -72,7 +72,7 @@ MAKETREEBOOT = $(MAKE) -C arch/$(ARCH)/treeboot
ifdef CONFIG_8xx
SUBDIRS += arch/ppc/8xx_io
-DRIVERS += arch/ppc/8xx_io/8xx_io.a drivers/net/net.a
+DRIVERS += arch/ppc/8xx_io/8xx_io.a
endif
ifdef CONFIG_APUS
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 604205565..33fa87999 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -16,9 +16,9 @@
.c.o:
$(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -D__BOOTER__ -c -o $*.o $<
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+ $(CPP) $(AFLAGS) -traditional -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
ZOFF = 0
ZSZ = 0
diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile
index 216b289ed..e988ce9de 100644
--- a/arch/ppc/chrpboot/Makefile
+++ b/arch/ppc/chrpboot/Makefile
@@ -12,9 +12,9 @@
.c.o:
$(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+ $(CPP) $(AFLAGS) -traditional -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
LD_ARGS = -Ttext 0x00400000
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index e21140d9d..e9499fbc9 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -83,12 +83,13 @@ mainmenu_option next_comment
comment 'General setup'
define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS 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
+ if [ "$CONFIG_6xx" = "y" -o "$CONFIG_PPC64" = "y" ]; then
define_bool CONFIG_PCI y
else
# CONFIG_8xx
@@ -115,6 +116,8 @@ bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
if [ "$CONFIG_HOTPLUG" = "y" ]; then
source drivers/pcmcia/Config.in
+else
+ define_bool CONFIG_PCMCIA n
fi
source drivers/parport/Config.in
@@ -247,14 +250,13 @@ source drivers/video/Config.in
endmenu
source drivers/char/Config.in
-source drivers/usb/Config.in
source fs/Config.in
mainmenu_option next_comment
comment 'Sound'
tristate 'Sound card support' CONFIG_SOUND
if [ "$CONFIG_SOUND" != "n" ]; then
- dep_tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND
+ source drivers/sound/dmasound/Config.in
source drivers/sound/Config.in
fi
@@ -264,6 +266,8 @@ if [ "$CONFIG_8xx" = "y" ]; then
source arch/ppc/8xx_io/Config.in
fi
+source drivers/usb/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index 1f5784701..8717bc055 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -34,6 +34,7 @@ CONFIG_KMOD=y
# General setup
#
# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
CONFIG_PCI=y
CONFIG_NET=y
CONFIG_SYSCTL=y
@@ -45,6 +46,7 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_PCI_NAMES is not set
# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
#
# Parallel port support
@@ -185,6 +187,7 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
# CONFIG_BLK_DEV_AEC6210 is not set
# CONFIG_AEC6210_TUNING is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD7409 is not set
# CONFIG_AMD7409_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c
index d14c7380a..d5baa3747 100644
--- a/arch/ppc/kernel/feature.c
+++ b/arch/ppc/kernel/feature.c
@@ -184,14 +184,14 @@ feature_init(void)
if (controller_count)
printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
-#ifdef CONFIG_PMAC_PBOOK
-#ifdef CONFIG_DMASOUND_MODULE
- /* On PowerBooks, we disable the sound chip when dmasound is a module */
+#if defined(CONFIG_PMAC_PBOOK) && !defined(CONFIG_DMASOUND_AWACS)
+ /* On PowerBooks, we disable the sound chip when dmasound is a module
+ * or not used at all
+ */
if (controller_count && find_devices("via-pmu") != NULL) {
feature_clear(controllers[0].device, FEATURE_Sound_power);
feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
}
-#endif
#endif
}
diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c
index 36e886d0c..a417bed2e 100644
--- a/arch/ppc/kernel/m8xx_setup.c
+++ b/arch/ppc/kernel/m8xx_setup.c
@@ -276,7 +276,6 @@ m8xx_init_IRQ(void)
int i;
void cpm_interrupt_init(void);
- ppc8xx_pic.irq_offset = 0;
for ( i = 0 ; i < NR_SIU_INTS ; i++ )
irq_desc[i].handler = &ppc8xx_pic;
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index e454e952d..b6a16900c 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -3,7 +3,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $*.o
+ $(CC) $(AFLAGS) -c $< -o $*.o
O_TARGET = lib.o
O_OBJS = checksum.o string.o strcase.o
diff --git a/arch/ppc/math-emu/math.c b/arch/ppc/math-emu/math.c
index aed5c7062..146b17df4 100644
--- a/arch/ppc/math-emu/math.c
+++ b/arch/ppc/math-emu/math.c
@@ -233,14 +233,14 @@ do_mathemu(struct pt_regs *regs)
case LFD:
idx = (insn >> 16) & 0x1f;
sdisp = (insn & 0xffff);
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
lfd(op0, op1, op2, op3);
break;
case LFDU:
idx = (insn >> 16) & 0x1f;
sdisp = (insn & 0xffff);
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
lfd(op0, op1, op2, op3);
regs->gpr[idx] = (unsigned long)op1;
@@ -248,21 +248,21 @@ do_mathemu(struct pt_regs *regs)
case STFD:
idx = (insn >> 16) & 0x1f;
sdisp = (insn & 0xffff);
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
stfd(op0, op1, op2, op3);
break;
case STFDU:
idx = (insn >> 16) & 0x1f;
sdisp = (insn & 0xffff);
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
stfd(op0, op1, op2, op3);
regs->gpr[idx] = (unsigned long)op1;
break;
case OP63:
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
- op1 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
fmr(op0, op1, op2, op3);
break;
default:
@@ -359,28 +359,28 @@ do_mathemu(struct pt_regs *regs)
switch (type) {
case AB:
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
- op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
- op2 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+ op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
break;
case AC:
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
- op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
- op2 = (void *)&current->tss.fpr[(insn >> 6) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+ op2 = (void *)&current->thread.fpr[(insn >> 6) & 0x1f];
break;
case ABC:
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
- op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
- op2 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
- op3 = (void *)&current->tss.fpr[(insn >> 6) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+ op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
+ op3 = (void *)&current->thread.fpr[(insn >> 6) & 0x1f];
break;
case D:
idx = (insn >> 16) & 0x1f;
sdisp = (insn & 0xffff);
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
break;
@@ -390,22 +390,22 @@ do_mathemu(struct pt_regs *regs)
goto illegal;
sdisp = (insn & 0xffff);
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)(regs->gpr[idx] + sdisp);
break;
case X:
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
break;
case XA:
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
- op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
break;
case XB:
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
- op1 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
break;
case XE:
@@ -413,13 +413,13 @@ do_mathemu(struct pt_regs *regs)
if (!idx)
goto illegal;
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]);
break;
case XEU:
idx = (insn >> 16) & 0x1f;
- op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)((idx ? regs->gpr[idx] : 0)
+ regs->gpr[(insn >> 11) & 0x1f]);
break;
@@ -427,8 +427,8 @@ do_mathemu(struct pt_regs *regs)
case XCR:
op0 = (void *)&regs->ccr;
op1 = (void *)((insn >> 23) & 0x7);
- op2 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
- op3 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ op2 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
+ op3 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
break;
case XCRL:
@@ -448,7 +448,7 @@ do_mathemu(struct pt_regs *regs)
case XFLB:
op0 = (void *)((insn >> 17) & 0xff);
- op1 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
break;
default:
diff --git a/arch/ppc/math-emu/sfp-machine.h b/arch/ppc/math-emu/sfp-machine.h
index 73b7e69c6..ac39cb054 100644
--- a/arch/ppc/math-emu/sfp-machine.h
+++ b/arch/ppc/math-emu/sfp-machine.h
@@ -166,7 +166,7 @@ extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
#include <linux/kernel.h>
#include <linux/sched.h>
-#define __FPU_FPSCR (current->tss.fpscr)
+#define __FPU_FPSCR (current->thread.fpscr)
/* We only actually write to the destination register
* if exceptions signalled (if any) will not trap.
diff --git a/arch/ppc/mbxboot/Makefile b/arch/ppc/mbxboot/Makefile
index 59b95c5df..6f9fd0135 100644
--- a/arch/ppc/mbxboot/Makefile
+++ b/arch/ppc/mbxboot/Makefile
@@ -16,9 +16,9 @@
.c.o:
$(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
.S.s:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
+ $(CPP) $(AFLAGS) -traditional -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+ $(CC) $(AFLAGS) -traditional -c -o $*.o $<
ZOFF = 0
ZSZ = 0
@@ -26,7 +26,7 @@ IOFF = 0
ISZ = 0
TFTPIMAGE=/tftpboot/zImage.mbx
-ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000
OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 0427f2166..5fee4463b 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -182,34 +182,44 @@ bad_page_fault(struct pt_regs *regs, unsigned long address)
#ifdef CONFIG_8xx
-unsigned long va_to_phys(unsigned long address)
+/* The pgtable.h claims some functions generically exist, but I
+ * can't find them......
+ */
+pte_t *find_pte(struct mm_struct *mm, unsigned long address)
{
pgd_t *dir;
pmd_t *pmd;
pte_t *pte;
-
- dir = pgd_offset(current->mm, address & PAGE_MASK);
- if (dir)
- {
+
+ dir = pgd_offset(mm, address & PAGE_MASK);
+ if (dir) {
pmd = pmd_offset(dir, address & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
+ if (pmd && pmd_present(*pmd)) {
pte = pte_offset(pmd, address & PAGE_MASK);
- if (pte && pte_present(*pte))
- {
- return(pte_page(*pte) | (address & ~(PAGE_MASK-1)));
+ if (pte && pte_present(*pte)) {
+ return(pte);
}
- } else
- {
+ }
+ else {
return (0);
}
- } else
- {
+ }
+ else {
return (0);
}
return (0);
}
+unsigned long va_to_phys(unsigned long address)
+{
+ pte_t *pte;
+
+ pte = find_pte(current->mm, address);
+ if (pte)
+ return((unsigned long)(pte_page(*pte)) | (address & ~(PAGE_MASK-1)));
+ return (0);
+}
+
void
print_8xx_pte(struct mm_struct *mm, unsigned long addr)
{
@@ -227,8 +237,8 @@ print_8xx_pte(struct mm_struct *mm, unsigned long addr)
printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
(long)pgd, (long)pte, (long)pte_val(*pte));
#define pp ((long)pte_val(*pte))
- printk(" RPN: %05x PP: %x SPS: %x SH: %x "
- "CI: %x v: %x\n",
+ printk(" RPN: %05x PP: %x SPS: %x SH: %lx "
+ "CI: %lx v: %lx\n",
pp>>12, /* rpn */
(pp>>10)&3, /* pp */
(pp>>3)&1, /* small */
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 83591c86c..1857ef33b 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.2 1999/12/23 12:13:53 gniibe Exp gniibe $
+# $Id: Makefile,v 1.4 2000/03/08 15:14:14 gniibe 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
diff --git a/arch/sh/config.in b/arch/sh/config.in
index e3bfd113c..2ee913c3c 100644
--- a/arch/sh/config.in
+++ b/arch/sh/config.in
@@ -48,6 +48,7 @@ mainmenu_option next_comment
comment 'General setup'
define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
bool 'Networking support' CONFIG_NET
@@ -73,6 +74,8 @@ bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
if [ "$CONFIG_HOTPLUG" = "y" ] ; then
source drivers/pcmcia/Config.in
+else
+ define_bool CONFIG_PCMCIA n
fi
bool 'System V IPC' CONFIG_SYSVIPC
@@ -170,8 +173,6 @@ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
source drivers/char/pcmcia/Config.in
fi
-#source drivers/misc/Config.in
-
source fs/Config.in
if [ "$CONFIG_VT" = "y" ]; then
diff --git a/arch/sh/defconfig b/arch/sh/defconfig
index fad2ab8b1..337e46956 100644
--- a/arch/sh/defconfig
+++ b/arch/sh/defconfig
@@ -29,10 +29,12 @@ CONFIG_MEMORY_START=0c000000
# General setup
#
# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
# CONFIG_NET is not set
CONFIG_CF_ENABLER=y
# CONFIG_PCI is not set
# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index efa2fb109..8996a13dc 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -7,7 +7,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
O_TARGET := kernel.o
O_OBJS := process.o signal.o entry.o traps.o irq.o irq_onchip.o \
@@ -29,7 +29,7 @@ all: kernel.o head.o init_task.o
entry.o: entry.S
head.o: head.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
+ $(CC) $(AFLAGS) -traditional -c $*.S -o $*.o
clean:
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
index 77bb7938b..46ad20f53 100644
--- a/arch/sh/kernel/entry.S
+++ b/arch/sh/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.55 2000/03/05 01:48:58 gniibe Exp $
+/* $Id: entry.S,v 1.71 2000/03/22 13:29:33 gniibe Exp $
*
* linux/arch/sh/entry.S
*
@@ -33,10 +33,9 @@
*
* syscall #
* ssr
- * r15 = stack pointer
* r0
* ...
- * r14
+ * r15 = stack pointer
* gbr
* mach
* macl
@@ -46,7 +45,7 @@
*/
/*
- * these are offsets into the task-struct.
+ * These are offsets into the task-struct.
*/
state = 0
flags = 4
@@ -78,8 +77,8 @@ MMU_TEA = 0xff00000c ! TLB Exception Address Register
/* Offsets to the stack */
SYSCALL_NR = 0
SR = 4
-SP = 8
-R0 = 12
+R0 = 8
+SP = (8+15*4)
#define k0 r0
#define k1 r1
@@ -96,7 +95,7 @@ R0 = 12
k2 scratch (Exception code)
k3 scratch (Return address)
k4 Stack base = current+8192
- k5 reserved
+ k5 Global Interrupt Mask (0--15)
k6 reserved
k7 reserved
*/
@@ -115,109 +114,113 @@ R0 = 12
! this first version depends *much* on C implementation.
!
-#define DO_FAULT(write) \
- mov.l 4f,r0; \
- mov.l @r0,r6; \
- /* STI */ \
- mov.l 3f,r1; \
- stc sr,r0; \
- and r1,r0; \
- ldc r0,sr; \
- /* */ \
- mov r15,r4; \
- mov.l 2f,r0; \
- jmp @r0; \
- mov #write,r5;
+#define RESTORE_FLAGS() \
+ mov.l @(SR,$r15), $r0; \
+ and #0xf0, $r0; \
+ shlr8 $r0; \
+ cmp/eq #0x0f, $r0; \
+ bt 9f; \
+ mov.l __INV_IMASK, $r1; \
+ stc $sr, $r0; \
+ and $r1, $r0; \
+ stc $r5_bank, $r1; \
+ or $r1, $r0; \
+ ldc $r0, $sr
.balign 4
tlb_protection_violation_load:
tlb_miss_load:
- mov #-1,r0
- mov.l r0,@r15 ! syscall nr = -1
- DO_FAULT(0)
+ mov #-1, $r0
+ mov.l $r0, @$r15 ! syscall nr = -1
+ mov.l 2f, $r0
+ mov.l @$r0, $r6
+ RESTORE_FLAGS()
+9: mov $r15, $r4
+ mov.l 1f, $r0
+ jmp @$r0
+ mov #0, $r5
.balign 4
tlb_protection_violation_store:
tlb_miss_store:
initial_page_write:
- mov #-1,r0
- mov.l r0,@r15 ! syscall nr = -1
- DO_FAULT(1)
+ mov #-1, $r0
+ mov.l $r0, @$r15 ! syscall nr = -1
+ mov.l 2f, $r0
+ mov.l @$r0, $r6
+ RESTORE_FLAGS()
+9: mov $r15, $r4
+ mov.l 1f, $r0
+ jmp @$r0
+ mov #1, $r5
.balign 4
-2: .long SYMBOL_NAME(do_page_fault)
-3: .long 0xefffffff ! BL=0
-4: .long MMU_TEA
+1: .long SYMBOL_NAME(do_page_fault)
+2: .long MMU_TEA
#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
.balign 4
/* Unwind the stack and jmp to the debug entry */
debug:
- add #4,r15 ! skip syscall number
- mov.l @r15+,r11 ! SSR
- mov.l @r15+,r10 ! original stack
- mov.l @r15+,r0
- mov.l @r15+,r1
- mov.l @r15+,r2
- mov.l @r15+,r3
- mov.l @r15+,r4
- mov.l @r15+,r5
- mov.l @r15+,r6
- mov.l @r15+,r7
- stc sr,r14
- mov.l 8f,r9 ! BL =1, RB=1
- or r9,r14
- ldc r14,sr ! here, change the register bank
- mov r10,k0
- mov r11,k1
- mov.l @r15+,r8
- mov.l @r15+,r9
- mov.l @r15+,r10
- mov.l @r15+,r11
- mov.l @r15+,r12
- mov.l @r15+,r13
- mov.l @r15+,r14
- ldc.l @r15+,gbr
- lds.l @r15+,mach
- lds.l @r15+,macl
- lds.l @r15+,pr
- ldc.l @r15+,spc
- mov k0,r15
+ add #4, $r15 ! skip syscall number
+ mov.l @$r15+, $r11 ! SSR
+ mov.l @$r15+, $r0
+ mov.l @$r15+, $r1
+ mov.l @$r15+, $r2
+ mov.l @$r15+, $r3
+ mov.l @$r15+, $r4
+ mov.l @$r15+, $r5
+ mov.l @$r15+, $r6
+ mov.l @$r15+, $r7
+ stc $sr, $r14
+ mov.l 1f, $r9 ! BL =1, RB=1
+ or $r9, $r14
+ ldc $r14, $sr ! here, change the register bank
+ mov $r11, $k1
+ mov.l @$r15+, $r8
+ mov.l @$r15+, $r9
+ mov.l @$r15+, $r10
+ mov.l @$r15+, $r11
+ mov.l @$r15+, $r12
+ mov.l @$r15+, $r13
+ mov.l @$r15+, $r14
+ mov.l @$r15+, $k0
+ ldc.l @$r15+, $gbr
+ lds.l @$r15+, $mach
+ lds.l @$r15+, $macl
+ lds.l @$r15+, $pr
+ ldc.l @$r15+, $spc
+ mov $k0, $r15
!
- mov.l 9f,k0
- jmp @k0
- ldc k1,ssr
+ mov.l 2f, $k0
+ jmp @$k0
+ ldc $k1, $ssr
.balign 4
-8: .long 0x300000f0
-9: .long 0xa0000100
+1: .long 0x300000f0
+2: .long 0xa0000100
#endif
.balign 4
error:
- ! STI
- mov.l 2f,r1
- stc sr,r0
- and r1,r0
- ldc r0,sr
!
- mov.l 1f,r1
- mov #-1,r0
- jmp @r1
- mov.l r0,@r15 ! syscall nr = -1
+ RESTORE_FLAGS()
+9: mov.l 1f, $r1
+ mov #-1, $r0
+ jmp @$r1
+ mov.l $r0, @$r15 ! syscall nr = -1
.balign 4
1: .long SYMBOL_NAME(do_exception_error)
-2: .long 0xefffffff ! BL=0
-badsys: mov #-ENOSYS,r0
+badsys: mov #-ENOSYS, $r0
rts ! go to ret_from_syscall..
- mov.l r0,@(R0,r15)
+ mov.l $r0, @(R0,$r15)
!
!
!
ENTRY(ret_from_fork)
bra SYMBOL_NAME(ret_from_syscall)
- add #4,r15 ! pop down bogus r0 (see switch_to MACRO)
+ add #4, $r15 ! pop down bogus r0 (see switch_to MACRO)
!
! The immediate value of "trapa" indicates the number of arguments
@@ -226,83 +229,77 @@ ENTRY(ret_from_fork)
! Note that TRA register contains the value = Imm x 4.
!
system_call:
- mov.l 1f,r2
- mov.l @r2,r8
+ mov.l 1f, $r2
+ mov.l @$r2, $r8
!
! DEBUG DEBUG
- ! mov.l led,r1
- ! mov r0,r2
- ! mov.b r2,@r1
+ ! mov.l led, $r1
+ ! mov $r0, $r2
+ ! mov.b $r2, @$r1
!
#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
- mov #0x20,r1
- extu.b r1,r1
- shll2 r1
- cmp/hs r1,r8
+ mov #0x20, $r1
+ extu.b $r1, $r1
+ shll2 $r1
+ cmp/hs $r1, $r8
bt debug
#endif
- ! STI
- mov.l 2f,r1
- stc sr,r2
- and r1,r2
- ldc r2,sr
!
- mov.l __n_sys,r1
- cmp/hs r1,r0
- bt/s badsys
- mov r0,r2
+ mov $r0, $r2
+ RESTORE_FLAGS()
+9: mov.l __n_sys, $r1
+ cmp/hs $r1, $r2
+ bt badsys
!
- stc ksp,r1 !
- mov.l __tsk_flags,r0 !
- add r0,r1 !
- mov.l @r1,r0 ! Is it trace?
- tst #PF_TRACESYS,r0
+ stc $ksp, $r1
+ mov.l __tsk_flags, $r0
+ add $r0, $r1 !
+ mov.l @$r1, $r0 ! Is it trace?
+ tst #PF_TRACESYS, $r0
bt 5f
! Trace system call
- mov #-ENOSYS,r1
- mov.l r1,@(R0,r15)
- mov.l 3f,r1
- jsr @r1
+ mov #-ENOSYS, $r1
+ mov.l $r1, @(R0,$r15)
+ mov.l 3f, $r1
+ jsr @$r1
nop
- mova 4f,r0
+ mova 3f, $r0
bra 6f
- lds r0,pr
- !
-5: mova ret,r0 ! normal case
- lds r0,pr
- ! Build the stack frame if TRA > 0
+ lds $r0, $pr
!
-6: mov r2,r3
- mov r8,r2
- cmp/pl r8
- bf 9f
- mov.l @(SP,r15),r0 ! get original stack
-7: add #-4,r8
-8: mov.l @(r0,r8),r1 ! May cause address error exception..
- mov.l r1,@-r15
- cmp/pl r8
+5: mova syscall_ret, $r0
+ lds $r0, $pr
+ ! Build the stack frame if TRA > 0
+6: mov $r2, $r3
+ mov $r8, $r2
+ cmp/pl $r8
+ bf 0f
+ mov #SP, $r0
+ mov.l @($r0,$r15), $r0 ! get original stack
+7: add #-4, $r8
+4: mov.l @($r0,$r8), $r1 ! May cause address error exception..
+ mov.l $r1, @-$r15
+ cmp/pl $r8
bt 7b
!
-9: mov r3,r0
- shll2 r0 ! x4
- mov.l __sct,r1
- add r1,r0
- mov.l @r0,r1
- jmp @r1
- mov r2,r8
-
+0: mov $r3, $r0
+ shll2 $r0 ! x4
+ mov.l __sct, $r1
+ add $r1, $r0
+ mov.l @$r0, $r1
+ jmp @$r1
+ mov $r2, $r8
! In case of trace
.balign 4
-4: add r8,r15 ! pop off the arguments
- mov.l r0,@(R0,r15) ! save the return value
- mov.l 3f,r1
- mova SYMBOL_NAME(ret_from_syscall),r0
- jmp @r1
- lds r0,pr
+3: add $r8, $r15 ! pop off the arguments
+ mov.l $r0, @(R0,$r15) ! save the return value
+ mov.l 2f, $r1
+ mova SYMBOL_NAME(ret_from_syscall), $r0
+ jmp @$r1
+ lds $r0, $pr
.balign 4
-3: .long SYMBOL_NAME(syscall_trace)
-2: .long 0xefffffff ! BL=0
1: .long TRA
+2: .long SYMBOL_NAME(syscall_trace)
__n_sys: .long NR_syscalls
__sct: .long SYMBOL_NAME(sys_call_table)
__tsk_flags: .long flags-8192 ! offset from stackbase to tsk->flags
@@ -311,85 +308,80 @@ led: .long 0xa8000000 ! For my board -- gN
.section .fixup,"ax"
fixup_syscall_argerr:
rts
- mov.l 1f,r0
+ mov.l 1f, $r0
1: .long -22 ! -EINVAL
.previous
.section __ex_table, "a"
.balign 4
- .long 8b,fixup_syscall_argerr
+ .long 4b,fixup_syscall_argerr
.previous
+ .balign 4
reschedule:
- mova SYMBOL_NAME(ret_from_syscall),r0
- mov.l 1f,r1
- jmp @r1
- lds r0,pr
+ mova SYMBOL_NAME(ret_from_syscall), $r0
+ mov.l 1f, $r1
+ jmp @$r1
+ lds $r0, $pr
.balign 4
1: .long SYMBOL_NAME(schedule)
ENTRY(ret_from_irq)
- mov.l @(SR,r15),r0 ! get status register
- shll r0
- shll r0 ! kernel space?
+ mov.l @(SR,$r15), $r0 ! get status register
+ shll $r0
+ shll $r0 ! kernel space?
bt restore_all ! Yes, it's from kernel, go back soon
- ! STI
- mov.l 1f, $r1
- stc $sr, $r2
- and $r1, $r2
- ldc $r2, $sr
!
- bra ret_with_reschedule
+ RESTORE_FLAGS()
+9: bra ret_with_reschedule
nop
ENTRY(ret_from_exception)
- mov.l @(SR,r15),r0 ! get status register
- shll r0
- shll r0 ! kernel space?
+ mov.l @(SR,$r15), $r0 ! get status register
+ shll $r0
+ shll $r0 ! kernel space?
bt restore_all ! Yes, it's from kernel, go back soon
- ! STI
- mov.l 1f, $r1
- stc $sr, $r2
- and $r1, $r2
- ldc $r2, $sr
!
- bra ret_from_syscall
+ RESTORE_FLAGS()
+9: bra ret_from_syscall
nop
.balign 4
-1: .long 0xefffffff ! BL=0
+__INV_IMASK:
+ .long 0xffffff0f ! ~(IMASK)
.balign 4
-ret: add r8,r15 ! pop off the arguments
- mov.l r0,@(R0,r15) ! save the return value
+syscall_ret:
+ add $r8, $r15 ! pop off the arguments
+ mov.l $r0, @(R0,$r15) ! save the return value
/* fall through */
ENTRY(ret_from_syscall)
- mov.l __softirq_state,r0
- mov.l @r0,r1
- mov.l @(4,r0),r2
- tst r2,r1
+ mov.l __softirq_state, $r0
+ mov.l @$r0, $r1
+ mov.l @(4,$r0), $r2
+ tst $r2, $r1
bt ret_with_reschedule
handle_softirq:
- mov.l __do_softirq,r0
- jsr @r0
+ mov.l __do_softirq, $r0
+ jsr @$r0
nop
ret_with_reschedule:
- stc ksp,r1
- mov.l __minus8192,r0
- add r0,r1
- mov.l @(need_resched,r1),r0
- tst #0xff,r0
+ stc $ksp, $r1
+ mov.l __minus8192, $r0
+ add $r0, $r1
+ mov.l @(need_resched,$r1), $r0
+ tst #0xff, $r0
bf reschedule
- mov.l @(sigpending,r1),r0
- tst #0xff,r0
+ mov.l @(sigpending,$r1), $r0
+ tst #0xff, $r0
bt restore_all
signal_return:
- mov r15,r4
- mov #0,r5
- mov.l __do_signal,r1
- mova restore_all,r0
- jmp @r1
- lds r0,pr
+ mov $r15, $r4
+ mov #0, $r5
+ mov.l __do_signal, $r1
+ mova restore_all, $r0
+ jmp @$r1
+ lds $r0, $pr
.balign 4
__do_signal:
.long SYMBOL_NAME(do_signal)
@@ -407,56 +399,57 @@ restore_all:
jsr @$r1
stc $sr, $r4
#endif
- add #4,r15 ! Skip syscall number
- mov.l @r15+,r11 ! Got SSR into R11
+ add #4, $r15 ! Skip syscall number
+ mov.l @$r15+, $r11 ! Got SSR into R11
#if defined(__SH4__)
mov $r11, $r12
#endif
!
- mov.l 1f,r1
- stc sr,r0
- and r1,r0 ! Get IMASK+FD
- mov.l 2f,r1
- and r1,r11
- or r0,r11 ! Inherit the IMASK+FD value of SR
+ mov.l 1f, $r1
+ stc $sr, $r0
+ and $r1, $r0 ! Get FD
+ mov.l 2f, $r1
+ and $r1, $r11
+ or $r0, $r11 ! Inherit the FD value of SR
+ stc $r5_bank, $r0
+ or $r0, $r11 ! Inherit the IMASK value
!
- mov.l @r15+,r10 ! original stack
- mov.l @r15+,r0
- mov.l @r15+,r1
- mov.l @r15+,r2
- mov.l @r15+,r3
- mov.l @r15+,r4
- mov.l @r15+,r5
- mov.l @r15+,r6
- mov.l @r15+,r7
- stc sr,r14
- mov.l __blrb_flags,r9 ! BL =1, RB=1
- or r9,r14
- ldc r14,sr ! here, change the register bank
- mov r10,k0
- mov r11,k1
+ mov.l @$r15+, $r0
+ mov.l @$r15+, $r1
+ mov.l @$r15+, $r2
+ mov.l @$r15+, $r3
+ mov.l @$r15+, $r4
+ mov.l @$r15+, $r5
+ mov.l @$r15+, $r6
+ mov.l @$r15+, $r7
+ stc $sr, $r14
+ mov.l __blrb_flags, $r9 ! BL =1, RB=1
+ or $r9, $r14
+ ldc $r14, $sr ! here, change the register bank
+ mov $r11, $k1
#if defined(__SH4__)
mov $r12, $k2
#endif
- mov.l @r15+,r8
- mov.l @r15+,r9
- mov.l @r15+,r10
- mov.l @r15+,r11
- mov.l @r15+,r12
- mov.l @r15+,r13
- mov.l @r15+,r14
- ldc.l @r15+,gbr
- lds.l @r15+,mach
- lds.l @r15+,macl
- lds.l @r15+,pr
- ldc.l @r15+,spc
- ldc k1,ssr
+ mov.l @$r15+, $r8
+ mov.l @$r15+, $r9
+ mov.l @$r15+, $r10
+ mov.l @$r15+, $r11
+ mov.l @$r15+, $r12
+ mov.l @$r15+, $r13
+ mov.l @$r15+, $r14
+ mov.l @$r15+, $k0 ! original stack
+ ldc.l @$r15+, $gbr
+ lds.l @$r15+, $mach
+ lds.l @$r15+, $macl
+ lds.l @$r15+, $pr
+ ldc.l @$r15+, $spc
+ ldc $k1, $ssr
#if defined(__SH4__)
shll $k1
shll $k1
bf 9f ! user mode
/* Kernel to kernel transition */
- mov.l 3f, $k1
+ mov.l 1f, $k1
tst $k1, $k2
bf 9f ! it hadn't FPU
! Kernel to kernel and FPU was used
@@ -496,7 +489,7 @@ restore_all:
lds.l @$r15+, $fpul
9:
#endif
- mov k0,r15
+ mov $k0, $r15
rte
nop
@@ -510,9 +503,8 @@ __init_task_flags:
__PF_USEDFPU:
.long PF_USEDFPU
#endif
-1: .long 0x000080f0 ! IMASK+FD
+1: .long 0x00008000 ! FD
2: .long 0xffff7f0f ! ~(IMASK+FD)
-3: .long 0x00008000 ! FD=1
! Exception Vector Base
!
@@ -524,10 +516,10 @@ ENTRY(vbr_base)
!
.balign 256,0,256
general_exception:
- mov.l 1f,k2
- mov.l 2f,k3
+ mov.l 1f, $k2
+ mov.l 2f, $k3
bra handle_exception
- mov.l @k2,k2
+ mov.l @$k2, $k2
.balign 4
2: .long SYMBOL_NAME(ret_from_exception)
1: .long EXPEVT
@@ -535,17 +527,17 @@ general_exception:
!
.balign 1024,0,1024
tlb_miss:
- mov.l 1f,k2
- mov.l 4f,k3
+ mov.l 1f, $k2
+ mov.l 4f, $k3
bra handle_exception
- mov.l @k2,k2
+ mov.l @$k2, $k2
!
.balign 512,0,512
interrupt:
- mov.l 2f,k2
- mov.l 3f,k3
+ mov.l 2f, $k2
+ mov.l 3f, $k3
bra handle_exception
- mov.l @k2,k2
+ mov.l @$k2, $k2
.balign 4
1: .long EXPEVT
@@ -559,9 +551,9 @@ handle_exception:
! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
! save all registers onto stack.
!
- stc ssr,k0 ! from kernel space?
- shll k0 ! Check MD bit (bit30)
- shll k0
+ stc $ssr, $k0 ! from kernel space?
+ shll $k0 ! Check MD bit (bit30)
+ shll $k0
#if defined(__SH4__)
bf/s 8f ! it's from user to kernel transition
mov $r15, $k0 ! save original stack to k0
@@ -569,6 +561,7 @@ handle_exception:
mov.l 2f, $k1
stc $ssr, $k0
tst $k1, $k0
+ mov.l 4f, $k1
bf/s 9f ! FPU is not used
mov $r15, $k0 ! save original stack to k0
! FPU is used, save FPU
@@ -593,64 +586,63 @@ handle_exception:
fmov.s $fr1, @-$r15
fmov.s $fr0, @-$r15
bra 9f
- mov #0, $k1
+ mov.l 3f, $k1
#else
+ mov.l 3f, $k1
bt/s 9f ! it's from kernel to kernel transition
- mov r15,k0 ! save original stack to k0 anyway
+ mov $r15, $k0 ! save original stack to k0 anyway
#endif
8: /* User space to kernel */
- mov kernel_sp, $r15 ! change to kernel stack
-#if defined(__SH4__)
- mov.l 2f, $k1 ! let kernel release FPU
-#endif
-9: stc.l spc,@-r15
- sts.l pr,@-r15
+ mov $kernel_sp, $r15 ! change to kernel stack
+ mov.l 4f, $k1 ! let kernel release FPU
+9: stc.l $spc, @-$r15
+ sts.l $pr, @-$r15
!
- lds k3,pr ! Set the return address to pr
+ lds $k3, $pr ! Set the return address to pr
!
- sts.l macl,@-r15
- sts.l mach,@-r15
- stc.l gbr,@-r15
- mov.l r14,@-r15
+ sts.l $macl, @-$r15
+ sts.l $mach, @-$r15
+ stc.l $gbr, @-$r15
+ mov.l $k0, @-$r15 ! save orignal stack
+ mov.l $r14, @-$r15
!
- stc sr,r14 ! Back to normal register bank, and
-#if defined(__SH4__)
- or $k1, $r14 ! may release FPU
-#endif
- mov.l 3f,k1
- and k1,r14 ! ...
- ldc r14,sr ! ...changed here.
+ stc $sr, $r14 ! Back to normal register bank, and
+ or $k1, $r14 ! Block all interrupts, may release FPU
+ mov.l 5f, $k1
+ and $k1, $r14 ! ...
+ ldc $r14, $sr ! ...changed here.
!
- mov.l r13,@-r15
- mov.l r12,@-r15
- mov.l r11,@-r15
- mov.l r10,@-r15
- mov.l r9,@-r15
- mov.l r8,@-r15
- mov.l r7,@-r15
- mov.l r6,@-r15
- mov.l r5,@-r15
- mov.l r4,@-r15
- mov.l r3,@-r15
- mov.l r2,@-r15
- mov.l r1,@-r15
- mov.l r0,@-r15
- stc.l r0_bank,@-r15 ! save orignal stack
- stc.l ssr,@-r15
- mov.l r0,@-r15 ! push r0 again (for syscall number)
+ mov.l $r13, @-$r15
+ mov.l $r12, @-$r15
+ mov.l $r11, @-$r15
+ mov.l $r10, @-$r15
+ mov.l $r9, @-$r15
+ mov.l $r8, @-$r15
+ mov.l $r7, @-$r15
+ mov.l $r6, @-$r15
+ mov.l $r5, @-$r15
+ mov.l $r4, @-$r15
+ mov.l $r3, @-$r15
+ mov.l $r2, @-$r15
+ mov.l $r1, @-$r15
+ mov.l $r0, @-$r15
+ stc.l $ssr, @-$r15
+ mov.l $r0, @-$r15 ! push $r0 again (for syscall number)
! Then, dispatch to the handler, according to the excepiton code.
- stc k_ex_code,r1
- shlr2 r1
- shlr r1
- mov.l 1f,r0
- add r1,r0
- mov.l @r0,r0
- jmp @r0
- mov.l @r15,r0 ! recovering r0..
+ stc $k_ex_code, $r1
+ shlr2 $r1
+ shlr $r1
+ mov.l 1f, $r0
+ add $r1, $r0
+ mov.l @$r0, $r0
+ jmp @$r0
+ mov.l @$r15, $r0 ! recovering $r0..
.balign 4
1: .long SYMBOL_NAME(exception_handling_table)
2: .long 0x00008000 ! FD=1
-3: .long 0xdfffffff ! RB=0, leave BL=1
+3: .long 0x000000f0 ! FD=0, IMASK=15
+4: .long 0x000080f0 ! FD=1, IMASK=15
+5: .long 0xcfffffff ! RB=0, BL=0
none:
rts
@@ -679,7 +671,7 @@ ENTRY(exception_handling_table)
ENTRY(nmi_slot)
.long none ! Not implemented yet
ENTRY(user_break_point_trap)
- .long error ! Not implemented yet
+ .long break_point_trap
ENTRY(interrupt_table)
! external hardware
.long SYMBOL_NAME(do_IRQ) ! 0000
@@ -985,6 +977,8 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_setfsuid) /* 215 */
.long SYMBOL_NAME(sys_setfsgid)
.long SYMBOL_NAME(sys_pivot_root)
+ .long SYMBOL_NAME(sys_mincore)
+ .long SYMBOL_NAME(sys_madvise)
/*
* NOTE!! This doesn't have to be exact - we just have
@@ -992,7 +986,7 @@ ENTRY(sys_call_table)
* entries. Don't panic if you notice that this hasn't
* been shrunk every time we add a new system call.
*/
- .rept NR_syscalls-217
+ .rept NR_syscalls-219
.long SYMBOL_NAME(sys_ni_syscall)
.endr
diff --git a/arch/sh/kernel/fpu.c b/arch/sh/kernel/fpu.c
index 335902c1d..5301a1333 100644
--- a/arch/sh/kernel/fpu.c
+++ b/arch/sh/kernel/fpu.c
@@ -1,4 +1,4 @@
-/* $Id: fpu.c,v 1.27 2000/03/05 01:48:34 gniibe Exp $
+/* $Id: fpu.c,v 1.29 2000/03/22 13:42:10 gniibe Exp $
*
* linux/arch/sh/kernel/fpu.c
*
@@ -114,8 +114,6 @@ restore_fpu(struct task_struct *tsk)
* has the property that no matter wether considered as single or as
* double precission represents signaling NANS.
*/
-/* Double presision, NANS as NANS, rounding to nearest, no exceptions */
-#define FPU_DEFAULT 0x00080000
void fpu_init(void)
{
@@ -156,7 +154,7 @@ void fpu_init(void)
"fsts $fpul, $fr15\n\t"
"frchg"
: /* no output */
- : "r" (0), "r" (FPU_DEFAULT));
+ : "r" (0), "r" (FPSCR_INIT));
}
asmlinkage void
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 3f938557a..ae406d22d 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.16 2000/03/02 00:01:15 gniibe Exp $
+/* $Id: head.S,v 1.17 2000/03/06 12:44:24 gniibe Exp $
*
* arch/sh/kernel/head.S
*
@@ -37,8 +37,11 @@ ENTRY(empty_zero_page)
*/
ENTRY(_stext)
! Initialize Status Register
- mov.l 1f, $r0 ! MD=1, RB=0, BL=1
+ mov.l 1f, $r0 ! MD=1, RB=0, BL=0, IMASK=0xF
ldc $r0, $sr
+ ! Initialize global interrupt mask
+ mov #0, $r0
+ ldc $r0, $r5_bank
!
mov.l 2f, $r0
mov $r0, $r15 ! Set initial r15 (stack pointer)
@@ -62,7 +65,7 @@ ENTRY(_stext)
nop
.balign 4
-1: .long 0x50000000 ! MD=1, RB=0, BL=1, FD=0
+1: .long 0x400000F0 ! MD=1, RB=0, BL=0, FD=0, IMASK=0xF
2: .long SYMBOL_NAME(stack)
3: .long SYMBOL_NAME(__bss_start)
4: .long SYMBOL_NAME(_end)
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index a15352389..af03ef46d 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.11 2000/02/29 11:03:40 gniibe Exp $
+/* $Id: irq.c,v 1.12 2000/03/06 14:07:50 gniibe Exp $
*
* linux/arch/sh/kernel/irq.c
*
@@ -238,11 +238,11 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
regs.syscall_nr = -1; /* It's not system call */
/* Get IRQ number */
- asm volatile("stc r2_bank,%0\n\t"
+ asm volatile("stc $r2_bank, %0\n\t"
"shlr2 %0\n\t"
"shlr2 %0\n\t"
"shlr %0\n\t"
- "add #-16,%0\n\t"
+ "add #-16, %0\n\t"
:"=z" (irq));
kstat.irqs[cpu][irq]++;
diff --git a/arch/sh/kernel/irq_imask.c b/arch/sh/kernel/irq_imask.c
index a3cf78b5f..380acf405 100644
--- a/arch/sh/kernel/irq_imask.c
+++ b/arch/sh/kernel/irq_imask.c
@@ -1,8 +1,8 @@
-/* $Id: irq_imask.c,v 1.2 2000/02/11 04:57:40 gniibe Exp $
+/* $Id: irq_imask.c,v 1.6 2000/03/06 14:11:32 gniibe Exp $
*
* linux/arch/sh/kernel/irq_imask.c
*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999, 2000 Niibe Yutaka
*
* Simple interrupt handling using IMASK of SR register.
*
@@ -52,35 +52,40 @@ static struct hw_interrupt_type imask_irq_type = {
end_imask_irq
};
-void disable_imask_irq(unsigned int irq)
+void static inline set_interrupt_registers(int ip)
{
unsigned long __dummy;
+ asm volatile("ldc %2, $r5_bank\n\t"
+ "stc $sr, %0\n\t"
+ "and #0xf0, %0\n\t"
+ "shlr8 %0\n\t"
+ "cmp/eq #0x0f, %0\n\t"
+ "bt 1f ! CLI-ed\n\t"
+ "stc $sr, %0\n\t"
+ "and %1, %0\n\t"
+ "or %2, %0\n\t"
+ "ldc %0, $sr\n"
+ "1:"
+ : "=&z" (__dummy)
+ : "r" (~0xf0), "r" (ip << 4));
+}
+
+void disable_imask_irq(unsigned int irq)
+{
clear_bit(irq, &imask_mask);
if (interrupt_priority < IMASK_PRIORITY - irq)
interrupt_priority = IMASK_PRIORITY - irq;
- asm volatile("stc sr,%0\n\t"
- "and %1,%0\n\t"
- "or %2,%0\n\t"
- "ldc %0,sr"
- : "=&r" (__dummy)
- : "r" (0xffffff0f), "r" (interrupt_priority << 4));
+ set_interrupt_registers(interrupt_priority);
}
static void enable_imask_irq(unsigned int irq)
{
- unsigned long __dummy;
-
set_bit(irq, &imask_mask);
interrupt_priority = IMASK_PRIORITY - ffz(imask_mask);
- asm volatile("stc sr,%0\n\t"
- "and %1,%0\n\t"
- "or %2,%0\n\t"
- "ldc %0,sr"
- : "=&r" (__dummy)
- : "r" (0xffffff0f), "r" (interrupt_priority << 4));
+ set_interrupt_registers(interrupt_priority);
}
static void mask_and_ack_imask(unsigned int irq)
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 2ca91cb40..97cd1fe0c 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.28 2000/03/05 02:16:15 gniibe Exp $
+/* $Id: process.c,v 1.33 2000/03/25 00:06:15 gniibe Exp $
*
* linux/arch/sh/kernel/process.c
*
@@ -94,7 +94,7 @@ void show_regs(struct pt_regs * regs)
{
printk("\n");
printk("PC : %08lx SP : %08lx SR : %08lx TEA : %08lx\n",
- regs->pc, regs->sp, regs->sr, ctrl_inl(MMU_TEA));
+ regs->pc, regs->regs[15], regs->sr, ctrl_inl(MMU_TEA));
printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
regs->regs[0],regs->regs[1],
regs->regs[2],regs->regs[3]);
@@ -210,22 +210,22 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct *p, struct pt_regs *regs)
{
struct pt_regs *childregs;
+#if defined(__SH4__)
struct task_struct *tsk = current;
- childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1;
- struct_cpy(childregs, regs);
-
-#if defined(__SH4__)
if (tsk != &init_task) {
unlazy_fpu(tsk);
- struct_cpy(&p->thread.fpu, &current->thread.fpu);
+ p->thread.fpu = current->thread.fpu;
p->used_math = tsk->used_math;
}
#endif
+ childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1;
+ *childregs = *regs;
+
if (user_mode(regs)) {
- childregs->sp = usp;
+ childregs->regs[15] = usp;
} else {
- childregs->sp = (unsigned long)p+2*PAGE_SIZE;
+ childregs->regs[15] = (unsigned long)p+2*PAGE_SIZE;
}
childregs->regs[0] = 0; /* Set return value for child */
childregs->sr |= SR_FD; /* Invalidate FPU flag */
@@ -244,7 +244,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->magic = CMAGIC;
dump->start_code = current->mm->start_code;
dump->start_data = current->mm->start_data;
- dump->start_stack = regs->sp & ~(PAGE_SIZE - 1);
+ dump->start_stack = regs->regs[15] & ~(PAGE_SIZE - 1);
dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT;
dump->u_ssize = (current->mm->start_stack - dump->start_stack +
@@ -279,7 +279,7 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- return do_fork(SIGCHLD, regs.sp, &regs);
+ return do_fork(SIGCHLD, regs.regs[15], &regs);
}
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
@@ -287,7 +287,7 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
struct pt_regs regs)
{
if (!newsp)
- newsp = regs.sp;
+ newsp = regs.regs[15];
return do_fork(clone_flags, newsp, &regs);
}
@@ -305,7 +305,7 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, &regs);
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], &regs);
}
/*
@@ -370,3 +370,12 @@ asmlinkage void print_syscall(int x)
(init_task.flags&PF_USEDFPU)?'K':' ', (sr&SR_FD)?' ':'F');
restore_flags(flags);
}
+
+asmlinkage void break_point_trap(void)
+{
+ /* Clear traicng. */
+ ctrl_outw(0, UBC_BBRA);
+ ctrl_outw(0, UBC_BBRB);
+
+ force_sig(SIGTRAP, current);
+}
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
index 2d69b5b7c..d4a1556b9 100644
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace.c
@@ -1,6 +1,13 @@
-/*
- * Surely this doesn't work... (we need to design ptrace for SupreH)
+/* $Id: ptrace.c,v 1.4 2000/03/22 13:59:01 gniibe Exp $
+ *
* linux/arch/sh/kernel/ptrace.c
+ *
+ * Original x86 implementation:
+ * By Ross Biro 1/23/92
+ * edited by Linus Torvalds
+ *
+ * SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
+ *
*/
#include <linux/kernel.h>
@@ -12,135 +19,126 @@
#include <linux/ptrace.h>
#include <linux/user.h>
+#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/processor.h>
+#include <asm/mmu_context.h>
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
-/* determines which flags the user has access to. */
-/* 1 = access 0 = no access */
-#define FLAG_MASK 0x00044dd5
-
-/* set's the trap flag. */
-#define TRAP_FLAG 0x100
-
/*
- * Offset of eflags on child stack..
+ * This routine will get a word off of the process kernel stack.
*/
-#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
-
-/*
- * this routine will get a word off of the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
- * data space.
- */
static inline int get_stack_long(struct task_struct *task, int offset)
{
unsigned char *stack;
- stack = (unsigned char *)task->thread.sp;
+ stack = (unsigned char *)task + THREAD_SIZE - sizeof(struct pt_regs);
stack += offset;
return (*((int *)stack));
}
/*
- * this routine will put a word on the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
- * data space.
+ * This routine will put a word on the process kernel stack.
*/
static inline int put_stack_long(struct task_struct *task, int offset,
- unsigned long data)
+ unsigned long data)
{
- unsigned char * stack;
+ unsigned char *stack;
- stack = (unsigned char *) task->thread.sp;
+ stack = (unsigned char *)task + THREAD_SIZE - sizeof(struct pt_regs);
stack += offset;
*(unsigned long *) stack = data;
return 0;
}
-static int putreg(struct task_struct *child,
- unsigned long regno, unsigned long value)
+static void
+compute_next_pc(struct pt_regs *regs, unsigned short inst,
+ unsigned long *pc1, unsigned long *pc2)
{
-#if 0
- switch (regno >> 2) {
- case ORIG_EAX:
- return -EIO;
- case FS:
- if (value && (value & 3) != 3)
- return -EIO;
- child->thread.fs = value;
- return 0;
- case GS:
- if (value && (value & 3) != 3)
- return -EIO;
- child->thread.gs = value;
- return 0;
- case DS:
- case ES:
- if (value && (value & 3) != 3)
- return -EIO;
- value &= 0xffff;
- break;
- case SS:
- case CS:
- if ((value & 3) != 3)
- return -EIO;
- value &= 0xffff;
- break;
- case EFL:
- value &= FLAG_MASK;
- value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
+ int nib[4]
+ = { (inst >> 12) & 0xf,
+ (inst >> 8) & 0xf,
+ (inst >> 4) & 0xf,
+ inst & 0xf};
+
+ /* bra & bsr */
+ if (nib[0] == 0xa || nib[0] == 0xb) {
+ *pc1 = regs->pc + 4 + ((short) ((inst & 0xfff) << 4) >> 3);
+ *pc2 = (unsigned long) -1;
+ return;
}
- if (regno > GS*4)
- regno -= 2*4;
- put_stack_long(child, regno - sizeof(struct pt_regs), value);
-#endif
- return 0;
+
+ /* bt & bf */
+ if (nib[0] == 0x8 && (nib[1] == 0x9 || nib[1] == 0xb)) {
+ *pc1 = regs->pc + 4 + ((char) (inst & 0xff) << 1);
+ *pc2 = regs->pc + 2;
+ return;
+ }
+
+ /* bt/s & bf/s */
+ if (nib[0] == 0x8 && (nib[1] == 0xd || nib[1] == 0xf)) {
+ *pc1 = regs->pc + 4 + ((char) (inst & 0xff) << 1);
+ *pc2 = regs->pc + 4;
+ return;
+ }
+
+ /* jmp & jsr */
+ if (nib[0] == 0x4 && nib[3] == 0xb
+ && (nib[2] == 0x0 || nib[2] == 0x2)) {
+ *pc1 = regs->regs[nib[1]];
+ *pc2 = (unsigned long) -1;
+ return;
+ }
+
+ /* braf & bsrf */
+ if (nib[0] == 0x0 && nib[3] == 0x3
+ && (nib[2] == 0x0 || nib[2] == 0x2)) {
+ *pc1 = regs->pc + 4 + regs->regs[nib[1]];
+ *pc2 = (unsigned long) -1;
+ return;
+ }
+
+ if (inst == 0x000b) {
+ *pc1 = regs->pr;
+ *pc2 = (unsigned long) -1;
+ return;
+ }
+
+ *pc1 = regs->pc + 2;
+ *pc2 = (unsigned long) -1;
+ return;
}
-static unsigned long getreg(struct task_struct *child,
- unsigned long regno)
+/* Tracing by user break controller. */
+static void
+ubc_set_tracing(int asid, unsigned long nextpc1, unsigned nextpc2)
{
- unsigned long retval = ~0UL;
-
-#if 0
- switch (regno >> 2) {
- case FS:
- retval = child->thread.fs;
- break;
- case GS:
- retval = child->thread.gs;
- break;
- case DS:
- case ES:
- case SS:
- case CS:
- retval = 0xffff;
- /* fall through */
- default:
- if (regno > GS*4)
- regno -= 2*4;
- regno = regno - sizeof(struct pt_regs);
- retval &= get_stack_long(child, regno);
+ ctrl_outl(nextpc1, UBC_BARA);
+ ctrl_outb(asid, UBC_BASRA);
+ ctrl_outb(BAMR_12, UBC_BAMRA);
+ ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
+
+ if (nextpc2 != (unsigned long) -1) {
+ ctrl_outl(nextpc2, UBC_BARB);
+ ctrl_outb(asid, UBC_BASRB);
+ ctrl_outb(BAMR_12, UBC_BAMRB);
+ ctrl_outw(BBR_INST | BBR_READ, UBC_BBRB);
}
-#endif
- return retval;
+ ctrl_outw(BRCR_PCBA | BRCR_PCBB, UBC_BRCR);
}
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
- struct task_struct *child;
+ struct task_struct *child, *tsk = current;
struct user * dummy = NULL;
unsigned long flags;
- int i, ret;
+ int ret;
lock_kernel();
ret = -EPERM;
@@ -163,16 +161,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
if (request == PTRACE_ATTACH) {
- if (child == current)
+ if (child == tsk)
goto out;
if ((!child->dumpable ||
- (current->uid != child->euid) ||
- (current->uid != child->suid) ||
- (current->uid != child->uid) ||
- (current->gid != child->egid) ||
- (current->gid != child->sgid) ||
- (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
- (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+ (tsk->uid != child->euid) ||
+ (tsk->uid != child->suid) ||
+ (tsk->uid != child->uid) ||
+ (tsk->gid != child->egid) ||
+ (tsk->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, tsk->cap_permitted)) ||
+ (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
goto out;
/* the same process cannot be attached many times */
if (child->flags & PF_PTRACED)
@@ -180,9 +178,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
child->flags |= PF_PTRACED;
write_lock_irqsave(&tasklist_lock, flags);
- if (child->p_pptr != current) {
+ if (child->p_pptr != tsk) {
REMOVE_LINKS(child);
- child->p_pptr = current;
+ child->p_pptr = tsk;
SET_LINKS(child);
}
write_unlock_irqrestore(&tasklist_lock, flags);
@@ -198,257 +196,180 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (request != PTRACE_KILL)
goto out;
}
- if (child->p_pptr != current)
+ if (child->p_pptr != tsk)
goto out;
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- goto out;
- ret = put_user(tmp,(unsigned long *) data);
- goto out;
- }
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
+ unsigned long tmp;
+ int copied;
+
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
+ break;
+ ret = put_user(tmp,(unsigned long *) data);
+ break;
+ }
/* read the word at location addr in the USER area. */
- case PTRACE_PEEKUSR: {
- unsigned long tmp;
-
- ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
- goto out;
-
- tmp = 0; /* Default return condition */
- if(addr < 17*sizeof(long))
- tmp = getreg(child, addr);
-#if 0
- if(addr >= (long) &dummy->u_debugreg[0] &&
- addr <= (long) &dummy->u_debugreg[7]){
- addr -= (long) &dummy->u_debugreg[0];
- addr = addr >> 2;
- tmp = child->thread.debugreg[addr];
- };
-#endif
- ret = put_user(tmp,(unsigned long *) data);
- goto out;
- }
+ case PTRACE_PEEKUSR: {
+ unsigned long tmp;
- /* when I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- goto out;
- ret = -EIO;
- goto out;
+ ret = -EIO;
+ if ((addr & 3) || addr < 0 ||
+ addr > sizeof(struct user) - 3)
+ break;
- case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
- ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
- goto out;
-
- if (addr < 17*sizeof(long)) {
- ret = putreg(child, addr, data);
- goto out;
- }
-
- /* We need to be very careful here. We implicitly
- want to modify a portion of the task_struct, and we
- have to be selective about what portions we allow someone
- to modify. */
-#if 0
- if(addr >= (long) &dummy->u_debugreg[0] &&
- addr <= (long) &dummy->u_debugreg[7]){
-
- if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
- if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
- if(addr < (long) &dummy->u_debugreg[4] &&
- ((unsigned long) data) >= TASK_SIZE-3) return -EIO;
-
- ret = -EIO;
- if(addr == (long) &dummy->u_debugreg[7]) {
- data &= ~DR_CONTROL_RESERVED;
- for(i=0; i<4; i++)
- if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
- goto out;
- };
-
- addr -= (long) &dummy->u_debugreg;
- addr = addr >> 2;
- child->thread.debugreg[addr] = data;
- ret = 0;
- goto out;
- };
-#endif
- ret = -EIO;
- goto out;
-
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- long tmp;
-
- ret = -EIO;
- if ((unsigned long) data > _NSIG)
- goto out;
- if (request == PTRACE_SYSCALL)
- child->flags |= PF_TRACESYS;
- else
- child->flags &= ~PF_TRACESYS;
- child->exit_code = data;
- /* make sure the single step bit is not set. */
-#if 0
- tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
- put_stack_long(child, EFL_OFFSET,tmp);
-#endif
- wake_up_process(child);
+ if (addr < sizeof(struct pt_regs))
+ tmp = get_stack_long(child, addr);
+ else if (addr >= (long) &dummy->fpu &&
+ addr < (long) &dummy->u_fpvalid) {
+ if (!child->used_math) {
+ if (addr == (long)&dummy->fpu.fpscr)
+ tmp = FPSCR_INIT;
+ else
+ tmp = 0;
+ } else
+ tmp = ((long *)&child->thread.fpu)
+ [(addr - (long)&dummy->fpu) >> 2];
+ } else if (addr == (long) &dummy->u_fpvalid)
+ tmp = child->used_math;
+ else
+ tmp = 0;
+ ret = put_user(tmp, (unsigned long *)data);
+ break;
+ }
+
+ /* when I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ ret = 0;
+ if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+ break;
+ ret = -EIO;
+ break;
+
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ ret = -EIO;
+ if ((addr & 3) || addr < 0 ||
+ addr > sizeof(struct user) - 3)
+ break;
+
+ if (addr < sizeof(struct pt_regs))
+ ret = put_stack_long(child, addr, data);
+ else if (addr >= (long) &dummy->fpu &&
+ addr < (long) &dummy->u_fpvalid) {
+ child->used_math = 1;
+ ((long *)&child->thread.fpu)
+ [(addr - (long)&dummy->fpu) >> 2] = data;
+ ret = 0;
+ } else if (addr == (long) &dummy->u_fpvalid) {
+ child->used_math = data?1:0;
ret = 0;
- goto out;
}
+ break;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ if (request == PTRACE_SYSCALL)
+ child->flags |= PF_TRACESYS;
+ else
+ child->flags &= ~PF_TRACESYS;
+ child->exit_code = data;
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
- case PTRACE_KILL: {
- long tmp;
+ case PTRACE_KILL: {
+ ret = 0;
+ if (child->state == TASK_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ wake_up_process(child);
+ break;
+ }
- ret = 0;
- if (child->state == TASK_ZOMBIE) /* already dead */
- goto out;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
-#if 0
- tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
- put_stack_long(child, EFL_OFFSET, tmp);
-#endif
- wake_up_process(child);
- goto out;
- }
+ case PTRACE_SINGLESTEP: { /* set the trap flag. */
+ long tmp, pc;
+ struct pt_regs *dummy = NULL;
+ struct pt_regs *regs;
+ unsigned long nextpc1, nextpc2;
+ unsigned short insn;
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
- long tmp;
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ child->flags &= ~PF_TRACESYS;
+ if ((child->flags & PF_DTRACE) == 0) {
+ /* Spurious delayed TF traps may occur */
+ child->flags |= PF_DTRACE;
+ }
- ret = -EIO;
- if ((unsigned long) data > _NSIG)
- goto out;
- child->flags &= ~PF_TRACESYS;
- if ((child->flags & PF_DTRACE) == 0) {
- /* Spurious delayed TF traps may occur */
- child->flags |= PF_DTRACE;
- }
-#if 0
- tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
- put_stack_long(child, EFL_OFFSET, tmp);
+ /* Compute next pc. */
+ pc = get_stack_long(child, (long)&dummy->pc);
+ regs = (struct pt_regs *)((unsigned long)child + THREAD_SIZE - sizeof(struct pt_regs));
+ if (access_process_vm(child, pc&~3, &tmp, sizeof(tmp), 1) != sizeof(data))
+ break;
+
+#ifdef __LITTLE_ENDIAN__
+ if (pc & 3)
+ insn = tmp >> 16;
+ else
+ insn = tmp & 0xffff;
+#else
+ if (pc & 3)
+ insn = tmp & 0xffff;
+ else
+ insn = tmp >> 16;
#endif
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
- goto out;
- }
+ compute_next_pc (regs, insn, &nextpc1, &nextpc2);
- case PTRACE_DETACH: { /* detach a process that was attached. */
- long tmp;
+ if (nextpc1 & 0x80000000)
+ break;
+ if (nextpc2 != (unsigned long) -1 && (nextpc2 & 0x80000000))
+ break;
- ret = -EIO;
- if ((unsigned long) data > _NSIG)
- goto out;
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
- child->exit_code = data;
- write_lock_irqsave(&tasklist_lock, flags);
- REMOVE_LINKS(child);
- child->p_pptr = child->p_opptr;
- SET_LINKS(child);
- write_unlock_irqrestore(&tasklist_lock, flags);
- /* make sure the single step bit is not set. */
-#if 0
- tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
- put_stack_long(child, EFL_OFFSET, tmp);
-#endif
- wake_up_process(child);
- ret = 0;
- goto out;
- }
-#if 0
- case PTRACE_GETREGS: { /* Get all gp regs from the child. */
- if (!access_ok(VERIFY_WRITE, (unsigned *)data,
- 17*sizeof(long)))
- {
- ret = -EIO;
- goto out;
- }
- for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
- {
- __put_user(getreg(child, i),(unsigned long *) data);
- data += sizeof(long);
- }
- ret = 0;
- goto out;
- };
-
- case PTRACE_SETREGS: { /* Set all gp regs in the child. */
- unsigned long tmp;
- if (!access_ok(VERIFY_READ, (unsigned *)data,
- 17*sizeof(long)))
- {
- ret = -EIO;
- goto out;
- }
- for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
- {
- __get_user(tmp, (unsigned long *) data);
- putreg(child, i, tmp);
- data += sizeof(long);
- }
- ret = 0;
- goto out;
- };
-
- case PTRACE_GETFPREGS: { /* Get the child FPU state. */
- if (!access_ok(VERIFY_WRITE, (unsigned *)data,
- sizeof(struct user_i387_struct)))
- {
- ret = -EIO;
- goto out;
- }
- ret = 0;
- if ( !child->used_math ) {
- /* Simulate an empty FPU. */
- child->thread.i387.hard.cwd = 0xffff037f;
- child->thread.i387.hard.swd = 0xffff0000;
- child->thread.i387.hard.twd = 0xffffffff;
- }
- __copy_to_user((void *)data, &child->thread.i387.hard,
- sizeof(struct user_i387_struct));
- goto out;
- };
-
- case PTRACE_SETFPREGS: { /* Set the child FPU state. */
- if (!access_ok(VERIFY_READ, (unsigned *)data,
- sizeof(struct user_i387_struct)))
- {
- ret = -EIO;
- goto out;
- }
- child->used_math = 1;
- __copy_from_user(&child->thread.i387.hard, (void *)data,
- sizeof(struct user_i387_struct));
- ret = 0;
- goto out;
- };
-#endif
- default:
- ret = -EIO;
- goto out;
+ ubc_set_tracing(child->mm->context & MMU_CONTEXT_ASID_MASK,
+ nextpc1, nextpc2);
+
+ child->exit_code = data;
+ /* give it a chance to run. */
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+ case PTRACE_DETACH: { /* detach a process that was attached. */
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ child->exit_code = data;
+ write_lock_irqsave(&tasklist_lock, flags);
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+ default:
+ ret = -EIO;
+ break;
}
out:
unlock_kernel();
@@ -457,20 +378,22 @@ out:
asmlinkage void syscall_trace(void)
{
- if ((current->flags & (PF_PTRACED|PF_TRACESYS))
- != (PF_PTRACED|PF_TRACESYS))
+ struct task_struct *tsk = current;
+
+ if ((tsk->flags & (PF_PTRACED|PF_TRACESYS))
+ != (PF_PTRACED|PF_TRACESYS))
return;
- current->exit_code = SIGTRAP;
- current->state = TASK_STOPPED;
- notify_parent(current, SIGCHLD);
+ tsk->exit_code = SIGTRAP;
+ tsk->state = TASK_STOPPED;
+ notify_parent(tsk, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
* for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl
*/
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
+ if (tsk->exit_code) {
+ send_sig(tsk->exit_code, tsk, 1);
+ tsk->exit_code = 0;
}
}
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index 0c24acf73..4b11100ae 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.16 2000/01/29 11:31:31 gniibe Exp gniibe $
+/* $Id: signal.c,v 1.21 2000/03/11 14:06:21 gniibe Exp $
*
* linux/arch/sh/kernel/signal.c
*
@@ -6,7 +6,7 @@
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
*
- * SuperH version: Copyright (C) 1999 Niibe Yutaka
+ * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
*
*/
@@ -125,7 +125,7 @@ sys_sigaltstack(const stack_t *uss, stack_t *uoss,
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- return do_sigaltstack(uss, uoss, regs.sp);
+ return do_sigaltstack(uss, uoss, regs.regs[15]);
}
@@ -136,7 +136,6 @@ sys_sigaltstack(const stack_t *uss, stack_t *uoss,
struct sigframe
{
struct sigcontext sc;
- /* FPU data should come here: SH-3 has no FPU */
unsigned long extramask[_NSIG_WORDS-1];
char retcode[4];
};
@@ -147,10 +146,38 @@ struct rt_sigframe
void *puc;
struct siginfo info;
struct ucontext uc;
- /* FPU should come here: SH-3 has no FPU */
char retcode[4];
};
+#if defined(__SH4__)
+static inline int restore_sigcontext_fpu(struct sigcontext *sc)
+{
+ current->used_math = 1;
+ return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
+ sizeof(long)*(NUM_FPU_REGS*2+2));
+}
+
+static inline int save_sigcontext_fpu(struct sigcontext *sc)
+{
+ struct task_struct *tsk = current;
+
+ if (!tsk->used_math) {
+ sc->owend_fp = 0;
+ return 0;
+ }
+
+ sc->owend_fp = 1;
+
+ /* This will cause a "finit" to be triggered by the next
+ attempted FPU operation by the 'current' process.
+ */
+ tsk->used_math = 0;
+
+ unlazy_fpu(tsk);
+ return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
+ sizeof(long)*(NUM_FPU_REGS*2+2));
+}
+#endif
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *r0_p)
@@ -165,15 +192,28 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *r0_p)
COPY(regs[8]); COPY(regs[9]);
COPY(regs[10]); COPY(regs[11]);
COPY(regs[12]); COPY(regs[13]);
- COPY(regs[14]); COPY(sp);
+ COPY(regs[14]); COPY(regs[15]);
COPY(gbr); COPY(mach);
COPY(macl); COPY(pr);
COPY(sr); COPY(pc);
#undef COPY
+#if defined(__SH4__)
+ {
+ int owned_fp;
+ struct task_struct *tsk = current;
+
+ regs->sr |= SR_FD; /* Release FPU */
+ clear_fpu(tsk);
+ current->used_math = 0;
+ __get_user (owned_fp, &context->sc_ownedfp);
+ if (owned_fp)
+ err |= restore_sigcontext_fpu(sc);
+ }
+#endif
+
regs->syscall_nr = -1; /* disable syscall checks */
err |= __get_user(*r0_p, &sc->sc_regs[0]);
-
return err;
}
@@ -181,7 +221,7 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- struct sigframe *frame = (struct sigframe *)regs.sp;
+ struct sigframe *frame = (struct sigframe *)regs.regs[15];
sigset_t set;
int r0;
@@ -214,7 +254,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- struct rt_sigframe *frame = (struct rt_sigframe *)regs.sp;
+ struct rt_sigframe *frame = (struct rt_sigframe *)regs.regs[15];
sigset_t set;
stack_t st;
int r0;
@@ -238,7 +278,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs.sp);
+ do_sigaltstack(&st, NULL, regs.regs[15]);
return r0;
@@ -265,12 +305,16 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
COPY(regs[8]); COPY(regs[9]);
COPY(regs[10]); COPY(regs[11]);
COPY(regs[12]); COPY(regs[13]);
- COPY(regs[14]); COPY(sp);
+ COPY(regs[14]); COPY(regs[15]);
COPY(gbr); COPY(mach);
COPY(macl); COPY(pr);
COPY(sr); COPY(pc);
#undef COPY
+#if defined(__SH4__)
+ err |= save_sigcontext_fpu(sc);
+#endif
+
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
@@ -296,7 +340,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
int err = 0;
int signal;
- frame = get_sigframe(ka, regs->sp, sizeof(*frame));
+ frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
@@ -334,7 +378,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
goto give_sigsegv;
/* Set up registers for signal handler */
- regs->sp = (unsigned long) frame;
+ regs->regs[15] = (unsigned long) frame;
regs->regs[4] = signal; /* Arg for signal handler */
regs->pc = (unsigned long) ka->sa.sa_handler;
@@ -361,7 +405,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
int err = 0;
int signal;
- frame = get_sigframe(ka, regs->sp, sizeof(*frame));
+ frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
@@ -381,7 +425,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user((void *)current->sas_ss_sp,
&frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(sas_ss_flags(regs->regs[15]),
+ &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
@@ -407,7 +452,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv;
/* Set up registers for signal handler */
- regs->sp = (unsigned long) frame;
+ regs->regs[15] = (unsigned long) frame;
regs->regs[4] = signal; /* Arg for signal handler */
regs->pc = (unsigned long) ka->sa.sa_handler;
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index 5f7d68755..7af24f1c3 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -3,7 +3,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
L_TARGET = lib.a
L_OBJS = delay.o memcpy.o memset.o memmove.o memchr.o old-checksum.o \
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index f5c5200be..33bdf2114 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -1,4 +1,4 @@
-/* $Id: cache.c,v 1.9 2000/02/14 12:45:26 gniibe Exp $
+/* $Id: cache.c,v 1.10 2000/03/07 11:58:34 gniibe Exp $
*
* linux/arch/sh/mm/cache.c
*
@@ -67,36 +67,15 @@ static struct _cache_system_info cache_system_info;
#define CACHE_IC_NUM_WAYS 1
#endif
-#define jump_to_p2(__dummy) \
- asm volatile("mova 1f,%0\n\t" \
- "add %1,%0\n\t" \
- "jmp @r0 ! Jump to P2 area\n\t" \
- " nop\n\t" \
- ".balign 4\n" \
- "1:" \
- : "=&z" (__dummy) \
- : "r" (0x20000000))
-
-#define back_to_p1(__dummy) \
- asm volatile("nop;nop;nop;nop;nop;nop\n\t" \
- "mova 9f,%0\n\t" \
- "sub %1,%0\n\t" \
- "jmp @r0 ! Back to P1 area\n\t" \
- " nop\n\t" \
- ".balign 4\n" \
- "9:" \
- : "=&z" (__dummy) \
- : "r" (0x20000000), "0" (__dummy))
-
/* Write back caches to memory (if needed) and invalidates the caches */
void cache_flush_area(unsigned long start, unsigned long end)
{
- unsigned long flags, __dummy;
+ unsigned long flags;
unsigned long addr, data, v, p;
start &= ~(L1_CACHE_BYTES-1);
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
for (v = start; v < end; v+=L1_CACHE_BYTES) {
p = __pa(v);
@@ -110,7 +89,7 @@ void cache_flush_area(unsigned long start, unsigned long end)
: "m" (__m(v)));
#endif
}
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
@@ -124,12 +103,12 @@ void cache_flush_area(unsigned long start, unsigned long end)
the cache line. */
void cache_purge_area(unsigned long start, unsigned long end)
{
- unsigned long flags, __dummy;
+ unsigned long flags;
unsigned long addr, data, v, p, j;
start &= ~(L1_CACHE_BYTES-1);
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
for (v = start; v < end; v+=L1_CACHE_BYTES) {
p = __pa(v);
@@ -150,19 +129,19 @@ void cache_purge_area(unsigned long start, unsigned long end)
: "m" (__m(v)));
#endif
}
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
/* write back the dirty cache, but not invalidate the cache */
void cache_wback_area(unsigned long start, unsigned long end)
{
- unsigned long flags, __dummy;
+ unsigned long flags;
unsigned long v;
start &= ~(L1_CACHE_BYTES-1);
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
for (v = start; v < end; v+=L1_CACHE_BYTES) {
#if CACHE_IC_ADDRESS_ARRAY == CACHE_OC_ADDRESS_ARRAY
@@ -187,7 +166,7 @@ void cache_wback_area(unsigned long start, unsigned long end)
: "m" (__m(v)));
#endif
}
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
@@ -199,11 +178,11 @@ void cache_wback_area(unsigned long start, unsigned long end)
*/
static void cache_wback_all(void)
{
- unsigned long flags, __dummy;
+ unsigned long flags;
unsigned long addr, data, i, j;
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
@@ -217,7 +196,7 @@ static void cache_wback_all(void)
}
}
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
@@ -225,9 +204,9 @@ static void
detect_cpu_and_cache_system(void)
{
#if defined(__sh3__)
- unsigned long __dummy, addr0, addr1, data0, data1, data2, data3;
+ unsigned long addr0, addr1, data0, data1, data2, data3;
- jump_to_p2(__dummy);
+ jump_to_P2();
/* Check if the entry shadows or not.
* When shadowed, it's 128-entry system.
* Otherwise, it's 256-entry system.
@@ -245,7 +224,7 @@ detect_cpu_and_cache_system(void)
/* Invaliate them, in case the cache has been enabled already. */
ctrl_outl(data0&~0x00000001,addr0);
ctrl_outl(data2&~0x00000001,addr1);
- back_to_p1(__dummy);
+ back_to_P1();
if (data0 == data1 && data2 == data3) { /* Shadow */
cache_system_info.way_shift = 11;
@@ -265,7 +244,7 @@ detect_cpu_and_cache_system(void)
void __init cache_init(void)
{
- unsigned long __dummy, ccr;
+ unsigned long ccr;
detect_cpu_and_cache_system();
@@ -277,19 +256,19 @@ void __init cache_init(void)
we only need to flush the half of the caches. */
cache_wback_all();
- jump_to_p2(__dummy);
+ jump_to_P2();
ctrl_outl(CCR_CACHE_INIT, CCR);
- back_to_p1(__dummy);
+ back_to_P1();
}
#if defined(__SH4__)
void flush_icache_page(struct vm_area_struct *vma, struct page *pg)
{
- unsigned long flags, __dummy;
+ unsigned long flags;
unsigned long addr, data, v;
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
v = page_address(pg);
@@ -303,18 +282,18 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *pg)
data = (v&0xfffffc00); /* Valid=0 */
ctrl_outl(data,addr);
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
void flush_icache_range(unsigned long start, unsigned long end)
{
- unsigned long flags, __dummy;
+ unsigned long flags;
unsigned long addr, data, v;
start &= ~(L1_CACHE_BYTES-1);
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
for (v = start; v < end; v+=L1_CACHE_BYTES) {
/* Write back O Cache */
@@ -327,22 +306,22 @@ void flush_icache_range(unsigned long start, unsigned long end)
data = (v&0xfffffc00); /* Valid=0 */
ctrl_outl(data,addr);
}
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
void flush_cache_all(void)
{
- unsigned long flags,__dummy;
+ unsigned long flags;
/* Write back Operand Cache */
cache_wback_all ();
/* Then, invalidate Instruction Cache and Operand Cache */
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
ctrl_outl(CCR_CACHE_INIT, CCR);
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
@@ -356,12 +335,12 @@ void flush_cache_mm(struct mm_struct *mm)
void flush_cache_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- unsigned long flags, __dummy;
+ unsigned long flags;
unsigned long addr, data, v;
start &= ~(L1_CACHE_BYTES-1);
save_and_cli(flags);
- jump_to_p2(__dummy);
+ jump_to_P2();
for (v = start; v < end; v+=L1_CACHE_BYTES) {
addr = CACHE_IC_ADDRESS_ARRAY |
@@ -372,7 +351,7 @@ void flush_cache_range(struct mm_struct *mm, unsigned long start,
(v&CACHE_OC_ENTRY_MASK) | 0x8 /* A-bit */;
ctrl_outl(data,addr);
}
- back_to_p1(__dummy);
+ back_to_P1();
restore_flags(flags);
}
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index 3b8e86e36..bf448bf8b 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.12 2000/03/01 11:15:27 gniibe Exp $
+/* $Id: fault.c,v 1.13 2000/03/07 12:05:24 gniibe Exp $
*
* linux/arch/sh/mm/fault.c
* Copyright (C) 1999 Niibe Yutaka
@@ -283,9 +283,6 @@ static void __flush_tlb_page(struct mm_struct *mm, unsigned long page)
{
unsigned long addr, data, asid;
unsigned long saved_asid = MMU_NO_ASID;
-#if defined(__SH4__)
- int i;
-#endif
if (mm->context == NO_CONTEXT)
return;
@@ -305,20 +302,26 @@ static void __flush_tlb_page(struct mm_struct *mm, unsigned long page)
data = (page & 0xfffe0000) | asid; /* VALID bit is off */
ctrl_outl(data, addr);
#elif defined(__SH4__)
+ jump_to_P2();
addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
data = page | asid; /* VALID bit is off */
ctrl_outl(data, addr);
-
- for (i=0; i<4; i++) {
- addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8);
- data = ctrl_inl(addr);
- data &= ~0x300;
- if (data == (page | asid)) {
- ctrl_outl(data, addr);
- break;
+#if 0 /* Not need when using ASSOC. ??? */
+ {
+ int i;
+ for (i=0; i<4; i++) {
+ addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8);
+ data = ctrl_inl(addr);
+ data &= ~0x300;
+ if (data == (page | asid)) {
+ ctrl_outl(data, addr);
+ break;
+ }
}
}
#endif
+ back_to_P1();
+#endif
if (saved_asid != MMU_NO_ASID)
set_asid(saved_asid);
}
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 776389cac..931564cac 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -224,7 +224,7 @@ void __init paging_init(void)
zones_size[ZONE_DMA] = max_dma - start_pfn;
zones_size[ZONE_NORMAL] = low - max_dma;
}
- free_area_init_node(0, 0, zones_size, __MEMORY_START);
+ free_area_init_node(0, 0, zones_size, __MEMORY_START, 0);
}
}
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index e77e72a76..279afb38f 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.90 2000/03/17 05:18:02 anton Exp $
+# $Id: config.in,v 1.92 2000/03/29 11:56:48 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -20,6 +20,8 @@ define_bool CONFIG_VT_CONSOLE y
bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP
# Global things across all Sun machines.
+define_bool CONFIG_ISA n
+define_bool CONFIG_PCMCIA n
define_bool CONFIG_SBUS y
define_bool CONFIG_SBUSCHAR y
define_bool CONFIG_BUSMOUSE y
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index b39da1989..f2059871c 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -14,6 +14,8 @@ CONFIG_EXPERIMENTAL=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_SMP is not set
+# CONFIG_ISA is not set
+# CONFIG_PCMCIA is not set
CONFIG_SBUS=y
CONFIG_SBUSCHAR=y
CONFIG_BUSMOUSE=y
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 0d93f3a2b..bd9181933 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -8,10 +8,10 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+ $(CPP) $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $< -o $*.o
all: kernel.o head.o init_task.o
@@ -47,7 +47,7 @@ O_OBJS += ebus.o
endif
head.o: head.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $*.S -o $*.o
check_asm: dummy
@echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
@@ -62,7 +62,7 @@ check_asm: dummy
@echo "#undef __SMP__" >> tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) $(CPPFLAGS) -E tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef __SMP__" >> check_asm.c
@@ -87,7 +87,7 @@ check_asm: dummy
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#define CONFIG_SMP 1" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) -D__SMP__ tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index b1ed3c2af..20c141a00 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.36 2000/03/16 08:22:53 anton Exp $
+/* $Id: ioport.c,v 1.37 2000/03/28 06:38:19 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -581,6 +581,7 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int dir
{
if (direction == PCI_DMA_NONE)
BUG();
+ /* IIep is write-through, not flushing. */
return virt_to_bus(ptr);
}
@@ -591,11 +592,15 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int dir
* After this call, reads by the cpu to the buffer are guarenteed to see
* whatever the device wrote there.
*/
-void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
+void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size,
+ int direction)
{
if (direction == PCI_DMA_NONE)
BUG();
- /* Nothing to do... */
+ if (direction != PCI_DMA_TODEVICE) {
+ mmu_inval_dma_area((unsigned long)bus_to_virt(ba),
+ (size + PAGE_SIZE-1) & PAGE_MASK);
+ }
}
/* Map a set of buffers described by scatterlist in streaming
@@ -613,13 +618,14 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, i
* Device ownership issues as mentioned above for pci_map_single are
* the same here.
*/
-int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
+int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+ int direction)
{
int n;
if (direction == PCI_DMA_NONE)
BUG();
-
+ /* IIep is write-through, not flushing. */
for (n = 0; n < nents; n++) {
sg->dvma_address = virt_to_bus(sg->address);
sg->dvma_length = sg->length;
@@ -632,15 +638,24 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int dir
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
-void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction)
+void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+ int direction)
{
+ int n;
+
if (direction == PCI_DMA_NONE)
BUG();
- /* Nothing to do... */
+ if (direction != PCI_DMA_TODEVICE) {
+ for (n = 0; n < nents; n++) {
+ mmu_inval_dma_area((unsigned long)sg->address,
+ (sg->length + PAGE_SIZE-1) & PAGE_MASK);
+ sg++;
+ }
+ }
}
/* Make physical memory consistent for a single
- * streaming mode DMA translation after a transfer.
+ * streaming mode DMA translation before or after a transfer.
*
* If you perform a pci_map_single() but wish to interrogate the
* buffer using the cpu, yet do not wish to teardown the PCI dma
@@ -652,8 +667,10 @@ void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int
{
if (direction == PCI_DMA_NONE)
BUG();
- mmu_inval_dma_area((unsigned long)bus_to_virt(ba),
- (size + PAGE_SIZE-1) & PAGE_MASK);
+ if (direction != PCI_DMA_TODEVICE) {
+ mmu_inval_dma_area((unsigned long)bus_to_virt(ba),
+ (size + PAGE_SIZE-1) & PAGE_MASK);
+ }
}
/* Make physical memory consistent for a set of streaming
@@ -664,13 +681,16 @@ void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int
*/
void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
{
+ int n;
+
if (direction == PCI_DMA_NONE)
BUG();
- while (nents) {
- --nents;
- mmu_inval_dma_area((unsigned long)sg->address,
- (sg->dvma_length + PAGE_SIZE-1) & PAGE_MASK);
- sg++;
+ if (direction != PCI_DMA_TODEVICE) {
+ for (n = 0; n < nents; n++) {
+ mmu_inval_dma_area((unsigned long)sg->address,
+ (sg->length + PAGE_SIZE-1) & PAGE_MASK);
+ sg++;
+ }
}
}
#endif CONFIG_PCI
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 5966e04d7..8c70c9f75 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.116 2000/03/15 23:26:22 anton Exp $
+/* $Id: setup.c,v 1.117 2000/03/27 12:14:54 davem Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -45,6 +45,8 @@
#include <asm/hardirq.h>
#include <asm/machines.h>
+#undef PROM_DEBUG_CONSOLE
+
struct screen_info screen_info = {
0, 0, /* orig-x, orig-y */
0, /* unused */
@@ -282,6 +284,7 @@ struct tt_entry *sparc_ttable;
struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
+#ifdef PROM_DEBUG_CONSOLE
static void prom_cons_write(struct console *con, const char *str, unsigned count)
{
while (count--)
@@ -291,6 +294,7 @@ static void prom_cons_write(struct console *con, const char *str, unsigned count
static struct console prom_console = {
"PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
};
+#endif
extern void paging_init(void);
@@ -345,6 +349,9 @@ void __init setup_arch(char **cmdline_p)
printk("UNKNOWN!\n");
break;
};
+#ifdef PROM_DEBUG_CONSOLE
+ register_console(&prom_console);
+#endif
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 98b542402..484ffac82 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1096,7 +1096,9 @@ static inline void read_maps (void)
if (map->vm_file != NULL) {
dev = map->vm_file->f_dentry->d_inode->i_dev;
ino = map->vm_file->f_dentry->d_inode->i_ino;
- line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+ line = d_path(map->vm_file->f_dentry,
+ map->vm_file->f_vfsmnt,
+ buffer, PAGE_SIZE);
}
printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
kdevname(dev), ino);
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 0a8a5827c..36670ab93 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.117 2000/03/15 02:43:32 davem Exp $
+/* $Id: sys_sunos.c,v 1.118 2000/03/26 11:28:56 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -91,7 +91,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
* of /dev/zero, transform it into an anonymous mapping.
* SunOS is so stupid some times... hmph!
*/
- if(file->f_dentry && file->f_dentry->d_inode) {
+ if (file) {
if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
flags |= MAP_ANONYMOUS;
@@ -633,10 +633,9 @@ struct sunos_nfs_mount_args {
};
-extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
extern dev_t get_unnamed_dev(void);
extern void put_unnamed_dev(dev_t);
-extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
+extern asmlinkage long do_sys_mount(char *, char *, char *, int, void *);
extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
extern asmlinkage int sys_socket(int family, int type, int protocol);
extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
@@ -660,8 +659,6 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
file = fget(fd);
if (!file)
goto out;
- if (!file->f_dentry || !(inode = file->f_dentry->d_inode))
- goto out_putf;
socket = &inode->u.socket_i;
local.sin_family = AF_INET;
@@ -702,12 +699,12 @@ static int get_default (int value, int def_value)
return def_value;
}
-asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
+static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
{
int server_fd;
char *the_name;
struct nfs_mount_data linux_nfs_mount;
- struct sunos_nfs_mount_args *sunos_mount = data;
+ struct sunos_nfs_mount_args sunos_mount;
/* Ok, here comes the fun part: Linux's nfs mount needs a
* socket connection to the server, but SunOS mount does not
@@ -715,33 +712,42 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
* address to create a socket and bind it to a reserved
* port on this system
*/
+ if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))
+ return -EFAULT;
+
server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (server_fd < 0)
return -ENXIO;
- if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){
+ if (copy_from_user(&linux_nfs_mount.addr,sunos_mount.addr,
+ sizeof(*sunos_mount.addr)) ||
+ copy_from_user(&linux_nfs_mount.root,sunos_mount.fh,
+ sizeof(*sunos_mount.fh))) {
+ sys_close (server_fd);
+ return -EFAULT;
+ }
+
+ if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){
sys_close (server_fd);
return -ENXIO;
}
/* Now, bind it to a locally reserved port */
linux_nfs_mount.version = NFS_MOUNT_VERSION;
- linux_nfs_mount.flags = sunos_mount->flags;
- linux_nfs_mount.addr = *sunos_mount->addr;
- linux_nfs_mount.root = *sunos_mount->fh;
+ linux_nfs_mount.flags = sunos_mount.flags;
linux_nfs_mount.fd = server_fd;
- linux_nfs_mount.rsize = get_default (sunos_mount->rsize, 8192);
- linux_nfs_mount.wsize = get_default (sunos_mount->wsize, 8192);
- linux_nfs_mount.timeo = get_default (sunos_mount->timeo, 10);
- linux_nfs_mount.retrans = sunos_mount->retrans;
+ linux_nfs_mount.rsize = get_default (sunos_mount.rsize, 8192);
+ linux_nfs_mount.wsize = get_default (sunos_mount.wsize, 8192);
+ linux_nfs_mount.timeo = get_default (sunos_mount.timeo, 10);
+ linux_nfs_mount.retrans = sunos_mount.retrans;
- linux_nfs_mount.acregmin = sunos_mount->acregmin;
- linux_nfs_mount.acregmax = sunos_mount->acregmax;
- linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
- linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
+ linux_nfs_mount.acregmin = sunos_mount.acregmin;
+ linux_nfs_mount.acregmax = sunos_mount.acregmax;
+ linux_nfs_mount.acdirmin = sunos_mount.acdirmin;
+ linux_nfs_mount.acdirmax = sunos_mount.acdirmax;
- the_name = getname(sunos_mount->hostname);
+ the_name = getname(sunos_mount.hostname);
if(IS_ERR(the_name))
return PTR_ERR(the_name);
@@ -749,7 +755,7 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
- return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
+ return do_sys_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount);
}
asmlinkage int
@@ -758,6 +764,7 @@ sunos_mount(char *type, char *dir, int flags, void *data)
int linux_flags = MS_MGC_MSK; /* new semantics */
int ret = -EINVAL;
char *dev_fname = 0;
+ char *dir_page, *type_page;
if (!capable (CAP_SYS_ADMIN))
return -EPERM;
@@ -777,24 +784,44 @@ sunos_mount(char *type, char *dir, int flags, void *data)
linux_flags |= MS_RDONLY;
if(flags & SMNT_NOSUID)
linux_flags |= MS_NOSUID;
- if(strcmp(type, "ext2") == 0) {
- dev_fname = (char *) data;
- } else if(strcmp(type, "iso9660") == 0) {
- dev_fname = (char *) data;
- } else if(strcmp(type, "minix") == 0) {
- dev_fname = (char *) data;
- } else if(strcmp(type, "nfs") == 0) {
- ret = sunos_nfs_mount (dir, flags, data);
+
+ dir_page = getname(dir);
+ ret = PTR_ERR(dir_page);
+ if (IS_ERR(dir_page))
goto out;
- } else if(strcmp(type, "ufs") == 0) {
+
+ type_page = getname(type);
+ ret = PTR_ERR(type_page);
+ if (IS_ERR(type_page))
+ goto out1;
+
+ if(strcmp(type_page, "ext2") == 0) {
+ dev_fname = getname(data);
+ } else if(strcmp(type_page, "iso9660") == 0) {
+ dev_fname = getname(data);
+ } else if(strcmp(type_page, "minix") == 0) {
+ dev_fname = getname(data);
+ } else if(strcmp(type_page, "nfs") == 0) {
+ ret = sunos_nfs_mount (dir_page, flags, data);
+ goto out2
+ } else if(strcmp(type_page, "ufs") == 0) {
printk("Warning: UFS filesystem mounts unsupported.\n");
ret = -ENODEV;
- goto out;
- } else if(strcmp(type, "proc")) {
+ goto out2
+ } else if(strcmp(type_page, "proc")) {
ret = -ENODEV;
- goto out;
+ goto out2
}
- ret = sys_mount(dev_fname, dir, type, linux_flags, NULL);
+ ret = PTR_ERR(dev_fname);
+ if (IS_ERR(dev_fname))
+ goto out2;
+ ret = do_sys_mount(dev_fname, dir_page, type_page, linux_flags, NULL);
+ if (dev_fname)
+ putname(dev_fname);
+out2:
+ putname(type_page);
+out1:
+ putname(dir_page);
out:
unlock_kernel();
return ret;
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 8c3e8e4a9..f5e316534 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -13,10 +13,10 @@ lib.a: $(OBJS)
sync
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s
+ $(CPP) $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o
+ $(CC) $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o
dep:
diff --git a/arch/sparc/math-emu/Makefile b/arch/sparc/math-emu/Makefile
index e8880cd07..3c4195085 100644
--- a/arch/sparc/math-emu/Makefile
+++ b/arch/sparc/math-emu/Makefile
@@ -11,10 +11,10 @@ O_TARGET := math-emu.o
O_OBJS := math.o ashldi3.o
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+ $(CPP) $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $< -o $*.o
CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 00a4f35d2..440e4fc61 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -7,6 +7,9 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
+.S.o:
+ $(CC) $(AFLAGS) -ansi -c -o $*.o $<
+
O_TARGET := mm.o
O_OBJS := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
ifeq ($(CONFIG_SUN4),y)
@@ -21,15 +24,3 @@ O_OBJS += sun4c.o
endif
include $(TOPDIR)/Rules.make
-
-hypersparc.o: hypersparc.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
-
-viking.o: viking.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S
-
-tsunami.o: tsunami.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
-
-swift.o: swift.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o swift.o swift.S
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index 6e93111ae..3c8b079c3 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -2408,20 +2408,16 @@ static pgd_t *sun4c_pgd_alloc(void)
*/
static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
- struct dentry *dentry = NULL;
- struct inode *inode = NULL;
pgd_t *pgdp;
pte_t *ptep;
- if (vma->vm_file)
- dentry = vma->vm_file->f_dentry;
- if(dentry)
- inode = dentry->d_inode;
- if(inode) {
- struct address_space *mapping = inode->i_mapping;
+ if (vma->vm_file) {
+ struct address_space *mapping;
unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
struct vm_area_struct *vmaring;
int alias_found = 0;
+
+ mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
spin_lock(&mapping->i_shared_lock);
vmaring = mapping->i_mmap;
do {
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index 8f06e836b..27e5549c0 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.105 2000/03/24 00:34:11 davem Exp $
+# $Id: config.in,v 1.107 2000/03/29 11:56:51 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -18,6 +18,8 @@ define_bool CONFIG_VT_CONSOLE y
bool 'Symmetric multi-processing support' CONFIG_SMP
# Global things across all Sun machines.
+define_bool CONFIG_ISA n
+define_bool CONFIG_PCMCIA n
define_bool CONFIG_SBUS y
define_bool CONFIG_SBUSCHAR y
define_bool CONFIG_BUSMOUSE y
@@ -29,7 +31,6 @@ 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
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 4cfd9b565..2f9febcbe 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -13,6 +13,8 @@ CONFIG_EXPERIMENTAL=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_SMP is not set
+# CONFIG_ISA is not set
+# CONFIG_PCMCIA is not set
CONFIG_SBUS=y
CONFIG_SBUSCHAR=y
CONFIG_BUSMOUSE=y
@@ -24,7 +26,6 @@ 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
@@ -225,6 +226,7 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
# CONFIG_BLK_DEV_AEC6210 is not set
# CONFIG_AEC6210_TUNING is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD7409 is not set
# CONFIG_AMD7409_OVERRIDE is not set
CONFIG_BLK_DEV_CMD64X=y
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 124776f51..5e37c94b4 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -8,10 +8,10 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+ $(CPP) $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $< -o $*.o
all: kernel.o head.o init_task.o
@@ -54,7 +54,7 @@ endif
head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
etrap.S rtrap.S winfixup.S entry.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $*.S -o $*.o
#
# This is just to get the dependencies...
@@ -84,7 +84,7 @@ check_asm: dummy
@echo "#undef __SMP__" >> tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) $(CPPFLAGS) -E tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef __SMP__" >> check_asm.c
@@ -113,7 +113,7 @@ check_asm: dummy
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#define CONFIG_SMP 1" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) -D__SMP__ tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
@@ -138,7 +138,7 @@ check_asm: dummy
@rm -f check_asm check_asm.c
@echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
@echo "#include <linux/sched.h>" > tmp.c
- $(CC) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
+ $(CPP) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S
index 0f86bc896..72120b563 100644
--- a/arch/sparc64/kernel/dtlb_base.S
+++ b/arch/sparc64/kernel/dtlb_base.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_base.S,v 1.5 2000/01/31 04:59:12 davem Exp $
+/* $Id: dtlb_base.S,v 1.7 2000/03/26 09:13:48 davem Exp $
* dtlb_base.S: Front end to DTLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -56,19 +56,19 @@
be,pn %xcc, 3f ! Yep, special processing
srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset
ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE
-1: brlz,pt %g5, 2f ! Valid, load into TLB
+1: brlz,pt %g5, 9f ! Valid, load into TLB
and %g5, (_PAGE_PRESENT|_PAGE_READ), %g4 ! Mask readable bits
ba,a,pt %xcc, 4f ! Invalid, branch out
/* DTLB ** ICACHE line 2: Quick kernel TLB misses */
-3: brgez,a,pn %g4, 1b ! Kernel virtual map?
- ldxa [%g3 + %g6] ASI_N, %g5 ! Yep, load k-vpte
- srlx %g4, 40, %g5 ! Else compute phys-kpte
- andcc %g5, 1, %g0 ! I/O area?
- be,pt %xcc, 2f ! Nope, go and load TLB
+3: brlz,pt %g4, 9f ! Kernel virtual map?
xor %g2, %g4, %g5 ! Finish bit twiddles
- ba,pt %xcc, 2f ! Yes, I/O space, back back
- xor %g5, (KERN_IOBITS), %g5 ! After set E, clear CP/CV
+ ldxa [%g3 + %g6] ASI_N, %g5 ! Yep, load k-vpte
+ ba,pt %xcc, 1b ! Continue tlb reload
+ nop
+9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
+ retry ! Trap return
+ nop
/* DTLB ** ICACHE line 3: winfixups+real_faults */
4: cmp %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page?
@@ -81,14 +81,14 @@
mov TLB_TAG_ACCESS, %g4 ! Prepare for fault processing
/* DTLB ** ICACHE line 4: padding */
+ ldxa [%g4] ASI_DMMU, %g5 ! Load faulting VA page
be,pt %xcc, sparc64_realfault_common ! Jump to normal fault handling
- ldxa [%g4] ASI_DMMU, %g5 ! And load faulting VA page
+ mov FAULT_CODE_DTLB, %g4 ! It was read from DTLB
ba,a,pt %xcc, winfix_trampoline ! Call window fixup code
5: or %g5, _PAGE_ACCESSED, %g5 ! Indicate reference
or %g5, %g4, %g5 ! Set valid
stxa %g5, [%g3 + %g6] ASI_S ! Update PTE table (cant trap)
-2: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
- retry ! Trap return
+ ba,a,pt %xcc, 9b ! Complete tlb miss
#undef TAG_CONTEXT_BITS
#undef VPTE_SHIFT
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 73f3596e1..5e99d5d47 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.19 2000/01/31 04:59:12 davem Exp $
+/* $Id: dtlb_prot.S,v 1.20 2000/03/26 09:13:48 davem Exp $
* dtlb_prot.S: DTLB protection trap strategy.
* This is included directly into the trap table.
*
@@ -40,15 +40,15 @@
/* PROT ** ICACHE line 3: Real user faults */
1: rdpr %pstate, %g5 ! Move into alternate globals
wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
- rdpr %tl, %g4 ! Need to do a winfixup?
- cmp %g4, 1 ! Trap level >1?
+ rdpr %tl, %g1 ! Need to do a winfixup?
+ cmp %g1, 1 ! Trap level >1?
mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr
bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup
ldxa [%g4] ASI_DMMU, %g5 ! Put tagaccess in %g5
ba,pt %xcc, sparc64_realfault_common ! Nope, normal fault
/* PROT ** ICACHE line 4: More real fault processing */
- mov 1, %g4 ! Indicate this was a write
+ mov FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
nop
nop
nop
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 903bcf445..f64422a0e 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.46 1999/11/19 05:52:48 davem Exp $
+/* $Id: ebus.c,v 1.47 2000/03/25 05:18:10 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -278,7 +278,6 @@ void __init ebus_init(void)
struct linux_ebus *ebus;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
- unsigned short pci_command;
int nd, ebusnd;
int num_ebus = 0;
@@ -328,17 +327,6 @@ void __init ebus_init(void)
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
- /* Enable BUS Master. */
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- pci_command |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
- /* Set reasonable cache line size and latency timer values. */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-
- /* NOTE: Cache line size is in 32-bit word units. */
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64/sizeof(u32));
-
ebus_ranges_init(ebus);
ebus_intmap_init(ebus);
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 2ab8b70d4..529703dfc 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.113 2000/03/06 22:33:42 davem Exp $
+/* $Id: entry.S,v 1.115 2000/03/29 09:55:30 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -998,12 +998,12 @@ linux_sparc_syscall32:
mov %i5, %o5 ! IEU1
srl %i2, 0, %o2 ! IEU0 Group
- mov %i0, %l5 ! IEU1
- andcc %l0, 0x20, %g0 ! IEU1 Group
+ andcc %l0, 0x20, %g0 ! IEU0 Group
bne,pn %icc, linux_syscall_trace32 ! CTI
- srl %i3, 0, %o3 ! IEU0
+ mov %i0, %l5 ! IEU1
call %l7 ! CTI Group brk forced
- add %o7, 3f-.-4, %o7 ! IEU0
+ srl %i3, 0, %o3 ! IEU0
+ ba,a,pt %xcc, 3f
/* Linux native and SunOS system calls enter here... */
.align 32
@@ -1032,30 +1032,31 @@ linux_sparc_syscall:
mov %i0, %l5 ! IEU0
2: call %l7 ! CTI Group brk forced
mov %i5, %o5 ! IEU0
+ nop
+
3: stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
ret_sys_call:
#ifdef SYSCALL_TRACING
call syscall_trace_exit
add %sp, STACK_BIAS + REGWIN_SZ, %o1
#endif
- ldx [%curptr + AOFF_task_flags], %l6
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
sra %o0, 0, %o0
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
cmp %o0, -ENOIOCTLCMD
sllx %g2, 32, %g2
bgeu,pn %xcc, 1f
- andcc %l6, 0x20, %l6
- /* System call success, clear Carry condition code. */
- andn %g3, %g2, %g3
+ andcc %l0, 0x20, %l6
+ andn %g3, %g2, %g3 /* System call success, clear Carry condition code. */
stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
- add %l1, 0x4, %l2 !npc = npc+4
+ add %l1, 0x4, %l2 ! npc = npc+4
stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
- b,pt %xcc, rtrap_clr_l6
+ ba,pt %xcc, rtrap_clr_l6
stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+
1:
/* System call failure, set Carry condition code.
* Also, get abs(errno) to return to the process.
@@ -1066,15 +1067,14 @@ ret_sys_call:
mov 1, %l6
stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
- add %l1, 0x4, %l2 !npc = npc+4
-
+ add %l1, 0x4, %l2 !npc = npc+4
stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+
b,pt %xcc, rtrap
stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
linux_syscall_trace2:
call syscall_trace
- add %l1, 0x4, %l2 /* npc = npc+4 */
+ nop
stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
@@ -1082,6 +1082,9 @@ linux_syscall_trace2:
.align 32
.globl __flushw_user
__flushw_user:
+ rdpr %otherwin, %g1
+ brz,pn %g1, 2f
+ clr %g2
1: save %sp, -128, %sp
rdpr %otherwin, %g1
brnz,pt %g1, 1b
@@ -1090,4 +1093,4 @@ __flushw_user:
brnz,pt %g2, 1b
restore %g0, %g0, %g0
2: retl
- mov %g3, %o7
+ nop
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index d243a43b3..b0a8f766d 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.42 1999/07/30 09:35:18 davem Exp $
+/* $Id: etrap.S,v 1.43 2000/03/29 09:55:30 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,6 +13,8 @@
#include <asm/head.h>
#define TASK_REGOFF ((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ)
+#define ETRAP_PSTATE1 (PSTATE_RMO | PSTATE_PRIV)
+#define ETRAP_PSTATE2 (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE)
/*
* On entry, %g7 is return address - 0x4.
@@ -20,148 +22,167 @@
*/
.text
- .align 32
- .globl etrap, etrap_irq, etraptl1
- .globl scetrap
-
-etrap: rdpr %pil, %g2 ! Single Group
-etrap_irq: rdpr %tstate, %g1 ! Single Group
- sllx %g2, 20, %g3 ! IEU0 Group
- andcc %g1, TSTATE_PRIV, %g0 ! IEU1
- or %g1, %g3, %g1 ! IEU0 Group
- bne,a,pn %xcc, 1f ! CTI
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1
- sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
- sethi %hi(TSTATE_PEF), %g3 ! IEU1
- or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
- and %g1, %g3, %g3 ! IEU1
- brnz,pn %g3, 1f ! CTI+IEU1 Group
- add %g6, %g2, %g2 ! IEU0
- wr %g0, 0, %fprs ! Single Group+4bubbles
-1: rdpr %tpc, %g3 ! Single Group
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
- rdpr %tnpc, %g1 ! Single Group
- stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group
- rd %y, %g3 ! Single Group+4bubbles
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group
- st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group
- save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group
- rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles
- andn %g6, 0x1f, %l6 ! IEU0 Group
- bne,pn %xcc, 3f ! CTI
- mov PRIMARY_CONTEXT, %l4 ! IEU1
- rdpr %canrestore, %g3 ! Single Group+4bubbles
- rdpr %wstate, %g2 ! Single Group+4bubbles
- wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
- wrpr %g0, 0, %canrestore ! Single Group+4bubbles
- sll %g2, 3, %g2 ! IEU0 Group
- mov 1, %l5 ! IEU1
- stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store
- wrpr %g3, 0, %otherwin ! Single Group+4bubbles
- wrpr %g2, 0, %wstate ! Single Group+4bubbles
- stxa %g0, [%l4] ASI_DMMU ! Store Group
- flush %l6 ! Single Group+9bubbles
- wr %g0, ASI_AIUS, %asi ! Single Group+4bubbles
-2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles
- andn %g1, PSTATE_MM, %l1 ! IEU0 Group
- mov %g4, %l4 ! IEU1
- mov %g5, %l5 ! IEU0 Group
- mov %g7, %l2 ! IEU1
- wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
- stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
- stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group
- stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group
- stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group
- stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group
- stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group
- stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group
- stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group
- stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group
- stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group
- stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group
- sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
- stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group
- stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group
- sllx %g4, 32, %g4 ! IEU0
- stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group
- wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
- jmpl %l2 + 0x4, %g0 ! CTI Group
- mov %l6, %g6 ! IEU0
-
-3: ldub [%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5 ! Load Group
- add %l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4 ! IEU0
- srl %l5, 1, %l3 ! IEU0 Group
- add %l5, 2, %l5 ! IEU1
- stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store
- ba,pt %xcc, 2b ! CTI
- stb %g0, [%l4 + %l3] ! Store Group
-
-etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1
- ba,pt %xcc, 1b ! CTI Group
- andcc %g1, TSTATE_PRIV, %g0 ! IEU0
-
-scetrap: rdpr %pil, %g2 ! Single Group
- rdpr %tstate, %g1 ! Single Group
- sllx %g2, 20, %g3 ! IEU0 Group
- andcc %g1, TSTATE_PRIV, %g0 ! IEU1
- or %g1, %g3, %g1 ! IEU0 Group
- bne,a,pn %xcc, 1f ! CTI
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1
- sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
- sethi %hi(TSTATE_PEF), %g3 ! IEU1
- or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
- and %g1, %g3, %g3 ! IEU1
- brnz,pn %g3, 1f ! CTI+IEU1 Group
- add %g6, %g2, %g2 ! IEU0
- wr %g0, 0, %fprs ! Single Group+4bubbles
-1: rdpr %tpc, %g3 ! Single Group
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
- rdpr %tnpc, %g1 ! Single Group
- stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group
- stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group
- st %g0, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group
- save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group
- rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles
- andn %g6, 0x1f, %l6 ! IEU0 Group
- bne,pn %xcc, 2f ! CTI
- mov PRIMARY_CONTEXT, %l4 ! IEU1
- rdpr %canrestore, %g3 ! Single Group+4bubbles
- rdpr %wstate, %g2 ! Single Group+4bubbles
- wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
- wrpr %g0, 0, %canrestore ! Single Group+4bubbles
- sll %g2, 3, %g2 ! IEU0 Group
- wrpr %g3, 0, %otherwin ! Single Group+4bubbles
- wrpr %g2, 0, %wstate ! Single Group+4bubbles
- stxa %g0, [%l4] ASI_DMMU ! Store Group
- flush %l6 ! Single Group+9bubbles
- wr %g0, ASI_AIUS, %asi ! Single Group+4bubbles
-2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles
- andn %g1, PSTATE_MM, %l1 ! IEU0 Group
- mov %g4, %l4 ! IEU1
- mov %g5, %l5 ! IEU0 Group
- mov %g7, %l2 ! IEU1
- wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
- stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
- stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group
- stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group
- stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group
- stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group
- stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group
- stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group
- stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group
- stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group
- stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group
- stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group
- sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
- stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group
- stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group
- sllx %g4, 32, %g4 ! IEU0
- stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group
- wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
- jmpl %l2 + 0x4, %g0 ! CTI Group
- mov %l6, %g6 ! IEU0
+ .align 64
+ .globl etrap, etrap_irq, etraptl1
+
+etrap: rdpr %pil, %g2 ! Single Group
+etrap_irq: rdpr %tstate, %g1 ! Single Group
+ sllx %g2, 20, %g3 ! IEU0 Group
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU1
+ or %g1, %g3, %g1 ! IEU0 Group
+ bne,pn %xcc, 1f ! CTI
+ sub %sp, REGWIN_SZ+TRACEREG_SZ-STACK_BIAS, %g2 ! IEU1
+ wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
+
+ sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
+ sethi %hi(TSTATE_PEF), %g3 ! IEU1
+ or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
+ and %g1, %g3, %g3 ! IEU1
+ brnz,pn %g3, 1f ! CTI+IEU1 Group
+ add %g6, %g2, %g2 ! IEU0
+ wr %g0, 0, %fprs ! Single Group+4bubbles
+1: rdpr %tpc, %g3 ! Single Group
+
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
+ rdpr %tnpc, %g1 ! Single Group
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group
+ rd %y, %g3 ! Single Group+4bubbles
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group
+ st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group
+ save %g2, -STACK_BIAS, %sp ! Ordering here is critical ! Single Group
+ mov %g6, %l6 ! IEU0 Group
+
+ bne,pn %xcc, 3f ! CTI
+ mov PRIMARY_CONTEXT, %l4 ! IEU1
+ rdpr %canrestore, %g3 ! Single Group+4bubbles
+ rdpr %wstate, %g2 ! Single Group+4bubbles
+ wrpr %g0, 0, %canrestore ! Single Group+4bubbles
+ sll %g2, 3, %g2 ! IEU0 Group
+ mov 1, %l5 ! IEU1
+ stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store
+
+ wrpr %g3, 0, %otherwin ! Single Group+4bubbles
+ wrpr %g2, 0, %wstate ! Single Group+4bubbles
+ stxa %g0, [%l4] ASI_DMMU ! Store Group
+ flush %l6 ! Single Group+9bubbles
+ wr %g0, ASI_AIUS, %asi ! Single Group+4bubbles
+2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles
+ mov %g4, %l4 ! IEU1
+ mov %g5, %l5 ! IEU0 Group
+
+ mov %g7, %l2 ! IEU1
+ wrpr %g0, ETRAP_PSTATE1, %pstate ! Single Group+4bubbles
+ stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
+ stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group
+ stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group
+ stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group
+ stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group
+
+ stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group
+ stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group
+ stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group
+ stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group
+ stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group
+ stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group
+ sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
+ stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group
+
+ stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group
+ sllx %g4, 32, %g4 ! IEU0
+ stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group
+ wrpr %g0, ETRAP_PSTATE2, %pstate ! Single Group+4bubbles
+ jmpl %l2 + 0x4, %g0 ! CTI Group
+ mov %l6, %g6 ! IEU0
+ nop
+ nop
+
+3: ldub [%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5 ! Load Group
+ add %l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4 ! IEU0
+ srl %l5, 1, %l3 ! IEU0 Group
+ add %l5, 2, %l5 ! IEU1
+ stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store
+ ba,pt %xcc, 2b ! CTI
+ stb %g0, [%l4 + %l3] ! Store Group
+ nop
+
+etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1
+ ba,pt %xcc, 1b ! CTI Group
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU0
+
+ .align 64
+ .globl scetrap
+scetrap: rdpr %pil, %g2 ! Single Group
+ rdpr %tstate, %g1 ! Single Group
+ sllx %g2, 20, %g3 ! IEU0 Group
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU1
+ or %g1, %g3, %g1 ! IEU0 Group
+ bne,pn %xcc, 1f ! CTI
+ sub %sp, (REGWIN_SZ+TRACEREG_SZ-STACK_BIAS), %g2 ! IEU1
+ wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
+
+ sllx %g1, 51, %g3 ! IEU0 Group
+ sethi %hi(TASK_REGOFF), %g2 ! IEU1
+ or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
+ brlz,pn %g3, 1f ! CTI+IEU1
+ add %g6, %g2, %g2 ! IEU0 Group
+ wr %g0, 0, %fprs ! Single Group+4bubbles
+1: rdpr %tpc, %g3 ! Single Group
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
+
+ rdpr %tnpc, %g1 ! Single Group
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group
+ save %g2, -STACK_BIAS, %sp ! Ordering here is critical ! Single Group
+ mov %g6, %l6 ! IEU0 Group
+ bne,pn %xcc, 2f ! CTI
+ mov ASI_P, %l7 ! IEU1
+ rdpr %canrestore, %g3 ! Single Group+4bubbles
+
+ rdpr %wstate, %g2 ! Single Group+4bubbles
+ wrpr %g0, 0, %canrestore ! Single Group+4bubbles
+ sll %g2, 3, %g2 ! IEU0 Group
+ mov PRIMARY_CONTEXT, %l4 ! IEU1
+ wrpr %g3, 0, %otherwin ! Single Group+4bubbles
+ wrpr %g2, 0, %wstate ! Single Group+4bubbles
+ stxa %g0, [%l4] ASI_DMMU ! Store
+ flush %l6 ! Single Group+9bubbles
+
+ mov ASI_AIUS, %l7 ! IEU0 Group
+2: mov %g4, %l4 ! IEU1
+ mov %g5, %l5 ! IEU0 Group
+ add %g7, 0x4, %l2 ! IEU1
+ wrpr %g0, ETRAP_PSTATE1, %pstate ! Single Group+4bubbles
+ stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
+ stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
+ sllx %l7, 24, %l7 ! IEU0
+
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group
+ rdpr %cwp, %l0 ! Single Group
+ stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group
+ stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group
+ stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group
+ stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group
+ or %l7, %l0, %l7 ! IEU0
+ sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 ! IEU1
+
+ or %l7, %l0, %l7 ! IEU0 Group
+ wrpr %l2, %tnpc ! Single Group+4bubbles
+ wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate ! Single Group+4bubbles
+ stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group
+ stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group
+ stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group
+ stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group
+ stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group
+
+ sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
+ stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group
+ stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group
+ sllx %g4, 32, %g4 ! IEU0
+ mov %l6, %g6 ! IEU1
+ stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group
+ done
+ nop
#undef TASK_REGOFF
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 254e2eb8a..ef07fca85 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.85 2000/03/23 05:25:41 davem Exp $
+/* $Id: ioctl32.c,v 1.87 2000/03/30 02:09:07 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
@@ -2716,6 +2716,25 @@ COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
COMPATIBLE_IOCTL(SG_EMULATED_HOST)
COMPATIBLE_IOCTL(SG_SET_TRANSFORM)
COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
+COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
+COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
+COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
+COMPATIBLE_IOCTL(SG_SET_DEBUG)
+COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
+COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
+COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
+COMPATIBLE_IOCTL(SG_SCSI_RESET)
+COMPATIBLE_IOCTL(SG_IO)
+COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
+COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
+COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
/* PPP stuff */
COMPATIBLE_IOCTL(PPPIOCGFLAGS)
COMPATIBLE_IOCTL(PPPIOCSFLAGS)
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S
index 4ef509731..7f0da3d14 100644
--- a/arch/sparc64/kernel/itlb_base.S
+++ b/arch/sparc64/kernel/itlb_base.S
@@ -1,4 +1,4 @@
-/* $Id: itlb_base.S,v 1.8 2000/01/31 04:59:12 davem Exp $
+/* $Id: itlb_base.S,v 1.9 2000/03/26 09:13:48 davem Exp $
* itlb_base.S: Front end to ITLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -40,25 +40,25 @@
/* ITLB ** ICACHE line 3: Real faults */
rdpr %tpc, %g5 ! And load faulting VA
- clr %g4 ! It was read
+ mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB
sparc64_realfault_common: ! Called by TL0 dtlb_miss too
- sethi %hi(1f), %g7 ! Save state
- ba,pt %xcc, etrap ! ...
-1: or %g7, %lo(1b), %g7 ! ...
- mov %l4, %o2 ! Read/Write/No idea
- srlx %l5, PAGE_SHIFT, %o1 ! Page align faulting VA
- add %sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
-
-/* ITLB ** ICACHE line 4: Call fault processing code */
+ stb %g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
+ stx %g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
+ ba,pt %xcc, etrap ! Save state
+1: rd %pc, %g7 ! ...
call do_sparc64_fault ! Call fault handler
- sllx %o1, PAGE_SHIFT, %o1 ! Finish page alignment
- ba,a,pt %xcc, rtrap_clr_l6 ! Restore cpu state
- nop
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
+
+/* ITLB ** ICACHE line 4: Finish faults + window fixups */
+ ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state
+ nop
winfix_trampoline:
rdpr %tpc, %g3 ! Prepare winfixup TNPC
or %g3, 0x7c, %g3 ! Compute offset to branch
wrpr %g3, %tnpc ! Write it into TNPC
done ! Do it to it
+ nop
+ nop
#undef TAG_CONTEXT_BITS
#undef VPTE_SHIFT
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 154ee0181..98b41d079 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.6 2000/01/06 23:51:49 davem Exp $
+/* $Id: pci_common.c,v 1.7 2000/03/25 05:18:11 davem Exp $
* pci_common.c: PCI controller common support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -565,6 +565,165 @@ void __init pci_fixup_irq(struct pci_pbm_info *pbm,
pci_fixup_irq(pbm, pci_bus_b(walk));
}
+#undef DEBUG_BUSMASTERING
+
+static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
+{
+ u16 cmd;
+ u8 hdr_type, min_gnt, ltimer;
+
+#ifdef DEBUG_BUSMASTERING
+ printk("PCI: Checking DEV(%s), ", pdev->name);
+#endif
+
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+ /* Read it back, if the mastering bit did not
+ * get set, the device does not support bus
+ * mastering so we have nothing to do here.
+ */
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if ((cmd & PCI_COMMAND_MASTER) == 0) {
+#ifdef DEBUG_BUSMASTERING
+ printk("no bus mastering...\n");
+#endif
+ return;
+ }
+
+ /* Set correct cache line size, 64-byte on all
+ * Sparc64 PCI systems. Note that the value is
+ * measured in 32-bit words.
+ */
+#ifdef DEBUG_BUSMASTERING
+ printk("set cachelinesize, ");
+#endif
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ 64 / sizeof(u32));
+
+ pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type);
+ hdr_type &= ~0x80;
+ if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
+#ifdef DEBUG_BUSMASTERING
+ printk("hdr_type=%x, exit\n", hdr_type);
+#endif
+ return;
+ }
+
+ /* If the latency timer is already programmed with a non-zero
+ * value, assume whoever set it (OBP or whoever) knows what
+ * they are doing.
+ */
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ltimer);
+ if (ltimer != 0) {
+#ifdef DEBUG_BUSMASTERING
+ printk("ltimer was %x, exit\n", ltimer);
+#endif
+ return;
+ }
+
+ /* XXX Since I'm tipping off the min grant value to
+ * XXX choose a suitable latency timer value, I also
+ * XXX considered making use of the max latency value
+ * XXX as well. Unfortunately I've seen too many bogusly
+ * XXX low settings for it to the point where it lacks
+ * XXX any usefulness. In one case, an ethernet card
+ * XXX claimed a min grant of 10 and a max latency of 5.
+ * XXX Now, if I had two such cards on the same bus I
+ * XXX could not set the desired burst period (calculated
+ * XXX from min grant) without violating the max latency
+ * XXX bound. Duh...
+ * XXX
+ * XXX I blame dumb PC bios implementors for stuff like
+ * XXX this, most of them don't even try to do something
+ * XXX sensible with latency timer values and just set some
+ * XXX default value (usually 32) into every device.
+ */
+
+ pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt);
+
+ if (min_gnt == 0) {
+ /* If no min_gnt setting then use a default
+ * value.
+ */
+ if (is_66mhz)
+ ltimer = 16;
+ else
+ ltimer = 32;
+ } else {
+ int shift_factor;
+
+ if (is_66mhz)
+ shift_factor = 2;
+ else
+ shift_factor = 3;
+
+ /* Use a default value when the min_gnt value
+ * is erroneously high.
+ */
+ if (((unsigned int) min_gnt << shift_factor) > 512 ||
+ ((min_gnt << shift_factor) & 0xff) == 0) {
+ ltimer = 8 << shift_factor;
+ } else {
+ ltimer = min_gnt << shift_factor;
+ }
+ }
+
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer);
+#ifdef DEBUG_BUSMASTERING
+ printk("set ltimer to %x\n", ltimer);
+#endif
+}
+
+void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct list_head *walk;
+ int all_are_66mhz;
+ u16 status;
+
+ if (pbm->is_66mhz_capable == 0) {
+ all_are_66mhz = 0;
+ goto out;
+ }
+
+ walk = &pbus->devices;
+ all_are_66mhz = 1;
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next) {
+ struct pci_dev *pdev = pci_dev_b(walk);
+
+ pci_read_config_word(pdev, PCI_STATUS, &status);
+ if (!(status & PCI_STATUS_66MHZ)) {
+ all_are_66mhz = 0;
+ break;
+ }
+ }
+out:
+ pbm->all_devs_66mhz = all_are_66mhz;
+
+ printk("PCI%d(PBM%c): Bus running at %dMHz\n",
+ pbm->parent->index,
+ (pbm == &pbm->parent->pbm_A) ? 'A' : 'B',
+ (all_are_66mhz ? 66 : 33));
+}
+
+void pci_setup_busmastering(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct list_head *walk = &pbus->devices;
+ int is_66mhz;
+
+ is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz;
+
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next)
+ pdev_setup_busmastering(pci_dev_b(walk), is_66mhz);
+
+ walk = &pbus->children;
+ for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+ pci_setup_busmastering(pbm, pci_bus_b(walk));
+}
+
/* Generic helper routines for PCI error reporting. */
void pci_scan_for_target_abort(struct pci_controller_info *p,
struct pci_pbm_info *pbm,
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index eeda574f7..54a8952b8 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -1,4 +1,4 @@
-/* $Id: pci_impl.h,v 1.5 2000/02/08 05:11:32 jj Exp $
+/* $Id: pci_impl.h,v 1.6 2000/03/25 05:18:11 davem Exp $
* pci_impl.h: Helper definitions for PCI controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -28,6 +28,10 @@ extern void pci_assign_unassigned(struct pci_pbm_info *pbm,
struct pci_bus *pbus);
extern void pci_fixup_irq(struct pci_pbm_info *pbm,
struct pci_bus *pbus);
+extern void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus);
+extern void pci_setup_busmastering(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus);
/* Error reporting support. */
extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 1c8f59f3f..a45fe4740 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.14 2000/03/10 02:42:15 davem Exp $
+/* $Id: pci_psycho.c,v 1.15 2000/03/25 05:18:11 davem Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1193,6 +1193,23 @@ static void __init pbm_bridge_reconfigure(struct pci_controller_info *p)
pbm_renumber(&p->pbm_A, 0xff);
}
+static void __init pbm_config_busmastering(struct pci_pbm_info *pbm)
+{
+ u8 *addr;
+
+ /* Set cache-line size to 64 bytes, this is actually
+ * a nop but I do it for completeness.
+ */
+ addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PCI_CACHE_LINE_SIZE);
+ pci_config_write8(addr, 64 / sizeof(u32));
+
+ /* Set PBM latency timer to 64 PCI clocks. */
+ addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PCI_LATENCY_TIMER);
+ pci_config_write8(addr, 64);
+}
+
static void __init pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
{
@@ -1203,11 +1220,17 @@ static void __init pbm_scan_bus(struct pci_controller_info *p,
pci_record_assignments(pbm, pbm->pci_bus);
pci_assign_unassigned(pbm, pbm->pci_bus);
pci_fixup_irq(pbm, pbm->pci_bus);
+ pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
+ pci_setup_busmastering(pbm, pbm->pci_bus);
}
static void __init psycho_scan_bus(struct pci_controller_info *p)
{
pbm_bridge_reconfigure(p);
+ pbm_config_busmastering(&p->pbm_B);
+ p->pbm_B.is_66mhz_capable = 0;
+ pbm_config_busmastering(&p->pbm_A);
+ p->pbm_A.is_66mhz_capable = 1;
pbm_scan_bus(p, &p->pbm_B);
pbm_scan_bus(p, &p->pbm_A);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index a10f5f072..a55772179 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.15 2000/03/10 02:42:16 davem Exp $
+/* $Id: pci_sabre.c,v 1.16 2000/03/25 05:18:12 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1060,6 +1060,13 @@ static void __init sabre_scan_bus(struct pci_controller_info *p)
struct pci_bus *sabre_bus;
struct list_head *walk;
+ /* The APB bridge speaks to the Sabre host PCI bridge
+ * at 66Mhz, but the front side of APB runs at 33Mhz
+ * for both segments.
+ */
+ p->pbm_A.is_66mhz_capable = 0;
+ p->pbm_B.is_66mhz_capable = 0;
+
/* Unlike for PSYCHO, we can only have one SABRE
* in a system. Having multiple SABREs is thus
* and error, and as a consequence we do not need
@@ -1079,6 +1086,17 @@ static void __init sabre_scan_bus(struct pci_controller_info *p)
sabre_bus = pci_scan_bus(p->pci_first_busno,
p->pci_ops,
&p->pbm_A);
+
+ {
+ unsigned int devfn;
+ u8 *addr;
+
+ devfn = PCI_DEVFN(0, 0);
+ addr = sabre_pci_config_mkaddr(&p->pbm_A, 0,
+ devfn, PCI_LATENCY_TIMER);
+ pci_config_write8(addr, 32);
+ }
+
apb_init(p, sabre_bus);
walk = &sabre_bus->children;
@@ -1099,6 +1117,8 @@ static void __init sabre_scan_bus(struct pci_controller_info *p)
pci_record_assignments(pbm, pbus);
pci_assign_unassigned(pbm, pbus);
pci_fixup_irq(pbm, pbus);
+ pci_determine_66mhz_disposition(pbm, pbus);
+ pci_setup_busmastering(pbm, pbus);
}
sabre_register_error_handlers(p);
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index dd71b1e92..8ac030324 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.104 2000/03/01 02:53:32 davem Exp $
+/* $Id: process.c,v 1.105 2000/03/26 09:13:48 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -451,7 +451,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
{
unsigned long fp, distance, rval;
- if(!(current->thread.flags & SPARC_FLAG_32BIT)) {
+ if (!(current->thread.flags & SPARC_FLAG_32BIT)) {
csp += STACK_BIAS;
psp += STACK_BIAS;
__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
@@ -466,14 +466,14 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
distance = fp - psp;
rval = (csp - distance);
- if(copy_in_user(rval, psp, distance))
+ if (copy_in_user(rval, psp, distance))
rval = 0;
- else if(current->thread.flags & SPARC_FLAG_32BIT) {
- if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
+ else if (current->thread.flags & SPARC_FLAG_32BIT) {
+ if (put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
rval = 0;
} else {
- if(put_user(((u64)csp - STACK_BIAS),
- &(((struct reg_window *)rval)->ins[6])))
+ if (put_user(((u64)csp - STACK_BIAS),
+ &(((struct reg_window *)rval)->ins[6])))
rval = 0;
else
rval = rval - STACK_BIAS;
@@ -488,7 +488,7 @@ static inline void shift_window_buffer(int first_win, int last_win,
{
int i;
- for(i = first_win; i < last_win; i++) {
+ for (i = first_win; i < last_win; i++) {
t->rwbuf_stkptrs[i] = t->rwbuf_stkptrs[i+1];
memcpy(&t->reg_window[i], &t->reg_window[i+1],
sizeof(struct reg_window));
@@ -501,11 +501,11 @@ void synchronize_user_stack(void)
unsigned long window;
flush_user_windows();
- if((window = t->w_saved) != 0) {
+ if ((window = t->w_saved) != 0) {
int winsize = REGWIN_SZ;
int bias = 0;
- if(t->flags & SPARC_FLAG_32BIT)
+ if (t->flags & SPARC_FLAG_32BIT)
winsize = REGWIN32_SZ;
else
bias = STACK_BIAS;
@@ -515,11 +515,11 @@ void synchronize_user_stack(void)
unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
struct reg_window *rwin = &t->reg_window[window];
- if(!copy_to_user((char *)sp, rwin, winsize)) {
+ if (!copy_to_user((char *)sp, rwin, winsize)) {
shift_window_buffer(window, t->w_saved - 1, t);
t->w_saved--;
}
- } while(window--);
+ } while (window--);
}
}
@@ -530,25 +530,29 @@ void fault_in_user_windows(struct pt_regs *regs)
int winsize = REGWIN_SZ;
int bias = 0;
- if(t->flags & SPARC_FLAG_32BIT)
+ if (t->flags & SPARC_FLAG_32BIT)
winsize = REGWIN32_SZ;
else
bias = STACK_BIAS;
+
flush_user_windows();
window = t->w_saved;
- if(window != 0) {
+
+ if (window != 0) {
window -= 1;
do {
unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
struct reg_window *rwin = &t->reg_window[window];
- if(copy_to_user((char *)sp, rwin, winsize))
+ if (copy_to_user((char *)sp, rwin, winsize))
goto barf;
- } while(window--);
+ } while (window--);
}
t->w_saved = 0;
return;
+
barf:
+ t->w_saved = window + 1;
do_exit(SIGILL);
}
@@ -578,7 +582,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
t->cwp = (regs->tstate + 1) & TSTATE_CWP;
t->fpsaved[0] = 0;
- if(regs->tstate & TSTATE_PRIV) {
+
+ if (regs->tstate & TSTATE_PRIV) {
/* Special case, if we are spawning a kernel thread from
* a userspace task (via KMOD, NFS, or similar) we must
* disable performance counters in the child because the
@@ -597,7 +602,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
sizeof(struct reg_window));
t->kregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
- if(t->flags & SPARC_FLAG_32BIT) {
+ if (t->flags & SPARC_FLAG_32BIT) {
sp &= 0x00000000ffffffffUL;
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
}
@@ -607,7 +612,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
unsigned long csp;
csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
- if(!csp)
+ if (!csp)
return -EFAULT;
t->kregs->u_regs[UREG_FP] = csp;
}
@@ -621,19 +626,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
/* Set the second return value for the parent. */
regs->u_regs[UREG_I1] = 0;
-#if 0
- printk("\ncopy_thread: c(%p[mm(%p:%p)]) p(%p[mm(%p:%p)])\n",
- current, current->mm, current->active_mm,
- p, p->mm, p->active_mm);
- printk("copy_thread: c MM_ctx(%016lx) MM_pgd(%016lx)\n",
- (current->mm ? current->mm->context : 0),
- (current->mm ? pgd_val(current->mm->pgd[0]) : 0));
- printk("copy_thread: p MM_ctx(%016lx) MM_pgd(%08x)\n",
- (p->mm ? p->mm->context : 0),
- (p->mm ? pgd_val(p->mm->pgd[0]) : 0));
- printk("copy_thread: c->flags(%x) p->flags(%x) ",
- current->thread.flags, p->thread.flags);
-#endif
+
return 0;
}
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index d059a5a28..1c9b6ac3f 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.48 2000/02/09 11:15:07 davem Exp $
+/* $Id: rtrap.S,v 1.49 2000/03/29 09:55:31 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -14,194 +14,207 @@
#include <asm/processor.h>
#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ)
+#define RTRAP_PSTATE (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
+#define RTRAP_PSTATE_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV)
+#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
+
+#if 0
+#define RTRAP_CHECK call rtrap_check; add %sp, (STACK_BIAS+REGWIN_SZ), %o0;
+#else
+#define RTRAP_CHECK
+#endif
.text
+
.align 32
+__handle_softirq:
+ call do_softirq
+ nop
+ ba,a,pt %xcc, __handle_softirq_continue
+ nop
+__handle_preemption:
+ call schedule
+ nop
+ ba,pt %xcc, __handle_preemption_continue
+ nop
+__handle_user_windows:
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ call fault_in_user_windows
+ add %sp, STACK_BIAS + REGWIN_SZ, %g0
+ ba,a,pt %xcc, __handle_user_windows_continue
+__handle_perfctrs:
+ /* Don't forget to preserve user window invariants. */
+ wrpr %g0, RTRAP_PSTATE, %pstate
+ call update_perfctrs
+ nop
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
+ brz,pt %o2, __handle_perfctrs_continue
+ sethi %hi(TSTATE_PEF), %l6
+ wrpr %g0, RTRAP_PSTATE, %pstate
+
+ call fault_in_user_windows
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, __handle_perfctrs_continue
+ nop
+__handle_userfpu:
+ rd %fprs, %l5
+ andcc %l5, FPRS_FEF, %g0
+ be,a,pn %icc, __handle_userfpu_continue
+ andn %l1, %l6, %l1
+ ba,a,pt %xcc, __handle_userfpu_continue
+__handle_signal:
+ clr %o0
+ mov %l5, %o2
+ mov %l6, %o3
+ call do_signal
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ ba,pt %xcc, __handle_signal_continue
+ clr %l6
+ nop
+
+ .align 64
.globl rtrap_clr_l6, rtrap
rtrap_clr_l6: clr %l6
- /* Fall through */
rtrap: lduw [%g6 + AOFF_task_processor], %l0
sethi %hi(softirq_state), %l2
or %l2, %lo(softirq_state), %l2
sllx %l0, 6, %l0
ldx [%l2 + %l0], %l1
srlx %l1, 32, %l2
-
andcc %l1, %l2, %g0
- be,pt %icc, 2f
- nop
- call do_softirq
- nop
-2: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+
+ bne,pn %icc, __handle_softirq
+ ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+__handle_softirq_continue:
sethi %hi(0xf << 20), %l4
andcc %l1, TSTATE_PRIV, %l3
-
and %l1, %l4, %l4
- rdpr %pstate, %l7
- andn %l1, %l4, %l1
- be,pt %icc, to_user
- andn %l7, PSTATE_IE, %l7
+ bne,pn %icc, to_kernel
+ andn %l1, %l4, %l1
+to_user: ldx [%g6 + AOFF_task_need_resched], %l0
+
+ brnz,pn %l0, __handle_preemption
+__handle_preemption_continue:
+ lduw [%g6 + AOFF_task_sigpending], %l0
+ brnz,pn %l0, __handle_signal
+ nop
+__handle_signal_continue:
+check_user_wins:
+ wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
+ brnz,pn %o2, __handle_user_windows
+ sethi %hi(TSTATE_PEF), %l6
+
+__handle_user_windows_continue:
+ RTRAP_CHECK
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
+ andcc %l5, SPARC_FLAG_PERFCTR, %g0
+ bne,pn %xcc, __handle_perfctrs
+__handle_perfctrs_continue:
+ andcc %l1, %l6, %g0
+ bne,pn %xcc, __handle_userfpu
+ stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+__handle_userfpu_continue:
- ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
- brz,pt %l5, rt_continue
- srl %l5, 1, %o0
- add %g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6
- ldub [%l6 + %o0], %l2
- sub %l5, 2, %l5
- add %g6, AOFF_task_thread + AOFF_thread_gsr, %o1
- andcc %l2, (FPRS_FEF|FPRS_DU), %g0
- be,pt %icc, 2f
- and %l2, FPRS_DL, %l6
- andcc %l2, FPRS_FEF, %g0
- be,pn %icc, 5f
- sll %o0, 3, %o5
- rd %fprs, %g5
- wr %g5, FPRS_FEF, %fprs
- ldub [%o1 + %o0], %g5
- add %g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
- membar #StoreLoad | #LoadLoad
- sll %o0, 8, %o2
- add %g6, AOFF_task_fpregs, %o3
- brz,pn %l6, 1f
- add %g6, AOFF_task_fpregs+0x40, %o4
- ldda [%o3 + %o2] ASI_BLK_P, %f0
- ldda [%o4 + %o2] ASI_BLK_P, %f16
-1: andcc %l2, FPRS_DU, %g0
- be,pn %icc, 1f
- wr %g5, 0, %gsr
- add %o2, 0x80, %o2
- ldda [%o3 + %o2] ASI_BLK_P, %f32
- ldda [%o4 + %o2] ASI_BLK_P, %f48
-1: membar #Sync
- ldx [%o1 + %o5], %fsr
-2: stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
+
ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
- mov %g6, %o5
ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4
ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5
ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6
ldx [%sp + PTREGS_OFF + PT_V9_G7], %g7
-
- wrpr %l7, PSTATE_AG, %pstate
+ wrpr %g0, RTRAP_PSTATE_AG_IRQOFF, %pstate
ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0
ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1
+
ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2
ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3
ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4
ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5
ldx [%sp + PTREGS_OFF + PT_V9_I6], %i6
-
ldx [%sp + PTREGS_OFF + PT_V9_I7], %i7
- ld [%sp + PTREGS_OFF + PT_V9_Y], %o3
ldx [%sp + PTREGS_OFF + PT_V9_TPC], %l2
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %o2
+
+ ld [%sp + PTREGS_OFF + PT_V9_Y], %o3
wr %o3, %g0, %y
srl %l4, 20, %l4
wrpr %l4, 0x0, %pil
wrpr %g0, 0x1, %tl
-
wrpr %l1, %g0, %tstate
wrpr %l2, %g0, %tpc
wrpr %o2, %g0, %tnpc
+
brnz,pn %l3, kern_rtt
mov PRIMARY_CONTEXT, %l7
ldxa [%l7 + %l7] ASI_DMMU, %l0
stxa %l0, [%l7] ASI_DMMU
- flush %o5
-
+ flush %g6
rdpr %wstate, %l1
rdpr %otherwin, %l2
srl %l1, 3, %l1
+
wrpr %l2, %g0, %canrestore
wrpr %l1, %g0, %wstate
wrpr %g0, %g0, %otherwin
restore
rdpr %canrestore, %g1
-
wrpr %g1, 0x0, %cleanwin
retry
+ nop
+
kern_rtt: restore
retry
-to_user: ldx [%g6 + AOFF_task_need_resched], %l0
- wrpr %l7, PSTATE_IE, %pstate
- orcc %g0, %l0, %g0
- be,a,pt %xcc, check_signal
-
- lduw [%g6 + AOFF_task_sigpending], %l0
- call schedule
- nop
- lduw [%g6 + AOFF_task_sigpending], %l0
-check_signal: brz,a,pt %l0, check_user_wins
- nop
- clr %o0
- mov %l5, %o2
- mov %l6, %o3
- call do_signal
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
- clr %l6
-
- /* We must not take any traps between here and the actual
- * return to user-space. If we do we risk having windows
- * saved to the thread struct between the test and the
- * actual return from trap. --DaveM
- */
-check_user_wins:
- wrpr %l7, 0x0, %pstate
- ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
- brz,pt %o2, 1f
- sethi %hi(TSTATE_PEF), %l6
+to_kernel: ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
+ brz,pt %l5, rt_continue
+ srl %l5, 1, %o0
+ add %g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6
+ ldub [%l6 + %o0], %l2
+ sub %l5, 2, %l5
- wrpr %l7, PSTATE_IE, %pstate
- call fault_in_user_windows
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- /* It is OK to leave interrupts on now because if
- * fault_in_user_windows has returned it has left us
- * with a clean user stack state.
- */
-1:
-#if 0
- call rtrap_check
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
-#endif
- ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
- andcc %l5, SPARC_FLAG_PERFCTR, %g0
- be,pt %xcc, 1f
- nop
+ add %g6, AOFF_task_thread + AOFF_thread_gsr, %o1
+ andcc %l2, (FPRS_FEF|FPRS_DU), %g0
+ be,pt %icc, 2f
+ and %l2, FPRS_DL, %l6
+ andcc %l2, FPRS_FEF, %g0
+ be,pn %icc, 5f
+ sll %o0, 3, %o5
+ rd %fprs, %g5
- /* Don't forget to preserve user window invariants. */
- wrpr %l7, PSTATE_IE, %pstate
- call update_perfctrs
- nop
- wrpr %l7, 0x0, %pstate
- ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
- brz,pt %o2, 1f
- sethi %hi(TSTATE_PEF), %l6
- wrpr %l7, PSTATE_IE, %pstate
- call fault_in_user_windows
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ wr %g5, FPRS_FEF, %fprs
+ ldub [%o1 + %o0], %g5
+ add %g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
+ membar #StoreLoad | #LoadLoad
+ sll %o0, 8, %o2
+ add %g6, AOFF_task_fpregs, %o3
+ brz,pn %l6, 1f
+ add %g6, AOFF_task_fpregs+0x40, %o4
-1:
- andcc %l1, %l6, %g0
- be,pt %xcc, rt_continue
- stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+ ldda [%o3 + %o2] ASI_BLK_P, %f0
+ ldda [%o4 + %o2] ASI_BLK_P, %f16
+1: andcc %l2, FPRS_DU, %g0
+ be,pn %icc, 1f
+ wr %g5, 0, %gsr
+ add %o2, 0x80, %o2
+ ldda [%o3 + %o2] ASI_BLK_P, %f32
+ ldda [%o4 + %o2] ASI_BLK_P, %f48
- rd %fprs, %l5
- andcc %l5, FPRS_FEF, %g0
- be,a,pn %icc, rt_continue
- andn %l1, %l6, %l1
+1: membar #Sync
+ ldx [%o1 + %o5], %fsr
+2: stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
ba,pt %xcc, rt_continue
nop
-
5: wr %g0, FPRS_FEF, %fprs
membar #StoreLoad | #LoadLoad
sll %o0, 8, %o2
+
add %g6, AOFF_task_fpregs+0x80, %o3
add %g6, AOFF_task_fpregs+0xc0, %o4
ldda [%o3 + %o2] ASI_BLK_P, %f32
ldda [%o4 + %o2] ASI_BLK_P, %f48
-1: membar #Sync
+ membar #Sync
wr %g0, FPRS_DU, %fprs
ba,pt %xcc, rt_continue
stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c
index 88ab813f3..0919089ef 100644
--- a/arch/sparc64/kernel/semaphore.c
+++ b/arch/sparc64/kernel/semaphore.c
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.2 1999/12/23 17:12:03 jj Exp $
+/* $Id: semaphore.c,v 1.3 2000/03/27 10:38:46 davem Exp $
* Generic semaphore code. Buyer beware. Do your own
* specific changes in <asm/semaphore-helper.h>
*/
@@ -203,7 +203,7 @@ void down_read_failed_biased(struct rw_semaphore *sem)
add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
for (;;) {
- if (clear_le_bit(0, &sem->granted))
+ if (test_and_clear_le_bit(0, &sem->granted))
break;
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!test_le_bit(0, &sem->granted))
@@ -221,7 +221,7 @@ void down_write_failed_biased(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
for (;;) {
- if (clear_le_bit(1, &sem->granted))
+ if (test_and_clear_le_bit(1, &sem->granted))
break;
set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
if (!test_le_bit(1, &sem->granted))
@@ -286,11 +286,11 @@ void down_write_failed(struct rw_semaphore *sem)
void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
{
if (readers) {
- if (set_le_bit(0, &sem->granted))
+ if (test_and_set_le_bit(0, &sem->granted))
BUG();
wake_up(&sem->wait);
} else {
- if (set_le_bit(1, &sem->granted))
+ if (test_and_set_le_bit(1, &sem->granted))
BUG();
wake_up(&sem->write_bias_wait);
}
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 79db5bc4e..e7a50c150 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -616,7 +616,9 @@ static inline void read_maps (void)
if (map->vm_file != NULL) {
dev = map->vm_file->f_dentry->d_inode->i_dev;
ino = map->vm_file->f_dentry->d_inode->i_ino;
- line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+ line = d_path(map->vm_file->f_dentry,
+ map->vm_file->f_vfsmnt,
+ buffer, PAGE_SIZE);
}
printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
kdevname(dev), ino);
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 8df2116e7..423c5f648 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1279,7 +1279,9 @@ static inline void read_maps (void)
if (map->vm_file != NULL) {
dev = map->vm_file->f_dentry->d_inode->i_dev;
ino = map->vm_file->f_dentry->d_inode->i_ino;
- line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+ line = d_path(map->vm_file->f_dentry,
+ map->vm_file->f_vfsmnt,
+ buffer, PAGE_SIZE);
}
printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
kdevname(dev), ino);
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 0d5f615cf..e9a180d2a 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -469,52 +469,83 @@ void smp_flush_tlb_all(void)
*/
void smp_flush_tlb_mm(struct mm_struct *mm)
{
- u32 ctx = CTX_HWBITS(mm->context);
-
- if (mm == current->active_mm &&
- atomic_read(&mm->mm_users) == 1 &&
- (mm->cpu_vm_mask == (1UL << smp_processor_id())))
- goto local_flush_and_out;
+ if (CTX_VALID(mm->context)) {
+ u32 ctx = CTX_HWBITS(mm->context);
+ int cpu = smp_processor_id();
+
+ if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
+ /* See smp_flush_tlb_page for info about this. */
+ mm->cpu_vm_mask = (1UL << cpu);
+ goto local_flush_and_out;
+ }
- smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+ smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
-local_flush_and_out:
- __flush_tlb_mm(ctx, SECONDARY_CONTEXT);
+ local_flush_and_out:
+ __flush_tlb_mm(ctx, SECONDARY_CONTEXT);
+ }
}
void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- u32 ctx = CTX_HWBITS(mm->context);
+ if (CTX_VALID(mm->context)) {
+ u32 ctx = CTX_HWBITS(mm->context);
+ int cpu = smp_processor_id();
- start &= PAGE_MASK;
- end &= PAGE_MASK;
- if(mm == current->active_mm &&
- atomic_read(&mm->mm_users) == 1 &&
- (mm->cpu_vm_mask == (1UL << smp_processor_id())))
- goto local_flush_and_out;
+ start &= PAGE_MASK;
+ end &= PAGE_MASK;
- smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+ if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
+ mm->cpu_vm_mask = (1UL << cpu);
+ goto local_flush_and_out;
+ }
+
+ smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
-local_flush_and_out:
- __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
+ local_flush_and_out:
+ __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
+ }
}
void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
{
- u32 ctx = CTX_HWBITS(mm->context);
-
- page &= PAGE_MASK;
- if(mm == current->active_mm &&
- atomic_read(&mm->mm_users) == 1 &&
- (mm->cpu_vm_mask == (1UL << smp_processor_id()))) {
- goto local_flush_and_out;
- }
+ if (CTX_VALID(mm->context)) {
+ u32 ctx = CTX_HWBITS(mm->context);
+ int cpu = smp_processor_id();
+
+ page &= PAGE_MASK;
+ if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
+ /* By virtue of being the current address space, and
+ * having the only reference to it, the following operation
+ * is safe.
+ *
+ * It would not be a win to perform the xcall tlb flush in
+ * this case, because even if we switch back to one of the
+ * other processors in cpu_vm_mask it is almost certain that
+ * all TLB entries for this context will be replaced by the
+ * time that happens.
+ */
+ mm->cpu_vm_mask = (1UL << cpu);
+ goto local_flush_and_out;
+ } else {
+ /* By virtue of running under the mm->page_table_lock,
+ * and mmu_context.h:switch_mm doing the same, the following
+ * operation is safe.
+ */
+ if (mm->cpu_vm_mask == (1UL << cpu))
+ goto local_flush_and_out;
+ }
- smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+ /* OK, we have to actually perform the cross call. Most likely
+ * this is a cloned mm or kswapd is kicking out pages for a task
+ * which has run recently on another cpu.
+ */
+ smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
-local_flush_and_out:
- __flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
+ local_flush_and_out:
+ __flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
+ }
}
/* CPU capture. */
@@ -603,13 +634,16 @@ static inline void sparc64_do_profile(unsigned long pc, unsigned long o7)
extern int rwlock_impl_begin, rwlock_impl_end;
extern int atomic_impl_begin, atomic_impl_end;
extern int __memcpy_begin, __memcpy_end;
+ extern int __bitops_begin, __bitops_end;
if ((pc >= (unsigned long) &atomic_impl_begin &&
pc < (unsigned long) &atomic_impl_end) ||
(pc >= (unsigned long) &rwlock_impl_begin &&
pc < (unsigned long) &rwlock_impl_end) ||
(pc >= (unsigned long) &__memcpy_begin &&
- pc < (unsigned long) &__memcpy_end))
+ pc < (unsigned long) &__memcpy_end) ||
+ (pc >= (unsigned long) &__bitops_begin &&
+ pc < (unsigned long) &__bitops_end))
pc = o7;
pc -= (unsigned long) &_stext;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 26e11085d..fc7a8cfe5 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.79 2000/03/17 14:41:18 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.80 2000/03/27 10:38:47 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -170,6 +170,13 @@ EXPORT_SYMBOL_NOVERS(__rwsem_wake);
EXPORT_SYMBOL_PRIVATE(atomic_add);
EXPORT_SYMBOL_PRIVATE(atomic_sub);
+/* Atomic bit operations. */
+EXPORT_SYMBOL_PRIVATE(test_and_set_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_clear_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_change_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_set_le_bit);
+EXPORT_SYMBOL_PRIVATE(test_and_clear_le_bit);
+
EXPORT_SYMBOL(ivector_table);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index 34db8d056..c97b266be 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.11 2000/01/11 17:33:29 jj Exp $
+/* $Id: sys32.S,v 1.12 2000/03/24 04:17:37 davem Exp $
* sys32.S: I-cache tricks for 32-bit compatability layer simple
* conversions.
*
@@ -6,6 +6,8 @@
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
+#include <asm/errno.h>
+
/* NOTE: call as jump breaks return stack, we have to avoid that */
.text
@@ -69,3 +71,187 @@ sys32_mmap2:
srl %o5, 0, %o5
jmpl %g1 + %lo(sys_mmap), %g0
sllx %o5, 12, %o5
+
+ .align 32
+ .globl sys32_socketcall
+sys32_socketcall: /* %o0=call, %o1=args */
+ cmp %o0, 1
+ bl,pn %xcc, do_einval
+ cmp %o0, 17
+ bg,pn %xcc, do_einval
+ sub %o0, 1, %o0
+ sllx %o0, 5, %o0
+ sethi %hi(__socketcall_table_begin), %g2
+ or %g2, %lo(__socketcall_table_begin), %g2
+ jmpl %g2 + %o0, %g0
+ nop
+
+ /* Each entry is exactly 32 bytes. */
+ .align 32
+__socketcall_table_begin:
+do_sys_socket: /* sys_socket(int, int, int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_socket), %g1
+ ldswa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys_socket), %g0
+ ldswa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_bind), %g1
+ ldswa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys_bind), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_connect), %g1
+ ldswa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys_connect), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+do_sys_listen: /* sys_listen(int, int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_listen), %g1
+ jmpl %g1 + %lo(sys_listen), %g0
+ ldswa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+ nop
+do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_accept), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys_accept), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_getsockname), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys_getsockname), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_getpeername), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys_getpeername), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_socketpair), %g1
+ ldswa [%o1 + 0x8] %asi, %o2
+ lduwa [%o1 + 0xc] %asi, %o3
+ jmpl %g1 + %lo(sys_socketpair), %g0
+ ldswa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_send), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ lduwa [%o1 + 0xc] %asi, %o3
+ jmpl %g1 + %lo(sys_send), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_recv), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ lduwa [%o1 + 0xc] %asi, %o3
+ jmpl %g1 + %lo(sys_recv), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+do_sys_sendto: /* sys32_sendto(int, u32, __kernel_size_t32, unsigned int, u32, int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys32_sendto), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ lduwa [%o1 + 0xc] %asi, %o3
+ lduwa [%o1 + 0x10] %asi, %o4
+ ldswa [%o1 + 0x14] %asi, %o5
+ jmpl %g1 + %lo(sys32_sendto), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+do_sys_recvfrom: /* sys32_recvfrom(int, u32, __kernel_size_t32, unsigned int, u32, u32) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys32_recvfrom), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ lduwa [%o1 + 0xc] %asi, %o3
+ lduwa [%o1 + 0x10] %asi, %o4
+ lduwa [%o1 + 0x14] %asi, %o5
+ jmpl %g1 + %lo(sys32_recvfrom), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+do_sys_shutdown: /* sys_shutdown(int, int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys_shutdown), %g1
+ jmpl %g1 + %lo(sys_shutdown), %g0
+ ldswa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+ nop
+do_sys_setsockopt: /* sys32_setsockopt(int, int, int, char *, int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys32_setsockopt), %g1
+ ldswa [%o1 + 0x8] %asi, %o2
+ lduwa [%o1 + 0xc] %asi, %o3
+ ldswa [%o1 + 0x10] %asi, %o4
+ jmpl %g1 + %lo(sys32_setsockopt), %g0
+ ldswa [%o1 + 0x4] %asi, %o1
+ nop
+do_sys_getsockopt: /* sys32_getsockopt(int, int, int, u32, u32) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys32_getsockopt), %g1
+ ldswa [%o1 + 0x8] %asi, %o2
+ lduwa [%o1 + 0xc] %asi, %o3
+ lduwa [%o1 + 0x10] %asi, %o4
+ jmpl %g1 + %lo(sys32_getsockopt), %g0
+ ldswa [%o1 + 0x4] %asi, %o1
+ nop
+do_sys_sendmsg: /* sys32_sendmsg(int, struct msghdr32 *, unsigned int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys32_sendmsg), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys32_sendmsg), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+do_sys_recvmsg: /* sys32_recvmsg(int, struct msghdr32 *, unsigned int) */
+ ldswa [%o1 + 0x0] %asi, %o0
+ sethi %hi(sys32_recvmsg), %g1
+ lduwa [%o1 + 0x8] %asi, %o2
+ jmpl %g1 + %lo(sys32_recvmsg), %g0
+ lduwa [%o1 + 0x4] %asi, %o1
+ nop
+ nop
+ nop
+__socketcall_table_end:
+
+do_einval:
+ retl
+ mov -EINVAL, %o0
+do_efault:
+ retl
+ mov -EFAULT, %o0
+
+ .section __ex_table
+ .align 4
+ .word __socketcall_table_begin, 0, __socketcall_table_end, do_efault
+ .previous
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index d752f1a0d..b1eb160ad 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.141 2000/03/24 01:31:30 davem Exp $
+/* $Id: sys_sparc32.c,v 1.142 2000/03/24 04:17:38 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1746,8 +1746,8 @@ static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
return 0;
}
-extern long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
- unsigned long new_flags, unsigned long data_page);
+extern long do_sys_mount(char * dev_page, char * dir_page, char * type_page,
+ unsigned long new_flags, char * data_page);
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
@@ -1756,6 +1756,8 @@ asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned
{
unsigned long type_page = 0;
unsigned long data_page = 0;
+ unsigned long dev_page = 0;
+ unsigned long dir_page = 0;
int err, is_smb, is_ncp;
is_smb = is_ncp = 0;
@@ -1777,19 +1779,32 @@ asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned
if (err)
goto type_out;
+ err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
+ if (err)
+ goto data_out;
+
+ err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
+ if (err)
+ goto dev_out;
+
if (!is_smb && !is_ncp) {
- err = do_sys_mount(dev_name, dir_name, type_page, new_flags,
- data_page);
+ err = do_sys_mount((char*)dev_page, (char*)dir_page,
+ (char*)type_page, new_flags, (char*)data_page);
} else {
if (is_ncp)
do_ncp_super_data_conv((void *)data_page);
else
do_smb_super_data_conv((void *)data_page);
- err = do_sys_mount(dev_name, dir_name, type_page, new_flags,
- data_page);
+ err = do_sys_mount((char*)dev_page, (char*)dir_page,
+ (char*)type_page, new_flags, (char*)data_page);
}
+ free_page(dir_page);
+
+dev_out:
+ free_page(dev_page);
+data_out:
free_page(data_page);
type_out:
@@ -2790,85 +2805,6 @@ asmlinkage int sys32_setsockopt(int fd, int level, int optname,
return sys_setsockopt(fd, level, optname, optval, optlen);
}
-/* Argument list sizes for sys_socketcall */
-#define AL(x) ((x) * sizeof(u32))
-static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
- AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
- AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
-#undef AL
-
-extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
-extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
-extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags);
-extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
- unsigned flags, u32 addr, int addr_len);
-extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
-extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
- unsigned flags, u32 addr, u32 addr_len);
-extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
- u32 optval, u32 optlen);
-
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-extern asmlinkage int sys_socketpair(int family, int type, int protocol,
- int usockvec[2]);
-extern asmlinkage int sys_shutdown(int fd, int how);
-extern asmlinkage int sys_listen(int fd, int backlog);
-
-asmlinkage int sys32_socketcall(int call, u32 *args)
-{
- u32 a[6];
- u32 a0,a1;
-
- if (call<SYS_SOCKET||call>SYS_RECVMSG)
- return -EINVAL;
- if (copy_from_user(a, args, nargs[call]))
- return -EFAULT;
- a0=a[0];
- a1=a[1];
-
- switch(call)
- {
- case SYS_SOCKET:
- return sys_socket(a0, a1, a[2]);
- case SYS_BIND:
- return sys_bind(a0, (struct sockaddr *)A(a1), a[2]);
- case SYS_CONNECT:
- return sys_connect(a0, (struct sockaddr *)A(a1), a[2]);
- case SYS_LISTEN:
- return sys_listen(a0, a1);
- case SYS_ACCEPT:
- return sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
- case SYS_GETSOCKNAME:
- return sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
- case SYS_GETPEERNAME:
- return sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
- case SYS_SOCKETPAIR:
- return sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
- case SYS_SEND:
- return sys_send(a0, (void *)A(a1), a[2], a[3]);
- case SYS_SENDTO:
- return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
- case SYS_RECV:
- return sys_recv(a0, (void *)A(a1), a[2], a[3]);
- case SYS_RECVFROM:
- return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
- case SYS_SHUTDOWN:
- return sys_shutdown(a0,a1);
- case SYS_SETSOCKOPT:
- return sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
- case SYS_GETSOCKOPT:
- return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
- case SYS_SENDMSG:
- return sys32_sendmsg(a0, (struct msghdr32 *)A(a1), a[2]);
- case SYS_RECVMSG:
- return sys32_recvmsg(a0, (struct msghdr32 *)A(a1), a[2]);
- }
- return -EINVAL;
-}
-
extern void check_pending(int signum);
asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
@@ -4144,7 +4080,7 @@ asmlinkage long sparc32_open(const char * filename, int flags, int mode)
if (fd >= 0) {
struct file * f;
lock_kernel();
- f = filp_open(tmp, flags, mode, NULL);
+ f = filp_open(tmp, flags, mode);
unlock_kernel();
error = PTR_ERR(f);
if (IS_ERR(f))
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index a572e4976..291b174ac 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.42 2000/03/15 02:43:35 davem Exp $
+/* $Id: sys_sunos32.c,v 1.43 2000/03/26 11:28:53 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -79,19 +79,17 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
}
retval = -EBADF;
if(!(flags & MAP_ANONYMOUS)) {
+ struct inode * inode;
if(fd >= SUNOS_NR_OPEN)
goto out;
file = fget(fd);
if (!file)
goto out;
- if (file->f_dentry && file->f_dentry->d_inode) {
- struct inode * inode = file->f_dentry->d_inode;
- if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
- MINOR(inode->i_rdev) == 5) {
- flags |= MAP_ANONYMOUS;
- fput(file);
- file = NULL;
- }
+ inode = file->f_dentry->d_inode;
+ if(MAJOR(inode->i_rdev)==MEM_MAJOR && MINOR(inode->i_rdev)==5) {
+ flags |= MAP_ANONYMOUS;
+ fput(file);
+ file = NULL;
}
}
@@ -601,7 +599,7 @@ struct sunos_nfs_mount_args {
char *netname; /* server's netname */
};
-extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
+extern long do_sys_mount(const char *, const char *, char *, int, void *);
extern dev_t get_unnamed_dev(void);
extern void put_unnamed_dev(dev_t);
extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
@@ -627,17 +625,12 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
struct inode *inode;
struct file *file;
- file = fcheck(fd);
+ file = fget(fd);
if(!file)
return 0;
dentry = file->f_dentry;
- if(!dentry)
- return 0;
-
inode = dentry->d_inode;
- if(!inode)
- return 0;
socket = &inode->u.socket_i;
local.sin_family = AF_INET;
@@ -651,8 +644,10 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
sizeof(local));
} while (ret && try_port > (1024 / 2));
- if (ret)
+ if (ret) {
+ fput(file);
return 0;
+ }
server.sin_family = AF_INET;
server.sin_addr = addr->sin_addr;
@@ -661,6 +656,7 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
/* Call sys_connect */
ret = socket->ops->connect (socket, (struct sockaddr *) &server,
sizeof (server), file->f_flags);
+ fput(file);
if (ret < 0)
return 0;
return 1;
@@ -676,12 +672,12 @@ static int get_default (int value, int def_value)
}
/* XXXXXXXXXXXXXXXXXXXX */
-asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
+static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
{
int server_fd;
char *the_name;
struct nfs_mount_data linux_nfs_mount;
- struct sunos_nfs_mount_args *sunos_mount = data;
+ struct sunos_nfs_mount_args sunos_mount;
/* Ok, here comes the fun part: Linux's nfs mount needs a
* socket connection to the server, but SunOS mount does not
@@ -689,41 +685,50 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
* address to create a socket and bind it to a reserved
* port on this system
*/
+ if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))
+ return -EFAULT;
+
server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (server_fd < 0)
return -ENXIO;
- if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){
+ if (copy_from_user(&linux_nfs_mount.addr,sunos_mount.addr,
+ sizeof(*sunos_mount.addr)) ||
+ copy_from_user(&linux_nfs_mount.root,sunos_mount.fh,
+ sizeof(*sunos_mount.fh))) {
+ sys_close (server_fd);
+ return -EFAULT;
+ }
+
+ if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){
sys_close (server_fd);
return -ENXIO;
}
/* Now, bind it to a locally reserved port */
linux_nfs_mount.version = NFS_MOUNT_VERSION;
- linux_nfs_mount.flags = sunos_mount->flags;
- linux_nfs_mount.addr = *sunos_mount->addr;
- linux_nfs_mount.root = *sunos_mount->fh;
+ linux_nfs_mount.flags = sunos_mount.flags;
linux_nfs_mount.fd = server_fd;
- linux_nfs_mount.rsize = get_default (sunos_mount->rsize, 8192);
- linux_nfs_mount.wsize = get_default (sunos_mount->wsize, 8192);
- linux_nfs_mount.timeo = get_default (sunos_mount->timeo, 10);
- linux_nfs_mount.retrans = sunos_mount->retrans;
+ linux_nfs_mount.rsize = get_default (sunos_mount.rsize, 8192);
+ linux_nfs_mount.wsize = get_default (sunos_mount.wsize, 8192);
+ linux_nfs_mount.timeo = get_default (sunos_mount.timeo, 10);
+ linux_nfs_mount.retrans = sunos_mount.retrans;
- linux_nfs_mount.acregmin = sunos_mount->acregmin;
- linux_nfs_mount.acregmax = sunos_mount->acregmax;
- linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
- linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
+ linux_nfs_mount.acregmin = sunos_mount.acregmin;
+ linux_nfs_mount.acregmax = sunos_mount.acregmax;
+ linux_nfs_mount.acdirmin = sunos_mount.acdirmin;
+ linux_nfs_mount.acdirmax = sunos_mount.acdirmax;
- the_name = getname(sunos_mount->hostname);
+ the_name = getname(sunos_mount.hostname);
if(IS_ERR(the_name))
- return -EFAULT;
+ return PTR_ERR(the_name);
strncpy (linux_nfs_mount.hostname, the_name, 254);
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
-
- return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
+
+ return do_sys_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount);
}
/* XXXXXXXXXXXXXXXXXXXX */
@@ -733,6 +738,7 @@ sunos_mount(char *type, char *dir, int flags, void *data)
int linux_flags = MS_MGC_MSK; /* new semantics */
int ret = -EINVAL;
char *dev_fname = 0;
+ char *dir_page, *type_page;
if (!capable (CAP_SYS_ADMIN))
return -EPERM;
@@ -751,24 +757,44 @@ sunos_mount(char *type, char *dir, int flags, void *data)
linux_flags |= MS_RDONLY;
if(flags & SMNT_NOSUID)
linux_flags |= MS_NOSUID;
- if(strcmp(type, "ext2") == 0) {
- dev_fname = (char *) data;
- } else if(strcmp(type, "iso9660") == 0) {
- dev_fname = (char *) data;
- } else if(strcmp(type, "minix") == 0) {
- dev_fname = (char *) data;
- } else if(strcmp(type, "nfs") == 0) {
- ret = sunos_nfs_mount (dir, flags, data);
+
+ dir_page = getname(dir);
+ ret = PTR_ERR(dir_page);
+ if (IS_ERR(dir_page))
goto out;
- } else if(strcmp(type, "ufs") == 0) {
+
+ type_page = getname(type);
+ ret = PTR_ERR(type_page);
+ if (IS_ERR(type_page))
+ goto out1;
+
+ if(strcmp(type_page, "ext2") == 0) {
+ dev_fname = getname(data);
+ } else if(strcmp(type_page, "iso9660") == 0) {
+ dev_fname = getname(data);
+ } else if(strcmp(type_page, "minix") == 0) {
+ dev_fname = getname(data);
+ } else if(strcmp(type_page, "nfs") == 0) {
+ ret = sunos_nfs_mount (dir_page, flags, data);
+ goto out2
+ } else if(strcmp(type_page, "ufs") == 0) {
printk("Warning: UFS filesystem mounts unsupported.\n");
ret = -ENODEV;
- goto out;
- } else if(strcmp(type, "proc")) {
+ goto out2
+ } else if(strcmp(type_page, "proc")) {
ret = -ENODEV;
- goto out;
+ goto out2
}
- ret = sys_mount(dev_fname, dir, type, linux_flags, NULL);
+ ret = PTR_ERR(dev_fname);
+ if (IS_ERR(dev_fname))
+ goto out2;
+ ret = do_sys_mount(dev_fname, dir_page, type_page, linux_flags, NULL);
+ if (dev_fname)
+ putname(dev_fname);
+out2:
+ putname(type_page);
+out1:
+ putname(dir_page);
out:
unlock_kernel();
return ret;
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index 67653fef1..d733de2c1 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.28 1999/07/30 09:35:34 davem Exp $
+/* $Id: winfixup.S,v 1.29 2000/03/26 09:13:48 davem Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
@@ -31,7 +31,7 @@
fill_fixup:
rdpr %tstate, %g1
andcc %g1, TSTATE_PRIV, %g0
- clr %g4
+ or %g4, FAULT_CODE_WINFIXUP, %g4
be,pt %xcc, window_scheisse_from_user_common
and %g1, TSTATE_CWP, %g1
@@ -69,21 +69,20 @@ fill_fixup:
mov %g6, %o7 ! Get current.
andn %l1, PSTATE_MM, %l1 ! We want to be in RMO
- srlx %g5, PAGE_SHIFT, %o1 ! Fault address
+ stb %g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
+ stx %g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
wrpr %g0, 0x0, %tl ! Out of trap levels.
wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
sethi %uhi(PAGE_OFFSET), %g4 ! Prepare page_offset global reg
mov %o7, %g6
sllx %g4, 32, %g4 ! and finish it...
- clr %o2
/* This is the same as below, except we handle this a bit special
* since we must preserve %l5 and %l6, see comment above.
*/
- sllx %o1, PAGE_SHIFT, %o1
call do_sparc64_fault
add %sp, STACK_BIAS + REGWIN_SZ, %o0
- b,pt %xcc, rtrap
+ ba,pt %xcc, rtrap
nop ! yes, nop is correct
/* Be very careful about usage of the alternate globals here.
@@ -149,22 +148,19 @@ spill_fixup:
andcc %g1, TSTATE_PRIV, %g0
saved
and %g1, TSTATE_CWP, %g1
- be,a,pn %xcc, window_scheisse_from_user_common
- or %g4, 0x4, %g4 ! we know it was a write
+ be,pn %xcc, window_scheisse_from_user_common
+ mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4
retry
+
window_scheisse_from_user_common:
+ stb %g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
+ stx %g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
wrpr %g1, %cwp
- sethi %hi(109f), %g7
ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- srlx %l5, PAGE_SHIFT, %o1
-
- and %l4, 0x4, %o2
- sllx %o1, PAGE_SHIFT, %o1
+ rd %pc, %g7
call do_sparc64_fault
add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ba,pt %xcc, rtrap
- clr %l6
+ ba,a,pt %xcc, rtrap_clr_l6
.globl winfix_mna, fill_fixup_mna, spill_fixup_mna
winfix_mna:
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index f3067cad6..e70e28e52 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.20 2000/01/19 04:06:03 davem Exp $
+# $Id: Makefile,v 1.21 2000/03/27 10:38:41 davem Exp $
# Makefile for Sparc library files..
#
@@ -7,7 +7,7 @@ CFLAGS := $(CFLAGS)
OBJS = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \
- VIScsumcopyusr.o VISsave.o atomic.o rwlock.o
+ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
@@ -17,10 +17,10 @@ VIScopy.o: VIScopy.S VIS.h
VISbzero.o: VISbzero.S VIS.h
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+ $(CPP) $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $< -o $*.o
dep:
diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
index e20118648..56634f83f 100644
--- a/arch/sparc64/lib/VIScopy.S
+++ b/arch/sparc64/lib/VIScopy.S
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.22 2000/03/16 16:44:38 davem Exp $
+/* $Id: VIScopy.S,v 1.23 2000/03/26 09:13:49 davem Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -135,11 +135,11 @@
#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \
EXVIS(LDBLK [%src] ASIBLK, %fdest); \
ASI_SETDST_BLK \
+ EXVIS2(STBLK %fsrc, [%dest] ASIBLK); \
add %src, 0x40, %src; \
- add %dest, 0x40, %dest; \
subcc %len, 0x40, %len; \
be,pn %xcc, jmptgt; \
- EXVIS2(STBLK %fsrc, [%dest - 0x40] ASIBLK); \
+ add %dest, 0x40, %dest; \
ASI_SETSRC_BLK
#define LOOP_CHUNK1(src, dest, len, branch_dest) \
diff --git a/arch/sparc64/lib/bitops.S b/arch/sparc64/lib/bitops.S
new file mode 100644
index 000000000..f964e4550
--- /dev/null
+++ b/arch/sparc64/lib/bitops.S
@@ -0,0 +1,110 @@
+/* $Id: bitops.S,v 1.1 2000/03/27 10:38:41 davem Exp $
+ * bitops.S: Sparc64 atomic bit operations.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/asi.h>
+
+ .text
+ .align 64
+ .globl __bitops_begin
+__bitops_begin:
+
+ .globl __test_and_set_bit
+__test_and_set_bit: /* %o0=nr, %o1=addr */
+ srlx %o0, 6, %g1
+ mov 1, %g5
+ sllx %g1, 3, %g3
+ and %o0, 63, %g2
+ sllx %g5, %g2, %g5
+ add %o1, %g3, %o1
+ ldx [%o1], %g7
+1: andcc %g7, %g5, %o0
+ bne,pn %xcc, 2f
+ xor %g7, %g5, %g1
+ casx [%o1], %g7, %g1
+ cmp %g7, %g1
+ bne,a,pn %xcc, 1b
+ ldx [%o1], %g7
+2: retl
+ nop
+
+ .globl __test_and_clear_bit
+__test_and_clear_bit: /* %o0=nr, %o1=addr */
+ srlx %o0, 6, %g1
+ mov 1, %g5
+ sllx %g1, 3, %g3
+ and %o0, 63, %g2
+ sllx %g5, %g2, %g5
+ add %o1, %g3, %o1
+ ldx [%o1], %g7
+1: andcc %g7, %g5, %o0
+ be,pn %xcc, 2f
+ xor %g7, %g5, %g1
+ casx [%o1], %g7, %g1
+ cmp %g7, %g1
+ bne,a,pn %xcc, 1b
+ ldx [%o1], %g7
+2: retl
+ nop
+
+ .globl __test_and_change_bit
+__test_and_change_bit: /* %o0=nr, %o1=addr */
+ srlx %o0, 6, %g1
+ mov 1, %g5
+ sllx %g1, 3, %g3
+ and %o0, 63, %g2
+ sllx %g5, %g2, %g5
+ add %o1, %g3, %o1
+ ldx [%o1], %g7
+1: and %g7, %g5, %o0
+ xor %g7, %g5, %g1
+ casx [%o1], %g7, %g1
+ cmp %g7, %g1
+ bne,a,pn %xcc, 1b
+ ldx [%o1], %g7
+2: retl
+ nop
+ nop
+
+ .globl __test_and_set_le_bit
+__test_and_set_le_bit: /* %o0=nr, %o1=addr */
+ srlx %o0, 5, %g1
+ mov 1, %g5
+ sllx %g1, 2, %g3
+ and %o0, 31, %g2
+ sllx %g5, %g2, %g5
+ add %o1, %g3, %o1
+ lduwa [%o1] ASI_PL, %g7
+1: andcc %g7, %g5, %o0
+ bne,pn %icc, 2f
+ xor %g7, %g5, %g1
+ casa [%o1] ASI_PL, %g7, %g1
+ cmp %g7, %g1
+ bne,a,pn %icc, 1b
+ lduwa [%o1] ASI_PL, %g7
+2: retl
+ nop
+
+ .globl __test_and_clear_le_bit
+__test_and_clear_le_bit: /* %o0=nr, %o1=addr */
+ srlx %o0, 5, %g1
+ mov 1, %g5
+ sllx %g1, 2, %g3
+ and %o0, 31, %g2
+ sllx %g5, %g2, %g5
+ add %o1, %g3, %o1
+ lduwa [%o1] ASI_PL, %g7
+1: andcc %g7, %g5, %o0
+ be,pn %icc, 2f
+ xor %g7, %g5, %g1
+ casa [%o1] ASI_PL, %g7, %g1
+ cmp %g7, %g1
+ bne,a,pn %icc, 1b
+ lduwa [%o1] ASI_PL, %g7
+2: retl
+ nop
+
+ .globl __bitops_end
+__bitops_end:
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index b4a91b97c..9c6a8beba 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.22 2000/03/15 07:18:55 davem Exp $
+/* $Id: blockops.S,v 1.24 2000/03/27 10:38:41 davem Exp $
* blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
@@ -38,21 +38,21 @@ copy_page: /* %o0=dest, %o1=src */
sethi %hi(8192), %o2
1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
ldda [%o1] ASI_BLK_P, %f32
+ stda %f48, [%o0] ASI_BLK_P
add %o1, 0x40, %o1
sub %o2, 0x40, %o2
- stda %f48, [%o0] ASI_BLK_P
add %o0, 0x40, %o0
TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
ldda [%o1] ASI_BLK_P, %f0
+ stda %f48, [%o0] ASI_BLK_P
add %o1, 0x40, %o1
sub %o2, 0x40, %o2
- stda %f48, [%o0] ASI_BLK_P
add %o0, 0x40, %o0
TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
ldda [%o1] ASI_BLK_P, %f16
- add %o1, 0x40, %o1
- sub %o2, 0x40, %o2
stda %f48, [%o0] ASI_BLK_P
+ sub %o2, 0x40, %o2
+ add %o1, 0x40, %o1
cmp %o2, 0x80
bne,pt %xcc, 1b
add %o0, 0x40, %o0
@@ -122,7 +122,11 @@ copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS
membar #Sync
- membar #LoadStore | #StoreStore | #StoreLoad
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_use_blkcommit], %g2
+ cmp %g2, 0
+ bne,pn %xcc, copy_page_using_blkcommit
+ nop
+
ldda [%o1] ASI_BLK_P, %f0
add %o1, 0x40, %o1
ldda [%o1] ASI_BLK_P, %f16
@@ -130,21 +134,21 @@ copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
sethi %hi(8192), %o2
1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
ldda [%o1] ASI_BLK_P, %f32
+ stda %f48, [%o0] ASI_BLK_P
add %o1, 0x40, %o1
sub %o2, 0x40, %o2
- stda %f48, [%o0] ASI_BLK_P
add %o0, 0x40, %o0
TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
ldda [%o1] ASI_BLK_P, %f0
+ stda %f48, [%o0] ASI_BLK_P
add %o1, 0x40, %o1
sub %o2, 0x40, %o2
- stda %f48, [%o0] ASI_BLK_P
add %o0, 0x40, %o0
TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
ldda [%o1] ASI_BLK_P, %f16
- add %o1, 0x40, %o1
- sub %o2, 0x40, %o2
stda %f48, [%o0] ASI_BLK_P
+ sub %o2, 0x40, %o2
+ add %o1, 0x40, %o1
cmp %o2, 0x80
bne,pt %xcc, 1b
add %o0, 0x40, %o0
@@ -152,6 +156,7 @@ copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
stda %f0, [%o0] ASI_BLK_P
add %o0, 0x40, %o0
stda %f16, [%o0] ASI_BLK_P
+copy_user_page_continue:
membar #Sync
VISExit
@@ -166,6 +171,39 @@ copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
jmpl %o7 + 0x8, %g0
wrpr %g3, 0x0, %pstate
+copy_page_using_blkcommit:
+ membar #LoadStore | #StoreStore | #StoreLoad
+ ldda [%o1] ASI_BLK_P, %f0
+ add %o1, 0x40, %o1
+ ldda [%o1] ASI_BLK_P, %f16
+ add %o1, 0x40, %o1
+ sethi %hi(8192), %o2
+1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
+ ldda [%o1] ASI_BLK_P, %f32
+ stda %f48, [%o0] ASI_BLK_COMMIT_P
+ add %o1, 0x40, %o1
+ sub %o2, 0x40, %o2
+ add %o0, 0x40, %o0
+ TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
+ ldda [%o1] ASI_BLK_P, %f0
+ stda %f48, [%o0] ASI_BLK_COMMIT_P
+ add %o1, 0x40, %o1
+ sub %o2, 0x40, %o2
+ add %o0, 0x40, %o0
+ TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
+ ldda [%o1] ASI_BLK_P, %f16
+ stda %f48, [%o0] ASI_BLK_COMMIT_P
+ sub %o2, 0x40, %o2
+ add %o1, 0x40, %o1
+ cmp %o2, 0x80
+ bne,pt %xcc, 1b
+ add %o0, 0x40, %o0
+ membar #Sync
+ stda %f0, [%o0] ASI_BLK_COMMIT_P
+ add %o0, 0x40, %o0
+ ba,pt %xcc, copy_user_page_continue
+ stda %f16, [%o0] ASI_BLK_COMMIT_P
+
.align 32
.globl clear_page
.type clear_page,@function
@@ -213,6 +251,7 @@ clear_user_page: /* %o0=dest, %o1=vaddr */
mov 1, %o4
clear_page_common:
+ membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
fzero %f0 ! FPA Group
mov 32, %o1 ! IEU0
fzero %f2 ! FPA Group
@@ -223,7 +262,6 @@ clear_page_common:
faddd %f0, %f2, %f12 ! FPA Group
fmuld %f0, %f2, %f14 ! FPM
- membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
1: stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group
add %o0, 0x40, %o0 ! IEU0
stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group
diff --git a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile
index d97c47778..039195944 100644
--- a/arch/sparc64/mm/Makefile
+++ b/arch/sparc64/mm/Makefile
@@ -8,10 +8,10 @@
# Note 2! The CFLAGS definition is now in the main makefile...
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+ $(CPP) $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $< -o $*.o
O_TARGET := mm.o
O_OBJS := ultra.o fault.o init.o generic.o extable.o modutil.o
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 6063d002e..0d8152887 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.43 2000/03/14 03:59:46 davem Exp $
+/* $Id: fault.c,v 1.45 2000/03/27 10:38:51 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -92,162 +92,211 @@ void unhandled_fault(unsigned long address, struct task_struct *tsk,
die_if_kernel("Oops", regs);
}
-/* #define DEBUG_EXCEPTIONS */
-/* #define DEBUG_LOCKUPS */
-
-/* #define INSN_VPTE_LOOKUP */
-
-static inline u32 get_user_insn(unsigned long tpc)
+static unsigned int get_user_insn(unsigned long tpc)
{
- u32 insn;
-#ifndef INSN_VPTE_LOOKUP
pgd_t *pgdp = pgd_offset(current->mm, tpc);
pmd_t *pmdp;
- pte_t *ptep;
+ pte_t *ptep, pte;
+ unsigned long pa;
+ u32 insn = 0;
if(pgd_none(*pgdp))
- return 0;
+ goto out;
pmdp = pmd_offset(pgdp, tpc);
if(pmd_none(*pmdp))
- return 0;
+ goto out;
ptep = pte_offset(pmdp, tpc);
- if(!pte_present(*ptep))
- return 0;
- insn = *(unsigned int *)
- ((unsigned long)__va(pte_pagenr(*ptep) << PAGE_SHIFT) +
- (tpc & ~PAGE_MASK));
-#else
- register unsigned long pte asm("l1");
-
- /* So that we don't pollute TLB, we read the instruction
- * using PHYS bypass. For that, we of course need
- * to know its page table entry. Do this by simulating
- * dtlb_miss handler. -jj */
- pte = ((((long)tpc) >> (PAGE_SHIFT-3)) & ~7);
- asm volatile ("
- rdpr %%pstate, %%l0
- wrpr %%l0, %2, %%pstate
- wrpr %%g0, 1, %%tl
- mov %%l1, %%g6
- ldxa [%%g3 + %%l1] %3, %%g5
- mov %%g5, %%l1
- wrpr %%g0, 0, %%tl
- wrpr %%l0, 0, %%pstate
- " : "=r" (pte) : "0" (pte), "i" (PSTATE_MG|PSTATE_IE), "i" (ASI_S) : "l0");
-
- if ((long)pte >= 0) return 0;
-
- pte = (pte & _PAGE_PADDR) + (tpc & ~PAGE_MASK);
- asm ("lduwa [%1] %2, %0" : "=r" (insn) : "r" (pte), "i" (ASI_PHYS_USE_EC));
-#endif
+ pte = *ptep;
+ if(!pte_present(pte))
+ goto out;
+
+ pa = (pte_pagenr(pte) << PAGE_SHIFT) + (tpc & ~PAGE_MASK);
+ /* Use phys bypass so we don't pollute dtlb/dcache. */
+ __asm__ __volatile__("lduwa [%1] %2, %0"
+ : "=r" (insn)
+ : "r" (pa), "i" (ASI_PHYS_USE_EC));
+
+out:
return insn;
}
-asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, int write)
+static void do_fault_siginfo(int code, int sig, unsigned long address)
+{
+ siginfo_t info;
+
+ info.si_code = code;
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_addr = (void *) address;
+ info.si_trapno = 0;
+ force_sig_info(sig, &info, current);
+}
+
+extern int handle_ldf_stq(u32, struct pt_regs *);
+extern int handle_ld_nf(u32, struct pt_regs *);
+
+static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
+ unsigned int insn, unsigned long address)
+{
+ unsigned long g2;
+ unsigned char asi = ASI_P;
+
+ if (!insn) {
+ if (regs->tstate & TSTATE_PRIV) {
+ if (regs->tpc & 0x3)
+ goto cannot_handle;
+ insn = *(unsigned int *)regs->tpc;
+ } else {
+ insn = get_user_insn(regs->tpc);
+ }
+ }
+
+ /* If user insn could be read (thus insn is zero), that
+ * is fine. We will just gun down the process with a signal
+ * in that case.
+ */
+
+ if (!(fault_code & FAULT_CODE_WRITE) &&
+ (insn & 0xc0800000) == 0xc0800000) {
+ if (insn & 0x2000)
+ asi = (regs->tstate >> 24);
+ else
+ asi = (insn >> 5);
+ if ((asi & 0xf2) == 0x82) {
+ if (insn & 0x1000000) {
+ handle_ldf_stq(insn, regs);
+ } else {
+ /* This was a non-faulting load. Just clear the
+ * destination register(s) and continue with the next
+ * instruction. -jj
+ */
+ handle_ld_nf(insn, regs);
+ }
+ return;
+ }
+ }
+
+ g2 = regs->u_regs[UREG_G2];
+
+ /* Is this in ex_table? */
+ if (regs->tstate & TSTATE_PRIV) {
+ unsigned long fixup;
+
+ if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
+ if (insn & 0x2000)
+ asi = (regs->tstate >> 24);
+ else
+ asi = (insn >> 5);
+ }
+
+ /* Look in asi.h: All _S asis have LS bit set */
+ if ((asi & 0x1) &&
+ (fixup = search_exception_table (regs->tpc, &g2))) {
+ regs->tpc = fixup;
+ regs->tnpc = regs->tpc + 4;
+ regs->u_regs[UREG_G2] = g2;
+ return;
+ }
+ } else {
+ /* The si_code was set to make clear whether
+ * this was a SEGV_MAPERR or SEGV_ACCERR fault.
+ */
+ do_fault_siginfo(si_code, SIGSEGV, address);
+ return;
+ }
+
+cannot_handle:
+ unhandled_fault (address, current, regs);
+}
+
+asmlinkage void do_sparc64_fault(struct pt_regs *regs)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned int insn = 0;
- siginfo_t info;
-#ifdef DEBUG_LOCKUPS
- static unsigned long lastaddr, lastpc;
- static int lastwrite, lockcnt;
-#endif
+ int si_code, fault_code;
+ unsigned long address;
+
+ si_code = SEGV_MAPERR;
+ fault_code = current->thread.fault_code;
+ address = current->thread.fault_address;
+
+ if ((fault_code & FAULT_CODE_ITLB) &&
+ (fault_code & FAULT_CODE_DTLB))
+ BUG();
- info.si_code = SEGV_MAPERR;
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
if (in_interrupt() || !mm)
- goto do_kernel_fault;
+ goto handle_kernel_fault;
down(&mm->mmap_sem);
-#ifdef DEBUG_LOCKUPS
- if (regs->tpc == lastpc &&
- address == lastaddr &&
- write == lastwrite) {
- lockcnt++;
- if (lockcnt == 100000) {
- unsigned char tmp;
- register unsigned long tmp1 asm("o5");
- register unsigned long tmp2 asm("o4");
-
- printk("do_sparc64_fault[%s:%d]: possible fault loop for %016lx %s\n",
- current->comm, current->pid,
- address, write ? "write" : "read");
- printk("do_sparc64_fault: CHECK[papgd[%016lx],pcac[%016lx]]\n",
- __pa(mm->pgd), pgd_val(mm->pgd[0])<<11UL);
- __asm__ __volatile__(
- "wrpr %%g0, 0x494, %%pstate\n\t"
- "mov %3, %%g4\n\t"
- "mov %%g7, %0\n\t"
- "ldxa [%%g4] %2, %1\n\t"
- "wrpr %%g0, 0x096, %%pstate"
- : "=r" (tmp1), "=r" (tmp2)
- : "i" (ASI_DMMU), "i" (TSB_REG));
- printk("do_sparc64_fault: IS[papgd[%016lx],pcac[%016lx]]\n",
- tmp1, tmp2);
- printk("do_sparc64_fault: CHECK[ctx(%016lx)] IS[ctx(%016lx)]\n",
- mm->context, spitfire_get_secondary_context());
- __asm__ __volatile__("rd %%asi, %0"
- : "=r" (tmp));
- printk("do_sparc64_fault: CHECK[seg(%02x)] IS[seg(%02x)]\n",
- current->thread.current_ds.seg, tmp);
- show_regs(regs);
- __sti();
- while(1)
- barrier();
- }
- } else {
- lastpc = regs->tpc;
- lastaddr = address;
- lastwrite = write;
- lockcnt = 0;
- }
-#endif
vma = find_vma(mm, address);
- if(!vma)
+ if (!vma)
goto bad_area;
-#ifndef INSN_VPTE_LOOKUP
- write &= 0xf;
-#else
- if (write & 0x10) {
- write = 0;
- if((vma->vm_flags & VM_WRITE)) {
- if (regs->tstate & TSTATE_PRIV)
- insn = *(unsigned int *)regs->tpc;
- else
- insn = get_user_insn(regs->tpc);
- if ((insn & 0xc0200000) == 0xc0200000 && (insn & 0x1780000) != 0x1680000)
- write = 1;
+
+ /* Pure DTLB misses do not tell us whether the fault causing
+ * load/store/atomic was a write or not, it only says that there
+ * was no match. So in such a case we (carefully) read the
+ * instruction to try and figure this out. It's an optimization
+ * so it's ok if we can't do this.
+ *
+ * Special hack, window spill/fill knows the exact fault type.
+ */
+ if (((fault_code &
+ (FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) &&
+ (vma->vm_flags & VM_WRITE) != 0) {
+ unsigned long tpc = regs->tpc;
+
+ if (tpc & 0x3)
+ goto continue_fault;
+
+ if (regs->tstate & TSTATE_PRIV)
+ insn = *(unsigned int *)tpc;
+ else
+ insn = get_user_insn(tpc);
+
+ if ((insn & 0xc0200000) == 0xc0200000 &&
+ (insn & 0x1780000) != 0x1680000) {
+ /* Don't bother updating thread struct value,
+ * because update_mmu_cache only cares which tlb
+ * the access came from.
+ */
+ fault_code |= FAULT_CODE_WRITE;
}
}
-#endif
- if(vma->vm_start <= address)
+continue_fault:
+
+ if (vma->vm_start <= address)
goto good_area;
- if(!(vma->vm_flags & VM_GROWSDOWN))
+ if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- if(expand_stack(vma, address))
+ if (expand_stack(vma, address))
goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
- info.si_code = SEGV_ACCERR;
- if(write) {
- if(!(vma->vm_flags & VM_WRITE))
+ si_code = SEGV_ACCERR;
+ if (fault_code & FAULT_CODE_WRITE) {
+ if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
+ if ((vma->vm_flags & VM_EXEC) != 0 &&
+ vma->vm_file != NULL)
+ current->thread.use_blkcommit = 1;
} else {
/* Allow reads even for write-only mappings */
- if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
{
- int fault = handle_mm_fault(current, vma, address, write);
+ int fault = handle_mm_fault(current, vma,
+ address, (fault_code & FAULT_CODE_WRITE));
if (fault < 0)
goto out_of_memory;
@@ -255,7 +304,8 @@ good_area:
goto do_sigbus;
}
up(&mm->mmap_sem);
- return;
+ goto fault_done;
+
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
@@ -263,89 +313,10 @@ good_area:
bad_area:
up(&mm->mmap_sem);
-do_kernel_fault:
- {
- unsigned long g2;
- unsigned char asi = ASI_P;
-
- if (!insn) {
- if (regs->tstate & TSTATE_PRIV)
- insn = *(unsigned int *)regs->tpc;
- else
- insn = get_user_insn(regs->tpc);
- }
- if (write != 1 && (insn & 0xc0800000) == 0xc0800000) {
- if (insn & 0x2000)
- asi = (regs->tstate >> 24);
- else
- asi = (insn >> 5);
- if ((asi & 0xf2) == 0x82) {
- /* This was a non-faulting load. Just clear the
- destination register(s) and continue with the next
- instruction. -jj */
- if (insn & 0x1000000) {
- extern int handle_ldf_stq(u32, struct pt_regs *);
-
- handle_ldf_stq(insn, regs);
- } else {
- extern int handle_ld_nf(u32, struct pt_regs *);
-
- handle_ld_nf(insn, regs);
- }
- return;
- }
- }
-
- g2 = regs->u_regs[UREG_G2];
-
- /* Is this in ex_table? */
- if (regs->tstate & TSTATE_PRIV) {
- unsigned long fixup;
+handle_kernel_fault:
+ do_kernel_fault(regs, si_code, fault_code, insn, address);
- if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
- if (insn & 0x2000)
- asi = (regs->tstate >> 24);
- else
- asi = (insn >> 5);
- }
-
- /* Look in asi.h: All _S asis have LS bit set */
- if ((asi & 0x1) &&
- (fixup = search_exception_table (regs->tpc, &g2))) {
-#ifdef DEBUG_EXCEPTIONS
- printk("Exception: PC<%016lx> faddr<%016lx>\n",
- regs->tpc, address);
- printk("EX_TABLE: insn<%016lx> fixup<%016lx> "
- "g2<%016lx>\n", regs->tpc, fixup, g2);
-#endif
- regs->tpc = fixup;
- regs->tnpc = regs->tpc + 4;
- regs->u_regs[UREG_G2] = g2;
- return;
- }
- } else {
-#if 0
- extern void __show_regs(struct pt_regs *);
- printk("SHIT(%s:%d:cpu(%d)): PC[%016lx] ADDR[%016lx]\n",
- current->comm, current->pid, smp_processor_id(),
- regs->tpc, address);
- __show_regs(regs);
- __sti();
- while(1)
- barrier();
-#endif
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* info.si_code set above to make clear whether
- this was a SEGV_MAPERR or SEGV_ACCERR fault. */
- info.si_addr = (void *)address;
- info.si_trapno = 0;
- force_sig_info (SIGSEGV, &info, current);
- return;
- }
- unhandled_fault (address, current, regs);
- }
- return;
+ goto fault_done;
/*
* We ran out of memory, or some other thing happened to us that made
@@ -356,7 +327,7 @@ out_of_memory:
printk("VM: killing process %s\n", current->comm);
if (!(regs->tstate & TSTATE_PRIV))
do_exit(SIGKILL);
- goto do_kernel_fault;
+ goto handle_kernel_fault;
do_sigbus:
up(&mm->mmap_sem);
@@ -365,14 +336,15 @@ do_sigbus:
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRERR;
- info.si_addr = (void *)address;
- info.si_trapno = 0;
- force_sig_info (SIGBUS, &info, current);
+ do_fault_siginfo(BUS_ADRERR, SIGBUS, address);
/* Kernel mode? Handle exceptions or die */
if (regs->tstate & TSTATE_PRIV)
- goto do_kernel_fault;
+ goto handle_kernel_fault;
+
+fault_done:
+ /* These values are no longer needed, clear them. */
+ current->thread.fault_code = 0;
+ current->thread.use_blkcommit = 0;
+ current->thread.fault_address = 0;
}
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 210db79e6..1c3714e5b 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,11 +1,12 @@
-/* $Id: ultra.S,v 1.38 2000/03/03 23:48:44 davem Exp $
+/* $Id: ultra.S,v 1.41 2000/03/27 10:38:51 davem Exp $
* ultra.S: Don't expand these all over the place...
*
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
*/
#include <asm/asi.h>
#include <asm/pgtable.h>
+#include <asm/page.h>
#include <asm/spitfire.h>
/* This file is meant to be read efficiently by the CPU, not humans.
@@ -160,35 +161,87 @@ __flush_icache_page: /* %o0 = phys_page */
srlx %o0, 5, %o0
clr %o1 ! IC_addr
sllx %g1, 36, %g1
+ ldda [%o1] ASI_IC_TAG, %o4
sub %g1, 1, %g2
or %o0, %g1, %o0 ! VALID+phys-addr comparitor
- sllx %g2, 1, %g2
+ sllx %g2, 1, %g2
andn %g2, 0xfe, %g2 ! IC_tag mask
-1: ldda [%o1] ASI_IC_TAG, %o4
- and %o5, %g2, %o5
- cmp %o5, %o0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+1: addx %g0, %g0, %g0
+ ldda [%o1 + %o2] ASI_IC_TAG, %g4
+ addx %g0, %g0, %g0
+ and %o5, %g2, %g3
+ cmp %g3, %o0
+ add %o1, 0x20, %o1
+ ldda [%o1] ASI_IC_TAG, %o4
be,pn %xcc, iflush1
- add %o1, 0x20, %g3
-2: ldda [%o1 + %o2] ASI_IC_TAG, %o4
- and %o5, %g2, %o5
- cmp %o5, %o0
+2: nop
+ and %g5, %g2, %g5
+ cmp %g5, %o0
be,pn %xcc, iflush2
- nop
-3: cmp %g3, %o2
+3: cmp %o1, %o2
bne,pt %xcc, 1b
- mov %g3, %o1
+ addx %g0, %g0, %g0
+ nop
+
+ sethi %uhi(PAGE_OFFSET), %g4
retl
- nop
+ sllx %g4, 32, %g4
-iflush1:stxa %g0, [%o1] ASI_IC_TAG
+iflush1:sub %o1, 0x20, %g3
+ stxa %g0, [%g3] ASI_IC_TAG
flush %g6
ba,a,pt %xcc, 2b
-iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG
+iflush2:sub %o1, 0x20, %g3
+ stxa %g0, [%o1 + %o2] ASI_IC_TAG
flush %g6
ba,a,pt %xcc, 3b
+ .align 32
+__prefill_dtlb:
+ rdpr %pstate, %g7
+ wrpr %g7, PSTATE_IE, %pstate
+ mov TLB_TAG_ACCESS, %g1
+ stxa %o0, [%g1] ASI_DMMU
+ stxa %o1, [%g0] ASI_DTLB_DATA_IN
+ flush %g6
+ retl
+ wrpr %g7, %pstate
+__prefill_itlb:
+ rdpr %pstate, %g7
+ wrpr %g7, PSTATE_IE, %pstate
+ mov TLB_TAG_ACCESS, %g1
+ stxa %o0, [%g1] ASI_IMMU
+ stxa %o1, [%g0] ASI_ITLB_DATA_IN
+ flush %g6
+ retl
+ wrpr %g7, %pstate
+
+ .globl update_mmu_cache
+update_mmu_cache: /* %o0=vma, %o1=address, %o2=pte */
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_fault_code], %o3
+ srlx %o1, 13, %o1
+ ldx [%o0 + 0x0], %o4 /* XXX vma->vm_mm */
+ brz,pn %o3, 1f
+ sllx %o1, 13, %o0
+ ldx [%o4 + AOFF_mm_context], %o5
+ andcc %o3, FAULT_CODE_DTLB, %g0
+ mov %o2, %o1
+ and %o5, 0x3ff, %o5
+ bne,pt %xcc, __prefill_dtlb
+ or %o0, %o5, %o0
+ ba,a,pt %xcc, __prefill_itlb
+1: retl
+ nop
+
#ifdef __SMP__
/* These are all called by the slaves of a cross call, at
* trap level 1, with interrupts fully disabled.
diff --git a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile
index 42906da28..88ca5251b 100644
--- a/arch/sparc64/prom/Makefile
+++ b/arch/sparc64/prom/Makefile
@@ -18,10 +18,10 @@ promlib.a: $(OBJS)
sync
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+ $(CPP) $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+ $(CC) $(AFLAGS) -ansi -c $< -o $*.o
dep:
$(CPP) $(CPPFLAGS) -M *.c > .depend
diff --git a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile
index 5e5a6aff8..51598f727 100644
--- a/arch/sparc64/solaris/Makefile
+++ b/arch/sparc64/solaris/Makefile
@@ -15,10 +15,10 @@ CPPFLAGS = $(MODFLAGS)
endif
.S.s:
- $(CPP) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
+ $(CPP) $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
+ $(CC) $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
ifneq ($(CONFIG_SOLARIS_EMUL),y)
do_it_all:
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 4adaf4077..2c17d664d 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -495,26 +495,18 @@ asmlinkage int solaris_statvfs(u32 path, u32 buf)
asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
{
- struct inode * inode;
- struct dentry * dentry;
struct file * file;
int error;
- lock_kernel();
error = -EBADF;
file = fget(fd);
- if (!file)
- goto out;
-
- if (!(dentry = file->f_dentry))
- error = -ENOENT;
- else if (!(inode = dentry->d_inode))
- error = -ENOENT;
- else
- error = report_statvfs(inode, buf);
- fput(file);
+ if (file) {
+ lock_kernel();
+ error = report_statvfs(file->f_dentry->d_inode, buf);
+ unlock_kernel();
+ fput(file);
+ }
out:
- unlock_kernel();
return error;
}
@@ -538,26 +530,17 @@ asmlinkage int solaris_statvfs64(u32 path, u32 buf)
asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf)
{
- struct inode * inode;
- struct dentry * dentry;
struct file * file;
int error;
- lock_kernel();
error = -EBADF;
file = fget(fd);
- if (!file)
- goto out;
-
- if (!(dentry = file->f_dentry))
- error = -ENOENT;
- else if (!(inode = dentry->d_inode))
- error = -ENOENT;
- else
- error = report_statvfs64(inode, buf);
- fput(file);
-out:
- unlock_kernel();
+ if (file) {
+ lock_kernel();
+ error = report_statvfs64(file->f_dentry->d_inode, buf);
+ unlock_kernel();
+ fput(file);
+ }
return error;
}
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index b77a27236..c9341b0fd 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -72,7 +72,7 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o
file = fget(fd);
if (!file)
goto out;
- if (file->f_dentry && file->f_dentry->d_inode) {
+ else {
struct inode * inode = file->f_dentry->d_inode;
if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
MINOR(inode->i_rdev) == 5) {
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index 89f771609..220e549ac 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.12 2000/02/17 05:50:11 davem Exp $
+/* $Id: socksys.c,v 1.13 2000/03/29 11:56:54 davem Exp $
* socksys.c: /dev/inet/ stuff for Solaris emulation.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/malloc.h>
+#include <linux/in.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
index 062e00218..dbdcc2e1d 100644
--- a/arch/sparc64/solaris/timod.c
+++ b/arch/sparc64/solaris/timod.c
@@ -1,4 +1,4 @@
-/* $Id: timod.c,v 1.5 1999/11/23 08:55:24 davem Exp $
+/* $Id: timod.c,v 1.6 2000/03/25 03:23:21 davem Exp $
* timod.c: timod emulation.
*
* Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
@@ -151,7 +151,7 @@ static void timod_wake_socket(unsigned int fd)
SOLD("wakeing socket");
sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;
wake_up_interruptible(&sock->wait);
- if (sock->fasync_list && !(sock->flags & SO_WAITDATA))
+ if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
SOLD("done");
}
diff --git a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c
index 306feb2e9..8d26b37b1 100644
--- a/drivers/acorn/char/keyb_ps2.c
+++ b/drivers/acorn/char/keyb_ps2.c
@@ -32,8 +32,6 @@ extern struct tasklet_struct keyboard_tasklet;
extern void kbd_reset_kdown(void);
int kbd_read_mask;
-#define IRQ_KEYBOARDRX 15
-
#define VERSION 100
#define KBD_REPORT_ERR
@@ -330,6 +328,10 @@ int __init ps2kbd_init_hw(void)
{
unsigned long flags;
+ /* Reset the keyboard state machine. */
+ outb(0, IOMD_KCTRL);
+ outb(8, IOMD_KCTRL);
+
save_flags_cli (flags);
if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
panic("Could not allocate keyboard receive IRQ!");
@@ -342,4 +344,3 @@ int __init ps2kbd_init_hw(void)
printk (KERN_INFO "PS/2 keyboard driver v%d.%02d\n", VERSION/100, VERSION%100);
return 0;
}
-
diff --git a/drivers/acorn/scsi/acornscsi.h b/drivers/acorn/scsi/acornscsi.h
index b6a7f3148..18cd873d5 100644
--- a/drivers/acorn/scsi/acornscsi.h
+++ b/drivers/acorn/scsi/acornscsi.h
@@ -1,3 +1,8 @@
+/*
+ * Acorn SCSI driver
+ *
+ * Copyright (C) 1997 Russell King
+ */
#ifndef ACORNSCSI_H
#define ACORNSCSI_H
diff --git a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c
index cc1701708..27e5b266a 100644
--- a/drivers/acorn/scsi/arxescsi.c
+++ b/drivers/acorn/scsi/arxescsi.c
@@ -1,7 +1,7 @@
/*
- * linux/arch/arm/drivers/scsi/cumana_2.c
+ * linux/arch/arm/drivers/scsi/arxescsi.c
*
- * Copyright (C) 1997,1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
@@ -13,6 +13,7 @@
* 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it.
* 11-06-1998 0.0.2 Changed to support ARXE 16-bit SCSI card, enabled writing
* by Stefan Hanske
+ * 02-04-2000 RMK 0.0.3 Updated for new error handling code.
*/
#include <linux/module.h>
@@ -54,7 +55,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 2
+#define VER_PATCH 3
static struct expansion_card *ecs[MAX_ECARDS];
@@ -308,10 +309,9 @@ const char *arxescsi_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX irq %d v%d.%d.%d scsi %s",
- host->hostt->name, host->io_port, host->irq,
- VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d", VER_MAJOR, VER_MINOR, VER_PATCH);
return string;
}
@@ -354,12 +354,7 @@ int arxescsi_proc_info(char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"ARXE 16-bit SCSI driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d\n"
- "FAS : %s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, info->info.scsi.type);
-
+ pos += fas216_print_host(&info->info, buffer + pos);
pos += fas216_print_stats(&info->info, buffer + pos);
pos += sprintf (buffer+pos, "\nAttached devices:\n");
diff --git a/drivers/acorn/scsi/arxescsi.h b/drivers/acorn/scsi/arxescsi.h
index 11dc6b6e3..dd97233ae 100644
--- a/drivers/acorn/scsi/arxescsi.h
+++ b/drivers/acorn/scsi/arxescsi.h
@@ -1,7 +1,8 @@
/*
* ARXE SCSI card driver
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-2000 Russell King
+ *
* Changes to support ARXE 16-bit SCSI card by Stefan Hanske
*/
#ifndef ARXE_SCSI_H
@@ -44,22 +45,25 @@ extern int arxescsi_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
#endif
-#define ARXEScsi { \
-proc_info: arxescsi_proc_info, \
-name: "ARXE SCSI card", \
-detect: arxescsi_detect, /* detect */ \
-release: arxescsi_release, /* release */ \
-info: arxescsi_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \
-use_clustering: DISABLE_CLUSTERING \
+#define ARXEScsi { \
+proc_info: arxescsi_proc_info, \
+name: "ARXE SCSI card", \
+detect: arxescsi_detect, \
+release: arxescsi_release, \
+info: arxescsi_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CMD_PER_LUN, \
+use_clustering: DISABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c
index 2307ae397..b812ef2d0 100644
--- a/drivers/acorn/scsi/cumana_2.c
+++ b/drivers/acorn/scsi/cumana_2.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/drivers/scsi/cumana_2.c
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* Changelog:
* 30-08-1997 RMK 0.0.0 Created, READONLY version.
@@ -10,6 +10,7 @@
* 02-05-1998 RMK 0.0.2 Updated & added DMA support.
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
* 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth.
+ * 02-04-2000 RMK 0.0.4 Updated for new error handling code.
*/
#include <linux/module.h>
@@ -70,7 +71,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 3
+#define VER_PATCH 4
static struct expansion_card *ecs[MAX_ECARDS];
@@ -433,25 +434,11 @@ const char *cumanascsi_2_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX ",
- host->hostt->name, host->io_port);
-
- if (host->irq != NO_IRQ)
- p += sprintf(p, "irq %d ", host->irq);
- else
- p += sprintf(p, "NO IRQ ");
-
- if (host->dma_channel != NO_DMA)
- p += sprintf(p, "dma %d ", host->dma_channel);
- else
- p += sprintf(p, "NO DMA ");
-
- p += sprintf(p, "v%d.%d.%d scsi %s",
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d terminators o%s",
VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
-
- p += sprintf(p, " terminators %s",
- info->terms ? "on" : "off");
+ info->terms ? "n" : "ff");
return string;
}
@@ -525,26 +512,14 @@ int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"Cumana SCSI II driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d DMA : %d\n"
- "FAS : %-10s TERM: %-3s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, host->dma_channel,
- info->info.scsi.type, info->terms ? "on" : "off");
-
- pos += sprintf(buffer+pos,
- "Queued commands: %-10u Issued commands: %-10u\n"
- "Done commands : %-10u Reads : %-10u\n"
- "Writes : %-10u Others : %-10u\n"
- "Disconnects : %-10u Aborts : %-10u\n"
- "Resets : %-10u\n",
- info->info.stats.queues, info->info.stats.removes,
- info->info.stats.fins, info->info.stats.reads,
- info->info.stats.writes, info->info.stats.miscs,
- info->info.stats.disconnects, info->info.stats.aborts,
- info->info.stats.resets);
-
- pos += sprintf(buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+
+ pos += fas216_print_host(&info->info, buffer + pos);
+ pos += sprintf(buffer + pos, "Term : o%s\n",
+ info->terms ? "n" : "ff");
+
+ pos += fas216_print_stats(&info->info, buffer + pos);
+
+ pos += sprintf(buffer+pos, "\nAttached devices:\n");
for (scd = host->host_queue; scd; scd = scd->next) {
int len;
diff --git a/drivers/acorn/scsi/cumana_2.h b/drivers/acorn/scsi/cumana_2.h
index 66b374019..48ac695b7 100644
--- a/drivers/acorn/scsi/cumana_2.h
+++ b/drivers/acorn/scsi/cumana_2.h
@@ -1,7 +1,7 @@
/*
* Cumana SCSI II driver
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef CUMANA_2_H
#define CUMANA_2_H
@@ -23,6 +23,13 @@ extern int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
#define CAN_QUEUE 1
#endif
+#ifndef CMD_PER_LUN
+/*
+ * Default queue size
+ */
+#define CMD_PER_LUN 1
+#endif
+
#ifndef SCSI_ID
/*
* Default SCSI host ID
@@ -36,23 +43,25 @@ extern int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
#endif
-#define CUMANASCSI_2 { \
-proc_info: cumanascsi_2_proc_info, \
-name: "Cumana SCSI II", \
-detect: cumanascsi_2_detect, /* detect */ \
-release: cumanascsi_2_release, /* release */ \
-info: cumanascsi_2_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CAN_QUEUE, /* cmd per lun */ \
-unchecked_isa_dma: 0, /* unchecked isa dma */ \
-use_clustering: DISABLE_CLUSTERING \
+#define CUMANASCSI_2 { \
+proc_info: cumanascsi_2_proc_info, \
+name: "Cumana SCSI II", \
+detect: cumanascsi_2_detect, \
+release: cumanascsi_2_release, \
+info: cumanascsi_2_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CMD_PER_LUN, \
+use_clustering: DISABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c
index e6a6a4005..2ebe06f59 100644
--- a/drivers/acorn/scsi/eesox.c
+++ b/drivers/acorn/scsi/eesox.c
@@ -1,20 +1,22 @@
/*
* linux/arch/arm/drivers/scsi/eesox.c
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
* may not be reliable!
*
* Changelog:
- * 01-10-1997 RMK Created, READONLY version
- * 15-02-1998 RMK READ/WRITE version
- * added DMA support and hardware definitions
- * 14-03-1998 RMK Updated DMA support
- * Added terminator control
- * 15-04-1998 RMK Only do PIO if FAS216 will allow it.
- * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
+ * 01-10-1997 RMK Created, READONLY version
+ * 15-02-1998 RMK READ/WRITE version
+ * added DMA support and hardware definitions
+ * 14-03-1998 RMK Updated DMA support
+ * Added terminator control
+ * 15-04-1998 RMK Only do PIO if FAS216 will allow it.
+ * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
+ * 02-04-2000 RMK 0.0.3 Fixed NO_IRQ/NO_DMA problem, updated for new
+ * error handling code.
*/
#include <linux/module.h>
@@ -67,7 +69,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 2
+#define VER_PATCH 3
static struct expansion_card *ecs[MAX_ECARDS];
@@ -382,14 +384,16 @@ eesoxscsi_detect(Scsi_Host_Template *tpnt)
request_region(host->io_port + EESOX_FAS216_OFFSET,
16 << EESOX_FAS216_SHIFT, "eesox2-fas");
- if (request_irq(host->irq, eesoxscsi_intr,
+ if (host->irq != NO_IRQ &&
+ request_irq(host->irq, eesoxscsi_intr,
SA_INTERRUPT, "eesox", host)) {
printk("scsi%d: IRQ%d not free, interrupts disabled\n",
host->host_no, host->irq);
host->irq = NO_IRQ;
}
- if (request_dma(host->dma_channel, "eesox")) {
+ if (host->dma_channel != NO_DMA &&
+ request_dma(host->dma_channel, "eesox")) {
printk("scsi%d: DMA%d not free, DMA disabled\n",
host->host_no, host->dma_channel);
host->dma_channel = NO_DMA;
@@ -435,24 +439,11 @@ const char *eesoxscsi_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX ",
- host->hostt->name, host->io_port);
-
- if (host->irq != NO_IRQ)
- p += sprintf(p, "irq %d ", host->irq);
- else
- p += sprintf(p, "NO IRQ ");
-
- if (host->dma_channel != NO_DMA)
- p += sprintf(p, "dma %d ", host->dma_channel);
- else
- p += sprintf(p, "NO DMA ");
-
- p += sprintf(p, "v%d.%d.%d scsi %s", VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
-
- p += sprintf(p, " terminators %s",
- info->control.control & EESOX_TERM_ENABLE ? "on" : "off");
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d terminators o%s",
+ VER_MAJOR, VER_MINOR, VER_PATCH,
+ info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
return string;
}
@@ -526,26 +517,13 @@ int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"EESOX SCSI driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d DMA : %d\n"
- "FAS : %-10s TERM: %-3s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, host->dma_channel,
- info->info.scsi.type, info->control.control & EESOX_TERM_ENABLE ? "on" : "off");
-
- pos += sprintf(buffer+pos,
- "Queued commands: %-10u Issued commands: %-10u\n"
- "Done commands : %-10u Reads : %-10u\n"
- "Writes : %-10u Others : %-10u\n"
- "Disconnects : %-10u Aborts : %-10u\n"
- "Resets : %-10u\n",
- info->info.stats.queues, info->info.stats.removes,
- info->info.stats.fins, info->info.stats.reads,
- info->info.stats.writes, info->info.stats.miscs,
- info->info.stats.disconnects, info->info.stats.aborts,
- info->info.stats.resets);
-
- pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+ pos += fas216_print_host(&info->info, buffer + pos);
+ pos += sprintf(buffer + pos, "Term : o%s\n",
+ info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
+
+ pos += fas216_print_stats(&info->info, buffer + pos);
+
+ pos += sprintf (buffer+pos, "\nAttached devices:\n");
for (scd = host->host_queue; scd; scd = scd->next) {
int len;
diff --git a/drivers/acorn/scsi/eesox.h b/drivers/acorn/scsi/eesox.h
index 31c6c883e..05433fd6b 100644
--- a/drivers/acorn/scsi/eesox.h
+++ b/drivers/acorn/scsi/eesox.h
@@ -1,7 +1,7 @@
/*
* EESOX SCSI driver
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef EESOXSCSI_H
#define EESOXSCSI_H
@@ -38,22 +38,25 @@ extern int eesoxscsi_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
-#define EESOXSCSI { \
-proc_info: eesoxscsi_proc_info, \
-name: "EESOX SCSI", \
-detect: eesoxscsi_detect, /* detect */ \
-release: eesoxscsi_release, /* release */ \
-info: eesoxscsi_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CAN_QUEUE, /* cmd per lun */ \
-use_clustering: DISABLE_CLUSTERING \
+#define EESOXSCSI { \
+proc_info: eesoxscsi_proc_info, \
+name: "EESOX SCSI", \
+detect: eesoxscsi_detect, \
+release: eesoxscsi_release, \
+info: eesoxscsi_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CAN_QUEUE, \
+use_clustering: DISABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c
index 744480f51..1a89a91eb 100644
--- a/drivers/acorn/scsi/fas216.c
+++ b/drivers/acorn/scsi/fas216.c
@@ -1,11 +1,12 @@
/*
* linux/arch/arm/drivers/scsi/fas216.c
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
* other sources, including:
* the AMD Am53CF94 data sheet
+ * the AMD Am53C94 data sheet
*
* This is a generic driver. To use it, have a look at cumana_2.c. You
* should define your own structure that overlays FAS216_Info, eg:
@@ -25,6 +26,9 @@
* 24-05-1998 RMK Fixed synchronous transfers with period >= 200ns
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
* 26-08-1998 RMK Improved message support wrt MESSAGE_REJECT
+ * 02-04-2000 RMK Converted to use the new error handling, and
+ * automatically request sense data upon check
+ * condition status from targets.
*
* Todo:
* - allow individual devices to enable sync xfers.
@@ -59,8 +63,6 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
#define VER_MINOR 0
#define VER_PATCH 5
-#define SCSI2_TAG
-
/* NOTE: SCSI2 Synchronous transfers *require* DMA according to
* the data sheet. This restriction is crazy, especially when
* you only want to send 16 bytes! What were the guys who
@@ -85,8 +87,8 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
* I was thinking that this was a good chip until I found this restriction ;(
*/
#define SCSI2_SYNC
-
-#define SCSI2_WIDE
+#undef SCSI2_WIDE
+#undef SCSI2_TAG
#undef DEBUG_CONNECT
#undef DEBUG_BUSSERVICE
@@ -143,10 +145,11 @@ static void fas216_dumpinfo(FAS216_Info *info)
info->scsi.async_stp,
info->scsi.disconnectable, info->scsi.aborting);
printk(" stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
- " disconnects=%X aborts=%X resets=%X }\n",
+ " disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n",
info->stats.queues, info->stats.removes, info->stats.fins,
info->stats.reads, info->stats.writes, info->stats.miscs,
- info->stats.disconnects, info->stats.aborts, info->stats.resets);
+ info->stats.disconnects, info->stats.aborts, info->stats.bus_resets,
+ info->stats.host_resets);
printk(" ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",
info->ifcfg.clockrate, info->ifcfg.select_timeout,
info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
@@ -164,7 +167,7 @@ static void fas216_dumpinfo(FAS216_Info *info)
}
#ifdef CHECK_STRUCTURE
-static void fas216_checkmagic(FAS216_Info *info, const char *func)
+static void __fas216_checkmagic(FAS216_Info *info, const char *func)
{
int corruption = 0;
if (info->magic_start != MAGIC) {
@@ -180,8 +183,9 @@ static void fas216_checkmagic(FAS216_Info *info, const char *func)
panic("scsi memory space corrupted in %s", func);
}
}
+#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
#else
-#define fas216_checkmagic(info,func)
+#define fas216_checkmagic(info)
#endif
static const char *fas216_bus_phase(int stat)
@@ -312,7 +316,7 @@ fas216_syncperiod(FAS216_Info *info, int ns)
{
int value = (info->ifcfg.clockrate * ns) / 1000;
- fas216_checkmagic(info, "fas216_syncperiod");
+ fas216_checkmagic(info);
if (value < 4)
value = 4;
@@ -586,7 +590,7 @@ fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
unsigned char *ptr;
unsigned int residual;
- fas216_checkmagic(info, "fas216_updateptrs");
+ fas216_checkmagic(info);
ptr = info->scsi.SCp.ptr;
residual = info->scsi.SCp.this_residual;
@@ -629,7 +633,7 @@ fas216_pio(FAS216_Info *info, fasdmadir_t direction)
unsigned int residual;
char *ptr;
- fas216_checkmagic(info, "fas216_pio");
+ fas216_checkmagic(info);
residual = info->scsi.SCp.this_residual;
ptr = info->scsi.SCp.ptr;
@@ -668,7 +672,7 @@ fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction, int flush_fifo)
{
fasdmatype_t dmatype;
- fas216_checkmagic(info, "fas216_starttransfer");
+ fas216_checkmagic(info);
info->scsi.phase = (direction == DMA_OUT) ?
PHASE_DATAOUT : PHASE_DATAIN;
@@ -763,7 +767,7 @@ fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction, int flush_fifo)
static void
fas216_stoptransfer(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_stoptransfer");
+ fas216_checkmagic(info);
if (info->dma.transfer_type != fasdma_none &&
info->dma.transfer_type != fasdma_pio) {
@@ -797,7 +801,7 @@ fas216_stoptransfer(FAS216_Info *info)
static void
fas216_disconnect_intr(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_disconnected_intr");
+ fas216_checkmagic(info);
#ifdef DEBUG_CONNECT
printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no,
@@ -849,7 +853,7 @@ fas216_reselected_intr(FAS216_Info *info)
{
unsigned char target, identify_msg, ok;
- fas216_checkmagic(info, "fas216_reselected_intr");
+ fas216_checkmagic(info);
if ((info->scsi.phase == PHASE_SELECTION ||
info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {
@@ -949,6 +953,7 @@ fas216_reselected_intr(FAS216_Info *info)
msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
info->scsi.phase = PHASE_MSGOUT_EXPECT;
}
+
outb(CMD_MSGACCEPTED, REG_CMD(info));
}
@@ -959,7 +964,7 @@ fas216_reselected_intr(FAS216_Info *info)
static void
fas216_finish_reconnect(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_reconnect");
+ fas216_checkmagic(info);
#ifdef DEBUG_CONNECT
printk("Connected: %1X %1X %02X, reconnected: %1X %1X %02X\n",
@@ -1087,7 +1092,7 @@ static void fas216_message(FAS216_Info *info)
unsigned int msglen = 1, i;
int msgbyte = 0;
- fas216_checkmagic(info, "fas216_message");
+ fas216_checkmagic(info);
message[0] = inb(REG_FF(info));
@@ -1270,7 +1275,7 @@ static void fas216_send_command(FAS216_Info *info)
{
int i;
- fas216_checkmagic(info, "fas216_send_command");
+ fas216_checkmagic(info);
outb(CMD_NOP|CMD_WITHDMA, REG_CMD(info));
outb(CMD_FLUSHFIFO, REG_CMD(info));
@@ -1293,7 +1298,7 @@ static void fas216_send_messageout(FAS216_Info *info, int start)
{
unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
- fas216_checkmagic(info, "fas216_send_messageout");
+ fas216_checkmagic(info);
outb(CMD_FLUSHFIFO, REG_CMD(info));
@@ -1326,7 +1331,7 @@ static void fas216_send_messageout(FAS216_Info *info, int start)
*/
static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
{
- fas216_checkmagic(info, "fas216_busservice_intr");
+ fas216_checkmagic(info);
#ifdef DEBUG_BUSSERVICE
printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n",
@@ -1520,7 +1525,7 @@ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned
{
int status, message;
- fas216_checkmagic(info, "fas216_funcdone_intr");
+ fas216_checkmagic(info);
#ifdef DEBUG_FUNCTIONDONE
printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n",
@@ -1562,7 +1567,7 @@ void fas216_intr(struct Scsi_Host *instance)
FAS216_Info *info = (FAS216_Info *)instance->hostdata;
unsigned char isr, ssr, stat;
- fas216_checkmagic(info, "fas216_intr");
+ fas216_checkmagic(info);
stat = inb(REG_STAT(info));
ssr = inb(REG_IS(info));
@@ -1571,9 +1576,10 @@ void fas216_intr(struct Scsi_Host *instance)
add_debug_list(stat, ssr, isr, info->scsi.phase);
if (stat & STAT_INT) {
- if (isr & INST_BUSRESET)
+ if (isr & INST_BUSRESET) {
printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no);
- else if (isr & INST_ILLEGALCMD) {
+ scsi_report_bus_reset(instance, 0);
+ } else if (isr & INST_ILLEGALCMD) {
printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no);
fas216_dumpstate(info);
} else if (isr & INST_DISCONNECT)
@@ -1599,22 +1605,35 @@ void fas216_intr(struct Scsi_Host *instance)
*/
static void fas216_kick(FAS216_Info *info)
{
- Scsi_Cmnd *SCpnt;
- int tot_msglen, from_queue = 0;
+ Scsi_Cmnd *SCpnt = NULL;
+ int tot_msglen, from_queue = 0, disconnect_ok;
- fas216_checkmagic(info, "fas216_kick");
+ fas216_checkmagic(info);
- if (info->origSCpnt) {
- SCpnt = info->origSCpnt;
- info->origSCpnt = NULL;
- } else
- SCpnt = NULL;
+ /*
+ * Obtain the next command to process.
+ */
+ do {
+ if (info->reqSCpnt) {
+ SCpnt = info->reqSCpnt;
+ info->reqSCpnt = NULL;
+ break;
+ }
- /* retrieve next command */
- if (!SCpnt) {
- SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns);
- from_queue = 1;
- }
+ if (info->origSCpnt) {
+ SCpnt = info->origSCpnt;
+ info->origSCpnt = NULL;
+ break;
+ }
+
+ /* retrieve next command */
+ if (!SCpnt) {
+ SCpnt = queue_remove_exclude(&info->queues.issue,
+ info->busyluns);
+ from_queue = 1;
+ break;
+ }
+ } while (0);
if (!SCpnt) /* no command pending - just exit */
return;
@@ -1628,16 +1647,6 @@ static void fas216_kick(FAS216_Info *info)
}
/*
- * tagged queuing - allocate a new tag to this command
- */
- if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) {
- SCpnt->device->current_tag += 1;
- if (SCpnt->device->current_tag == 0)
- SCpnt->device->current_tag = 1;
- SCpnt->tag = SCpnt->device->current_tag;
- }
-
- /*
* claim host busy
*/
info->scsi.phase = PHASE_SELECTION;
@@ -1653,6 +1662,9 @@ static void fas216_kick(FAS216_Info *info)
if (from_queue) {
#ifdef SCSI2_TAG
+ /*
+ * tagged queuing - allocate a new tag to this command
+ */
if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
SCpnt->cmnd[0] != INQUIRY) {
SCpnt->device->current_tag += 1;
@@ -1681,41 +1693,48 @@ static void fas216_kick(FAS216_Info *info)
}
}
- /* build outgoing message bytes */
- msgqueue_flush(&info->scsi.msgs);
+ /*
+ * Don't allow request sense commands to disconnect.
+ */
+ disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&
+ info->device[SCpnt->target].disconnect_ok;
- if (info->device[SCpnt->target].disconnect_ok)
- msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun));
- else
- msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(0, SCpnt->lun));
+ /*
+ * build outgoing message bytes
+ */
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->lun));
- /* add tag message if required */
+ /*
+ * add tag message if required
+ */
if (SCpnt->tag)
msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
+ do {
#ifdef SCSI2_WIDE
- if (info->device[SCpnt->target].wide_state == neg_wait) {
- info->device[SCpnt->target].wide_state = neg_inprogress;
- msgqueue_addmsg(&info->scsi.msgs, 4,
- EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
- info->ifcfg.wide_max_size);
- }
-#ifdef SCSI2_SYNC
- else
-#endif
+ if (info->device[SCpnt->target].wide_state == neg_wait) {
+ info->device[SCpnt->target].wide_state = neg_inprogress;
+ msgqueue_addmsg(&info->scsi.msgs, 4,
+ EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
+ info->ifcfg.wide_max_size);
+ break;
+ }
#endif
#ifdef SCSI2_SYNC
- if ((info->device[SCpnt->target].sync_state == neg_wait ||
- info->device[SCpnt->target].sync_state == neg_complete) &&
- (SCpnt->cmnd[0] == REQUEST_SENSE ||
- SCpnt->cmnd[0] == INQUIRY)) {
- info->device[SCpnt->target].sync_state = neg_inprogress;
- msgqueue_addmsg(&info->scsi.msgs, 5,
- EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
- 1000 / info->ifcfg.clockrate,
- info->ifcfg.sync_max_depth);
- }
+ if ((info->device[SCpnt->target].sync_state == neg_wait ||
+ info->device[SCpnt->target].sync_state == neg_complete) &&
+ (SCpnt->cmnd[0] == REQUEST_SENSE ||
+ SCpnt->cmnd[0] == INQUIRY)) {
+ info->device[SCpnt->target].sync_state = neg_inprogress;
+ msgqueue_addmsg(&info->scsi.msgs, 5,
+ EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+ 1000 / info->ifcfg.clockrate,
+ info->ifcfg.sync_max_depth);
+ break;
+ }
#endif
+ } while (0);
/* following what the ESP driver says */
outb(0, REG_STCL(info));
@@ -1780,18 +1799,156 @@ static void fas216_kick(FAS216_Info *info)
/* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */
}
+/* Function: void fas216_rq_sns_done(info, SCpnt, result)
+ * Purpose : Finish processing automatic request sense command
+ * Params : info - interface that completed
+ * SCpnt - command that completed
+ * result - driver byte of result
+ */
+static void
+fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+#ifdef DEBUG_CONNECT
+ printk("scsi%d.%c: request sense complete, result=%04X%02X%02X\n",
+ info->host->host_no, '0' + SCpnt->target, result,
+ SCpnt->SCp.Message, SCpnt->SCp.Status);
+#endif
+
+ if (result != DID_OK || SCpnt->SCp.Status != GOOD)
+ /*
+ * Something went wrong. Make sure that we don't
+ * have valid data in the sense buffer that could
+ * confuse the higher levels.
+ */
+ memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+
+ /*
+ * Note that we don't set SCpnt->result, since that should
+ * reflect the status of the command that we were asked by
+ * the upper layers to process. This would have been set
+ * correctly by fas216_std_done.
+ */
+ SCpnt->scsi_done(SCpnt);
+}
+
+/* Function: void fas216_std_done(info, SCpnt, result)
+ * Purpose : Finish processing of standard command
+ * Params : info - interface that completed
+ * SCpnt - command that completed
+ * result - driver byte of result
+ */
+static void
+fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+ info->stats.fins += 1;
+
+ SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
+ info->scsi.SCp.Status;
+
+#ifdef DEBUG_CONNECT
+ printk("scsi%d.%c: command complete, result=%08X, command=",
+ info->host->host_no, '0' + SCpnt->target, SCpnt->result);
+ print_command(SCpnt->cmnd);
+#endif
+
+ /*
+ * If the driver detected an error, or the command
+ * was request sense, then we're all done.
+ */
+ if (result != DID_OK || SCpnt->cmnd[0] == REQUEST_SENSE)
+ goto done;
+
+ /*
+ * If the command returned CHECK_CONDITION status,
+ * request the sense information.
+ */
+ if (info->scsi.SCp.Status == CHECK_CONDITION)
+ goto request_sense;
+
+ /*
+ * If the command did not complete with GOOD status,
+ * we are all done here.
+ */
+ if (info->scsi.SCp.Status != GOOD)
+ goto done;
+
+ /*
+ * We have successfully completed a command. Make sure that
+ * we do not have any buffers left to transfer. The world
+ * is not perfect, and we seem to occasionally hit this.
+ * It can be indicative of a buggy driver, target or the upper
+ * levels of the SCSI code.
+ */
+ if (info->scsi.SCp.ptr) {
+ switch (SCpnt->cmnd[0]) {
+ case INQUIRY:
+ case START_STOP:
+// case READ_CAPACITY:
+ case MODE_SENSE:
+ break;
+
+ default:
+ printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
+ "detected: res=%08X ptr=%p len=%X command=",
+ info->host->host_no, '0' + SCpnt->target,
+ SCpnt->result, info->scsi.SCp.ptr,
+ info->scsi.SCp.this_residual);
+ print_command(SCpnt->cmnd);
+ }
+ }
+
+done: SCpnt->scsi_done(SCpnt);
+ return;
+
+request_sense:
+ memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd));
+ SCpnt->cmnd[0] = REQUEST_SENSE;
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
+ SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->SCp.buffer = NULL;
+ SCpnt->SCp.buffers_residual = 0;
+ SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer;
+ SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+ SCpnt->SCp.Message = 0;
+ SCpnt->SCp.Status = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
+ SCpnt->use_sg = 0;
+ SCpnt->tag = 0;
+ SCpnt->host_scribble = (void *)fas216_rq_sns_done;
+
+ /*
+ * Place this command into the high priority "request
+ * sense" slot. This will be the very next command
+ * executed, unless a target connects to us.
+ */
+ if (info->reqSCpnt)
+ printk(KERN_WARNING "scsi%d.%c: loosing request command\n",
+ info->host->host_no, '0' + SCpnt->target);
+ info->reqSCpnt = SCpnt;
+}
+
/* Function: void fas216_done(FAS216_Info *info, unsigned int result)
- * Purpose : complete processing for command
+ * Purpose : complete processing for current command
* Params : info - interface that completed
* result - driver byte of result
*/
static void fas216_done(FAS216_Info *info, unsigned int result)
{
+ void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
Scsi_Cmnd *SCpnt;
- fas216_checkmagic(info, "fas216_done");
+ fas216_checkmagic(info);
+
+ if (!info->SCpnt)
+ goto no_command;
SCpnt = info->SCpnt;
+ info->SCpnt = NULL;
+ info->scsi.phase = PHASE_IDLE;
+
+ if (!SCpnt->scsi_done)
+ goto no_done;
if (info->scsi.aborting) {
printk("scsi%d.%c: uncaught abort - returning DID_ABORT\n",
@@ -1800,66 +1957,39 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
info->scsi.aborting = 0;
}
- info->stats.fins += 1;
-
- if (SCpnt) {
- info->scsi.phase = PHASE_IDLE;
- info->SCpnt = NULL;
-
- SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
- info->scsi.SCp.Status;
-
- /*
- * In theory, this should not happen, but just in case it does.
- */
- if (info->scsi.SCp.ptr &&
- info->scsi.SCp.this_residual &&
- result == DID_OK) {
- switch (SCpnt->cmnd[0]) {
- case INQUIRY:
- case START_STOP:
- case READ_CAPACITY:
- case TEST_UNIT_READY:
- case MODE_SENSE:
- case REQUEST_SENSE:
- break;
-
- default:
- switch (status_byte(SCpnt->result)) {
- case CHECK_CONDITION:
- case COMMAND_TERMINATED:
- case BUSY:
- case QUEUE_FULL:
- case RESERVATION_CONFLICT:
- break;
-
- default:
- printk(KERN_ERR "scsi%d.H: incomplete data transfer "
- "detected: res=%08X ptr=%p len=%X command=",
- info->host->host_no, SCpnt->result,
- info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
- print_command(SCpnt->cmnd);
- }
- }
- }
-#ifdef DEBUG_CONNECT
- printk("scsi%d.%c: scsi command (%p) complete, result=%08X\n",
- info->host->host_no, fas216_target(info),
- SCpnt, SCpnt->result);
-#endif
-
- if (!SCpnt->scsi_done)
- panic("scsi%d.H: null scsi_done function in "
- "fas216_done", info->host->host_no);
+ /*
+ * Sanity check the completion - if we have zero bytes left
+ * to transfer, we should not have a valid pointer.
+ */
+ if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
+ printk("scsi%d.%c: zero bytes left to transfer, but "
+ "buffer pointer still valid: ptr=%p len=%08x command=",
+ info->host->host_no, '0' + SCpnt->target,
+ info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+ info->scsi.SCp.ptr = NULL;
+ print_command(SCpnt->cmnd);
+ }
- clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
+ /*
+ * Clear down this command as completed. If we need to request
+ * the sense information, fas216_kick will re-assert the busy
+ * status.
+ */
+ clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
- SCpnt->scsi_done(SCpnt);
- } else
- panic("scsi%d.H: null command in fas216_done", info->host->host_no);
+ fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
+ fn(info, SCpnt, result);
if (info->scsi.irq != NO_IRQ)
fas216_kick(info);
+ return;
+
+no_command:
+ panic("scsi%d.H: null command in fas216_done",
+ info->host->host_no);
+no_done:
+ panic("scsi%d.H: null scsi_done function in fas216_done",
+ info->host->host_no);
}
/* Function: int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
@@ -1867,13 +1997,14 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
* Params : SCpnt - Command to queue
* done - done function to call once command is complete
* Returns : 0 - success, else error
+ * Notes : io_request_lock is held, interrupts are disabled.
*/
int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- unsigned long flags;
+ int result;
- fas216_checkmagic(info, "fas216_queue_command");
+ fas216_checkmagic(info);
#ifdef DEBUG_CONNECT
printk("scsi%d.%c: received queuable command (%p) %02X\n",
@@ -1882,7 +2013,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
#endif
SCpnt->scsi_done = done;
- SCpnt->host_scribble = NULL;
+ SCpnt->host_scribble = (void *)fas216_std_done;
SCpnt->result = 0;
SCpnt->SCp.Message = 0;
SCpnt->SCp.Status = 0;
@@ -1896,10 +2027,16 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
/*
- * Calculate correct buffer length
+ * Calculate correct buffer length. Some commands
+ * come in with the wrong request_bufflen.
*/
for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
len += SCpnt->SCp.buffer[buf].length;
+
+ if (SCpnt->request_bufflen != len)
+ printk(KERN_WARNING "scsi%d.%c: bad request buffer "
+ "length %d, should be %ld\n", info->host->host_no,
+ '0' + SCpnt->target, SCpnt->request_bufflen, len);
SCpnt->request_bufflen = len;
} else {
SCpnt->SCp.buffer = NULL;
@@ -1908,22 +2045,36 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
SCpnt->SCp.this_residual = SCpnt->request_bufflen;
}
+ /*
+ * If the upper SCSI layers pass a buffer, but zero length,
+ * we aren't interested in the buffer pointer.
+ */
+ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) {
+#if 0
+ printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
+ "command ", info->host->host_no, '0' + SCpnt->target);
+ print_command(SCpnt->cmnd);
+#endif
+ SCpnt->SCp.ptr = NULL;
+ }
+
info->stats.queues += 1;
SCpnt->tag = 0;
- /* add command into execute queue and let it complete under
+ /*
+ * Add command into execute queue and let it complete under
* whatever scheme we're using.
*/
- if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
- SCpnt->result = DID_ERROR << 16;
- done(SCpnt);
- }
- save_flags_cli(flags);
- if (!info->SCpnt || info->scsi.disconnectable)
+ result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt);
+
+ /*
+ * If we successfully added the command,
+ * kick the interface to get it moving.
+ */
+ if (result == 0 && (!info->SCpnt || info->scsi.disconnectable))
fas216_kick(info);
- restore_flags(flags);
- return 0;
+ return result;
}
/* Function: void fas216_internal_done(Scsi_Cmnd *SCpnt)
@@ -1934,7 +2085,7 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- fas216_checkmagic(info, "fas216_internal_done");
+ fas216_checkmagic(info);
info->internal_done = 1;
}
@@ -1943,13 +2094,20 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt)
* Purpose : queue a command for adapter to process.
* Params : SCpnt - Command to queue
* Returns : scsi result code
+ * Notes : io_request_lock is held, interrupts are disabled.
*/
int fas216_command(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- unsigned long flags;
- fas216_checkmagic(info, "fas216_command");
+ fas216_checkmagic(info);
+
+ /*
+ * We should only be using this if we don't have an interrupt.
+ * Provide some "incentive" to use the queueing code.
+ */
+ if (info->scsi.irq != NO_IRQ)
+ BUG();
info->internal_done = 0;
fas216_queue_command(SCpnt, fas216_internal_done);
@@ -1960,114 +2118,52 @@ int fas216_command(Scsi_Cmnd *SCpnt)
* However, we must re-enable interrupts, or else we'll be
* waiting forever.
*/
- save_flags(flags);
- sti();
+ spin_unlock_irq(&io_request_lock);
while (!info->internal_done) {
/*
- * If we don't have an IRQ, then we must
- * poll the card for it's interrupt, and
- * use that to call this driver's interrupt
- * routine. That way, we keep the command
- * progressing.
+ * If we don't have an IRQ, then we must poll the card for
+ * it's interrupt, and use that to call this driver's
+ * interrupt routine. That way, we keep the command
+ * progressing. Maybe we can add some inteligence here
+ * and go to sleep if we know that the device is going
+ * to be some time (eg, disconnected).
*/
- if (info->scsi.irq == NO_IRQ) {
- sti();
- while (!(inb(REG_STAT(info)) & STAT_INT));
- cli();
+ if (inb(REG_STAT(info)) & STAT_INT) {
+ spin_lock_irq(&io_request_lock);
fas216_intr(info->host);
+ spin_unlock_irq(&io_request_lock);
}
}
- restore_flags(flags);
+ spin_lock_irq(&io_request_lock);
return SCpnt->result;
}
-/* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1,
- * Scsi_Cmnd **SCpntp2, int result, int no_report)
- * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
- * Params : SCpntp1 - pointer to command to return
- * SCpntp2 - pointer to command to check
- * result - result to pass back to mid-level done function
- * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command
- * structure as *SCpntp2.
- */
-static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2,
- int result, int no_report)
-{
- Scsi_Cmnd *SCpnt = *SCpntp1;
-
- if (SCpnt) {
- *SCpntp1 = NULL;
-
- SCpnt->result = result;
- if (!no_report || SCpnt != *SCpntp2)
- SCpnt->scsi_done(SCpnt);
- }
-
- if (SCpnt == *SCpntp2)
- *SCpntp2 = NULL;
-}
-
-/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
- * Purpose : abort this command
- * Params : SCpnt - command to abort
- * Returns : FAILED if unable to abort
- */
-int fas216_eh_abort(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the device associated with this command
- * Params : SCpnt - command specifing device to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the complete bus associated with this command
- * Params : SCpnt - command specifing bus to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the host associated with this command
- * Params : SCpnt - command specifing host to reset
- * Returns : FAILED if unable to reset
- */
-int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
-{
- return FAILED;
-}
-
-enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+enum res_abort {
+ res_failed, /* unable to abort */
+ res_success, /* command on issue queue */
+ res_success_clear, /* command marked tgt/lun busy */
+ res_hw_abort /* command on disconnected dev */
+};
/*
* Prototype: enum res_abort fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
- * Purpose : abort a command on this host
+ * Purpose : decide how to abort a command
* Params : SCpnt - command to abort
* Returns : abort status
*/
static enum res_abort
fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
{
- enum res_abort res = res_not_running;
+ enum res_abort res = res_failed;
if (queue_removecmd(&info->queues.issue, SCpnt)) {
/*
* The command was on the issue queue, and has not been
* issued yet. We can remove the command from the queue,
- * and acknowledge the abort. Neither the devices nor the
+ * and acknowledge the abort. Neither the device nor the
* interface know about the command.
*/
printk("on issue queue ");
@@ -2075,54 +2171,32 @@ fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
res = res_success;
} else if (queue_removecmd(&info->queues.disconnected, SCpnt)) {
/*
- * The command was on the disconnected queue. Simply
- * acknowledge the abort condition, and when the target
- * reconnects, we will give it an ABORT message. The
- * target should then disconnect, and we will clear
- * the busylun bit.
+ * The command was on the disconnected queue. We must
+ * reconnect with the device if possible, and send it
+ * an abort message.
*/
printk("on disconnected queue ");
- res = res_success;
+ res = res_hw_abort;
} else if (info->SCpnt == SCpnt) {
- unsigned long flags;
-
printk("executing ");
- save_flags(flags);
- cli();
switch (info->scsi.phase) {
/*
* If the interface is idle, and the command is 'disconnectable',
- * then it is the same as on the disconnected queue. We simply
- * remove all traces of the command. When the target reconnects,
- * we will give it an ABORT message since the command could not
- * be found. When the target finally disconnects, we will clear
- * the busylun bit.
+ * then it is the same as on the disconnected queue.
*/
case PHASE_IDLE:
if (info->scsi.disconnectable) {
info->scsi.disconnectable = 0;
info->SCpnt = NULL;
- res = res_success;
+ res = res_hw_abort;
}
break;
- /*
- * If the command has connected and done nothing futher,
- * simply force a disconnect. We also need to clear the
- * busylun bit.
- */
- case PHASE_SELECTION:
-// info->SCpnt = NULL;
-// res = res_success_clear;
-// break;
-
default:
- res = res_snooze;
break;
}
- restore_flags(flags);
} else if (info->origSCpnt == SCpnt) {
/*
* The command will be executed next, but a command
@@ -2139,17 +2213,18 @@ fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
return res;
}
-/* Function: int fas216_abort(Scsi_Cmnd *SCpnt)
- * Purpose : abort a command if something horrible happens.
- * Params : SCpnt - Command that is believed to be causing a problem.
- * Returns : one of SCSI_ABORT_ macros.
+/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ * Notes : io_request_lock is taken, and irqs are disabled
*/
-int fas216_abort(Scsi_Cmnd *SCpnt)
+int fas216_eh_abort(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- int result = SCSI_ABORT_SNOOZE;
+ int result = FAILED;
- fas216_checkmagic(info, "fas216_abort");
+ fas216_checkmagic(info);
info->stats.aborts += 1;
@@ -2176,29 +2251,23 @@ int fas216_abort(Scsi_Cmnd *SCpnt)
*/
case res_success:
printk("success\n");
- SCpnt->result = DID_ABORT << 16;
- SCpnt->scsi_done(SCpnt);
- result = SCSI_ABORT_SUCCESS;
+ result = SUCCESS;
break;
/*
- * We did find the command, but unfortunately we couldn't
- * unhook it from ourselves. Wait some more, and if it
- * still doesn't complete, reset the interface.
+ * We need to reconnect to the target and send it an
+ * ABORT or ABORT_TAG message. We can only do this
+ * if the bus is free.
*/
- case res_snooze:
- printk("snooze\n");
- result = SCSI_ABORT_SNOOZE;
- break;
+ case res_hw_abort:
+
/*
- * The command could not be found (either because it completed,
- * or it got dropped.
+ * We are unable to abort the command for some reason.
*/
default:
- case res_not_running:
- result = SCSI_ABORT_SNOOZE;
- printk("not running\n");
+ case res_failed:
+ printk("failed\n");
break;
}
@@ -2214,7 +2283,7 @@ static void fas216_reset_state(FAS216_Info *info)
neg_t sync_state, wide_state;
int i;
- fas216_checkmagic(info, "fas216_reset_state");
+ fas216_checkmagic(info);
/*
* Clear out all stale info in our state structure
@@ -2257,6 +2326,80 @@ static void fas216_reset_state(FAS216_Info *info)
info->device[i].sof = 0;
info->device[i].wide_xfer = 0;
}
+
+ /*
+ * Drain all commands on disconnected queue
+ */
+ while (queue_remove(&info->queues.disconnected) != NULL);
+
+ /*
+ * Remove executing commands.
+ */
+ info->SCpnt = NULL;
+ info->reqSCpnt = NULL;
+ info->origSCpnt = NULL;
+}
+
+/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+
+ printk("scsi%d.%c: "__FUNCTION__": called\n",
+ info->host->host_no, '0' + SCpnt->target);
+ return FAILED;
+}
+
+/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the bus associated with the command
+ * Params : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ * Notes : io_request_lock is taken, and irqs are disabled
+ */
+int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+ int result = FAILED;
+
+ fas216_checkmagic(info);
+
+ info->stats.bus_resets += 1;
+
+ printk("scsi%d.%c: "__FUNCTION__": resetting bus\n",
+ info->host->host_no, '0' + SCpnt->target);
+
+ /*
+ * Attempt to stop all activity on this interface.
+ */
+ outb(info->scsi.cfg[2], REG_CNTL3(info));
+ fas216_stoptransfer(info);
+
+ /*
+ * Clear any pending interrupts
+ */
+ while (inb(REG_STAT(info)) & STAT_INT)
+ inb(REG_INST(info));
+
+ /*
+ * Reset the SCSI bus
+ */
+ outb(CMD_RESETSCSI, REG_CMD(info));
+ udelay(5);
+
+ /*
+ * Clear reset interrupt
+ */
+ if (inb(REG_STAT(info)) & STAT_INT &&
+ inb(REG_INST(info)) & INST_BUSRESET)
+ result = SUCCESS;
+
+ fas216_reset_state(info);
+
+ return result;
}
/* Function: void fas216_init_chip(FAS216_Info *info)
@@ -2265,8 +2408,6 @@ static void fas216_reset_state(FAS216_Info *info)
*/
static void fas216_init_chip(FAS216_Info *info)
{
- fas216_checkmagic(info, "fas216_init_chip");
-
outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info));
outb(info->scsi.cfg[0], REG_CNTL1(info));
outb(info->scsi.cfg[1], REG_CNTL2(info));
@@ -2277,100 +2418,144 @@ static void fas216_init_chip(FAS216_Info *info)
outb(info->scsi.cfg[0], REG_CNTL1(info));
}
-/* Function: int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
- * Purpose : resets the adapter if something horrible happens.
- * Params : SCpnt - Command that is believed to be causing a problem.
- * reset_flags - flags indicating reset type that is believed
- * to be required.
- * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET
- * macros.
+/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ * Notes : io_request_lock is taken, and irqs are disabled
*/
-int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
- Scsi_Cmnd *SCptr;
- int result = 0;
- int synchronous = reset_flags & SCSI_RESET_SYNCHRONOUS;
- fas216_checkmagic(info, "fas216_reset");
+ fas216_checkmagic(info);
+
+ printk("scsi%d.%c: "__FUNCTION__": resetting host\n",
+ info->host->host_no, '0' + SCpnt->target);
/*
- * Validate that command is actually on one of our queues if we're doing
- * an asynchronous reset
+ * Reset the SCSI chip.
*/
- if (reset_flags & SCSI_RESET_ASYNCHRONOUS &&
- SCpnt &&
- info->SCpnt != SCpnt &&
- info->origSCpnt != SCpnt &&
- !queue_cmdonqueue(&info->queues.disconnected, SCpnt) &&
- !queue_cmdonqueue(&info->queues.issue, SCpnt)) {
- printk("scsi%d: fas216_reset: asynchronous reset for unknown command\n",
- info->host->host_no);
- return SCSI_RESET_NOT_RUNNING;
- }
+ outb(CMD_RESETCHIP, REG_CMD(info));
- info->stats.resets += 1;
+ /*
+ * Ugly ugly ugly!
+ * We need to release the io_request_lock and enable
+ * IRQs if we sleep, but we must relock and disable
+ * IRQs after the sleep.
+ */
+ spin_unlock_irq(&io_request_lock);
+ scsi_sleep(5);
+ spin_lock_irq(&io_request_lock);
- print_debug_list();
- printk(KERN_WARNING "scsi%d: reset ", info->host->host_no);
- if (SCpnt)
- printk("for target %d ", SCpnt->target);
+ /*
+ * Release the SCSI reset.
+ */
+ outb(CMD_NOP, REG_CMD(info));
- printk("\n");
+ fas216_init_chip(info);
- outb(info->scsi.cfg[3], REG_CNTL3(info));
+ return SUCCESS;
+}
- fas216_stoptransfer(info);
+#define TYPE_UNKNOWN 0
+#define TYPE_NCR53C90 1
+#define TYPE_NCR53C90A 2
+#define TYPE_NCR53C9x 3
+#define TYPE_Am53CF94 4
+#define TYPE_EmFAS216 5
+#define TYPE_QLFAS216 6
+
+static char *chip_types[] = {
+ "unknown",
+ "NS NCR53C90",
+ "NS NCR53C90A",
+ "NS NCR53C9x",
+ "AMD Am53CF94",
+ "Emulex FAS216",
+ "QLogic FAS216"
+};
+
+static int fas216_detect_type(FAS216_Info *info)
+{
+ int family, rev;
- switch (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
- case SCSI_RESET_SUGGEST_BUS_RESET:
- outb(CMD_RESETSCSI, REG_CMD(info));
- outb(CMD_NOP, REG_CMD(info));
- result |= SCSI_RESET_BUS_RESET;
- break;
+ /*
+ * Reset the chip.
+ */
+ outb(CMD_RESETCHIP, REG_CMD(info));
+ udelay(50);
+ outb(CMD_NOP, REG_CMD(info));
- case SCSI_RESET_SUGGEST_HOST_RESET:
- outb(CMD_RESETCHIP, REG_CMD(info));
- outb(CMD_NOP, REG_CMD(info));
- result |= SCSI_RESET_HOST_RESET;
- break;
+ /*
+ * Check to see if control reg 2 is present.
+ */
+ outb(0, REG_CNTL3(info));
+ outb(CNTL2_S2FE, REG_CNTL2(info));
- default:
- outb(CMD_RESETCHIP, REG_CMD(info));
- outb(CMD_NOP, REG_CMD(info));
- outb(CMD_RESETSCSI, REG_CMD(info));
- result |= SCSI_RESET_HOST_RESET | SCSI_RESET_BUS_RESET;
- break;
- }
+ /*
+ * If we are unable to read back control reg 2
+ * correctly, it is not present, and we have a
+ * NCR53C90.
+ */
+ if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE)
+ return TYPE_NCR53C90;
- udelay(300);
- fas216_reset_state(info);
- fas216_init_chip(info);
+ /*
+ * Now, check control register 3
+ */
+ outb(0, REG_CNTL2(info));
+ outb(0, REG_CNTL3(info));
+ outb(5, REG_CNTL3(info));
/*
- * Signal all commands in progress have been reset
+ * If we are unable to read the register back
+ * correctly, we have a NCR53C90A
*/
- fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16, synchronous);
+ if (inb(REG_CNTL3(info)) != 5)
+ return TYPE_NCR53C90A;
- while ((SCptr = queue_remove(&info->queues.disconnected)) != NULL)
- fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16, synchronous);
+ /*
+ * Now read the ID from the chip.
+ */
+ outb(0, REG_CNTL3(info));
- if (SCpnt) {
- /*
- * Command not found on disconnected queue, nor currently
- * executing command - check pending commands
- */
- if (info->origSCpnt == SCpnt)
- info->origSCpnt = NULL;
+ outb(CNTL3_ADIDCHK, REG_CNTL3(info));
+ outb(0, REG_CNTL3(info));
- queue_removecmd(&info->queues.issue, SCpnt);
+ outb(CMD_RESETCHIP, REG_CMD(info));
+ udelay(5);
+ outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info));
- SCpnt->result = DID_RESET << 16;
- if (!synchronous)
- SCpnt->scsi_done(SCpnt);
- }
+ outb(CNTL2_ENF, REG_CNTL2(info));
+ outb(CMD_RESETCHIP, REG_CMD(info));
+ udelay(5);
+ outb(CMD_NOP, REG_CMD(info));
+
+ rev = inb(REG1_ID(info));
+ family = rev >> 3;
+ rev &= 7;
+
+ switch (family) {
+ case 0x01:
+ if (rev == 4)
+ return TYPE_Am53CF94;
+ break;
+
+ case 0x02:
+ switch (rev) {
+ case 2:
+ return TYPE_EmFAS216;
+ case 3:
+ return TYPE_QLFAS216;
+ }
+ break;
- return result | SCSI_RESET_SUCCESS;
+ default:
+ break;
+ }
+ printk("family %x rev %x\n", family, rev);
+ return TYPE_NCR53C9x;
}
/* Function: int fas216_init(struct Scsi_Host *instance)
@@ -2381,19 +2566,14 @@ int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
int fas216_init(struct Scsi_Host *instance)
{
FAS216_Info *info = (FAS216_Info *)instance->hostdata;
- unsigned long flags;
- int target_jiffies;
+ int type;
info->magic_start = MAGIC;
- info->magic_end = MAGIC;
-
- info->host = instance;
+ info->magic_end = MAGIC;
+ info->host = instance;
info->scsi.cfg[0] = instance->this_id;
info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE;
info->scsi.cfg[2] = info->ifcfg.cntl3 | CNTL3_ADIDCHK | CNTL3_G2CB;
- info->scsi.type = "unknown";
- info->SCpnt = NULL;
- fas216_reset_state(info);
memset(&info->stats, 0, sizeof(info->stats));
@@ -2407,64 +2587,36 @@ int fas216_init(struct Scsi_Host *instance)
return 1;
}
- outb(CMD_RESETCHIP, REG_CMD(info));
-
- outb(0, REG_CNTL3(info));
- outb(CNTL2_S2FE, REG_CNTL2(info));
-
- if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) {
- info->scsi.type = "NCR53C90";
- } else {
- outb(0, REG_CNTL2(info));
- outb(0, REG_CNTL3(info));
- outb(5, REG_CNTL3(info));
- if (inb(REG_CNTL3(info)) != 5) {
- info->scsi.type = "NCR53C90A";
- } else {
- outb(0, REG_CNTL3(info));
- info->scsi.type = "NCR53C9x";
- }
- }
-
-
- outb(CNTL3_ADIDCHK, REG_CNTL3(info));
- outb(0, REG_CNTL3(info));
-
- outb(CMD_RESETCHIP, REG_CMD(info));
- outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info));
- outb(CNTL2_ENF, REG_CNTL2(info));
- outb(CMD_RESETCHIP, REG_CMD(info));
- switch (inb(REG1_ID(info))) {
- case 12:
- info->scsi.type = "Am53CF94";
- break;
- default:
- break;
- }
+ fas216_reset_state(info);
+ type = fas216_detect_type(info);
+ info->scsi.type = chip_types[type];
udelay(300);
- /* now for the real initialisation */
+
+ /*
+ * Initialise the chip correctly.
+ */
fas216_init_chip(info);
+ /*
+ * Reset the SCSI bus. We don't want to see
+ * the resulting reset interrupt, so mask it
+ * out.
+ */
outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info));
outb(CMD_RESETSCSI, REG_CMD(info));
- /* scsi standard says 250ms */
- target_jiffies = jiffies + (25 * HZ) / 100;
- save_flags(flags);
- sti();
-
- while (time_before(jiffies, target_jiffies)) barrier();
-
- restore_flags(flags);
+ /*
+ * scsi standard says wait 250ms
+ */
+ spin_unlock_irq(&io_request_lock);
+ scsi_sleep(5);
+ spin_lock_irq(&io_request_lock);
outb(info->scsi.cfg[0], REG_CNTL1(info));
inb(REG_INST(info));
- /* now for the real initialisation */
- fas216_init_chip(info);
-
- fas216_checkmagic(info, "fas216_init");
+ fas216_checkmagic(info);
return 0;
}
@@ -2479,7 +2631,7 @@ int fas216_release(struct Scsi_Host *instance)
{
FAS216_Info *info = (FAS216_Info *)instance->hostdata;
- fas216_checkmagic(info, "fas216_release");
+ fas216_checkmagic(info);
outb(CMD_RESETCHIP, REG_CMD(info));
queue_free(&info->queues.disconnected);
@@ -2488,19 +2640,67 @@ int fas216_release(struct Scsi_Host *instance)
return 0;
}
+/*
+ * Function: int fas216_info(FAS216_Info *info, char *buffer)
+ * Purpose : generate a string containing information about this
+ * host.
+ * Params : info - FAS216 host information
+ * buffer - string buffer to build string
+ * Returns : size of built string
+ */
+int fas216_info(FAS216_Info *info, char *buffer)
+{
+ char *p = buffer;
+
+ p += sprintf(p, "(%s) at port 0x%08lX ",
+ info->scsi.type, info->host->io_port);
+
+ if (info->host->irq != NO_IRQ)
+ p += sprintf(p, "irq %d ", info->host->irq);
+ else
+ p += sprintf(p, "no irq ");
+
+ if (info->host->dma_channel != NO_DMA)
+ p += sprintf(p, "dma %d ", info->host->dma_channel);
+ else
+ p += sprintf(p, "no dma ");
+
+ return p - buffer;
+}
+
+int fas216_print_host(FAS216_Info *info, char *buffer)
+{
+
+ return sprintf(buffer,
+ "\n"
+ "Chip : %s\n"
+ " Address: 0x%08lX\n"
+ " IRQ : %d\n"
+ " DMA : %d\n",
+ info->scsi.type, info->host->io_port,
+ info->host->irq, info->host->dma_channel);
+}
+
int fas216_print_stats(FAS216_Info *info, char *buffer)
{
return sprintf(buffer,
- "Queued commands: %-10u Issued commands: %-10u\n"
- "Done commands : %-10u Reads : %-10u\n"
- "Writes : %-10u Others : %-10u\n"
- "Disconnects : %-10u Aborts : %-10u\n"
- "Resets : %-10u\n",
+ "\n"
+ "Command Statistics:\n"
+ " Queued : %u\n"
+ " Issued : %u\n"
+ " Completed : %u\n"
+ " Reads : %u\n"
+ " Writes : %u\n"
+ " Others : %u\n"
+ " Disconnects: %u\n"
+ " Aborts : %u\n"
+ " Bus resets : %u\n"
+ " Host resets: %u\n",
info->stats.queues, info->stats.removes,
info->stats.fins, info->stats.reads,
info->stats.writes, info->stats.miscs,
info->stats.disconnects, info->stats.aborts,
- info->stats.resets);
+ info->stats.bus_resets, info->stats.host_resets);
}
int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
@@ -2531,9 +2731,8 @@ int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
return p - buffer;
}
+EXPORT_SYMBOL(fas216_info);
EXPORT_SYMBOL(fas216_init);
-EXPORT_SYMBOL(fas216_abort);
-EXPORT_SYMBOL(fas216_reset);
EXPORT_SYMBOL(fas216_queue_command);
EXPORT_SYMBOL(fas216_command);
EXPORT_SYMBOL(fas216_intr);
@@ -2542,6 +2741,7 @@ EXPORT_SYMBOL(fas216_eh_abort);
EXPORT_SYMBOL(fas216_eh_device_reset);
EXPORT_SYMBOL(fas216_eh_bus_reset);
EXPORT_SYMBOL(fas216_eh_host_reset);
+EXPORT_SYMBOL(fas216_print_host);
EXPORT_SYMBOL(fas216_print_stats);
EXPORT_SYMBOL(fas216_print_device);
diff --git a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h
index dede53ba9..4381888fd 100644
--- a/drivers/acorn/scsi/fas216.h
+++ b/drivers/acorn/scsi/fas216.h
@@ -1,11 +1,7 @@
/*
* FAS216 generic driver
*
- * Copyright (C) 1997-1998 Russell King
- *
- * NOTE! This file should be viewed using a console with
- * >100 character width (since it uses 8-space tabs)
- * (it used to fit in 80-columns with 4 space)
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef FAS216_H
#define FAS216_H
@@ -215,6 +211,7 @@ typedef struct {
struct Scsi_Host *host; /* host */
Scsi_Cmnd *SCpnt; /* currently processing command */
Scsi_Cmnd *origSCpnt; /* original connecting command */
+ Scsi_Cmnd *reqSCpnt; /* request sense command */
/* driver information */
struct {
@@ -254,7 +251,8 @@ typedef struct {
unsigned int miscs;
unsigned int disconnects;
unsigned int aborts;
- unsigned int resets;
+ unsigned int bus_resets;
+ unsigned int host_resets;
} stats;
/* configuration information */
@@ -350,6 +348,8 @@ extern void fas216_intr (struct Scsi_Host *instance);
*/
extern int fas216_release (struct Scsi_Host *instance);
+extern int fas216_info(FAS216_Info *info, char *buffer);
+extern int fas216_print_host(FAS216_Info *info, char *buffer);
extern int fas216_print_stats(FAS216_Info *info, char *buffer);
extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer);
diff --git a/drivers/acorn/scsi/msgqueue.h b/drivers/acorn/scsi/msgqueue.h
index 8016dcf4e..25fa2796f 100644
--- a/drivers/acorn/scsi/msgqueue.h
+++ b/drivers/acorn/scsi/msgqueue.h
@@ -1,7 +1,7 @@
/*
* msgqueue.h: message queue handling
*
- * (c) 1997 Russell King
+ * Copyright (C) 1997 Russell King
*/
#ifndef MSGQUEUE_H
#define MSGQUEUE_H
diff --git a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c
index 59d83dc1a..cd07f7da0 100644
--- a/drivers/acorn/scsi/powertec.c
+++ b/drivers/acorn/scsi/powertec.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/drivers/scsi/powertec.c
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
@@ -13,6 +13,7 @@
* 15-04-1998 RMK Only do PIO if FAS216 will allow it.
* 02-05-1998 RMK Moved DMA sg list into per-interface structure.
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
+ * 02-04-2000 RMK Updated for new error handling code.
*/
#include <linux/module.h>
@@ -67,7 +68,7 @@
*/
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 2
+#define VER_PATCH 5
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("Powertec SCSI driver");
@@ -345,25 +346,11 @@ const char *powertecscsi_info(struct Scsi_Host *host)
static char string[100], *p;
p = string;
- p += sprintf(string, "%s at port %lX ",
- host->hostt->name, host->io_port);
-
- if (host->irq != NO_IRQ)
- p += sprintf(p, "irq %d ", host->irq);
- else
- p += sprintf(p, "NO IRQ ");
-
- if (host->dma_channel != NO_DMA)
- p += sprintf(p, "dma %d ", host->dma_channel);
- else
- p += sprintf(p, "NO DMA ");
-
- p += sprintf(p, "v%d.%d.%d scsi %s",
+ p += sprintf(p, "%s ", host->hostt->name);
+ p += fas216_info(&info->info, p);
+ p += sprintf(p, "v%d.%d.%d terminators o%s",
VER_MAJOR, VER_MINOR, VER_PATCH,
- info->info.scsi.type);
-
- p += sprintf(p, " terminators %s",
- info->control.terms ? "on" : "off");
+ info->control.terms ? "n" : "ff");
return string;
}
@@ -403,13 +390,13 @@ powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
* int length, int host_no, int inout)
* Purpose : Return information about the driver to a user process accessing
* the /proc filesystem.
- * Params : buffer - a buffer to write information to
- * start - a pointer into this buffer set by this routine to the start
- * of the required information.
- * offset - offset into information that we have read upto.
- * length - length of buffer
+ * Params : buffer - a buffer to write information to
+ * start - a pointer into this buffer set by this routine to the start
+ * of the required information.
+ * offset - offset into information that we have read upto.
+ * length - length of buffer
* host_no - host number to return information for
- * inout - 0 for reading, 1 for writing.
+ * inout - 0 for reading, 1 for writing.
* Returns : length of data written to buffer.
*/
int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
@@ -437,16 +424,14 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
pos = sprintf(buffer,
"PowerTec SCSI driver version %d.%d.%d\n",
VER_MAJOR, VER_MINOR, VER_PATCH);
- pos += sprintf(buffer + pos,
- "Address: %08lX IRQ : %d DMA : %d\n"
- "FAS : %-10s TERM: %-3s\n\n"
- "Statistics:\n",
- host->io_port, host->irq, host->dma_channel,
- info->info.scsi.type, info->control.terms ? "on" : "off");
+
+ pos += fas216_print_host(&info->info, buffer + pos);
+ pos += sprintf(buffer + pos, "Term : o%s\n",
+ info->control.terms ? "n" : "ff");
pos += fas216_print_stats(&info->info, buffer + pos);
- pos += sprintf (buffer+pos, "\nAttached devices:\n");
+ pos += sprintf(buffer+pos, "\nAttached devices:\n");
for (scd = host->host_queue; scd; scd = scd->next) {
pos += fas216_print_device(&info->info, scd, buffer + pos);
diff --git a/drivers/acorn/scsi/powertec.h b/drivers/acorn/scsi/powertec.h
index bf9a8afc8..4b0387b89 100644
--- a/drivers/acorn/scsi/powertec.h
+++ b/drivers/acorn/scsi/powertec.h
@@ -1,7 +1,7 @@
/*
* PowerTec SCSI driver
*
- * Copyright (C) 1997-1998 Russell King
+ * Copyright (C) 1997-2000 Russell King
*/
#ifndef POWERTECSCSI_H
#define POWERTECSCSI_H
@@ -38,28 +38,25 @@ extern int powertecscsi_proc_info (char *buffer, char **start, off_t offset,
#include "fas216.h"
-#define POWERTECSCSI { \
-proc_info: powertecscsi_proc_info, \
-name: "PowerTec SCSI", \
-detect: powertecscsi_detect, /* detect */ \
-release: powertecscsi_release, /* release */ \
-info: powertecscsi_info, /* info */ \
-command: fas216_command, /* command */ \
-queuecommand: fas216_queue_command, /* queuecommand */ \
-abort: fas216_abort, /* abort */ \
-reset: fas216_reset, /* reset */ \
-bios_param: scsicam_bios_param, /* biosparam */ \
-can_queue: CAN_QUEUE, /* can queue */ \
-this_id: SCSI_ID, /* scsi host id */ \
-sg_tablesize: SG_ALL, /* sg_tablesize */ \
-cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \
-use_clustering: ENABLE_CLUSTERING, \
-eh_strategy_handler: NULL, \
-eh_host_reset_handler: fas216_eh_host_reset, \
-eh_bus_reset_handler: fas216_eh_bus_reset, \
-eh_device_reset_handler: fas216_eh_device_reset, \
-eh_abort_handler: fas216_eh_abort, \
-use_new_eh_code: 0 \
+#define POWERTECSCSI { \
+proc_info: powertecscsi_proc_info, \
+name: "PowerTec SCSI", \
+detect: powertecscsi_detect, \
+release: powertecscsi_release, \
+info: powertecscsi_info, \
+bios_param: scsicam_bios_param, \
+can_queue: CAN_QUEUE, \
+this_id: SCSI_ID, \
+sg_tablesize: SG_ALL, \
+cmd_per_lun: CMD_PER_LUN, \
+use_clustering: ENABLE_CLUSTERING, \
+command: fas216_command, \
+queuecommand: fas216_queue_command, \
+eh_host_reset_handler: fas216_eh_host_reset, \
+eh_bus_reset_handler: fas216_eh_bus_reset, \
+eh_device_reset_handler: fas216_eh_device_reset, \
+eh_abort_handler: fas216_eh_abort, \
+use_new_eh_code: 1 \
}
#ifndef HOSTS_C
diff --git a/drivers/acorn/scsi/queue.h b/drivers/acorn/scsi/queue.h
index f39816ccb..961a3f268 100644
--- a/drivers/acorn/scsi/queue.h
+++ b/drivers/acorn/scsi/queue.h
@@ -1,7 +1,7 @@
/*
* queue.h: queue handling
*
- * (c) 1997 Russell King
+ * Copyright (C) 1997 Russell King
*/
#ifndef QUEUE_H
#define QUEUE_H
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 96c022842..1fec6e006 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -45,10 +45,7 @@
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
-
-#ifdef CONFIG_ATM_FORE200E_PCA
#include <linux/pci.h>
-#endif
#ifdef CONFIG_ATM_FORE200E_SBA
#include <asm/idprom.h>
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index cadc7eca7..146cbce88 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -12,9 +12,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then
tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
fi
if [ "$CONFIG_MAC" = "y" ]; then
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP
- fi
+ dep_bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP $CONFIG_EXPERIMENTAL
fi
if [ "$CONFIG_MCA" = "y" ]; then
tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
@@ -30,36 +28,28 @@ if [ "$CONFIG_ATARI" = "y" ]; then
tristate ' Atari SLM laser printer support' CONFIG_ATARI_SLM
fi
fi
-tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
+dep_tristate 'XT hard disk support' CONFIG_BLK_DEV_XD $CONFIG_ISA
dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT
if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
source drivers/block/paride/Config.in
fi
-
-if [ "$CONFIG_PCI" = "y" ]; then
- tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
- tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960
-fi
+dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
+dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
comment 'Additional Block Devices'
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-if [ "$CONFIG_NET" = "y" ]; then
- tristate 'Network block device support' CONFIG_BLK_DEV_NBD
-fi
+dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+
bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
-if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
- tristate ' Linear (append) mode' CONFIG_MD_LINEAR
- tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED
-# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
-# tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5
+dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD
+dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED $CONFIG_BLK_DEV_MD
+#dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING $CONFIG_BLK_DEV_MD
+#dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD
+if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
+ bool ' Boot support (linear, striped)' CONFIG_MD_BOOT
fi
-#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-# bool ' Boot support (linear, striped)' CONFIG_MD_BOOT
-#fi
tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
- bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
-fi
+dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
endmenu
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 431860f44..4adbbb313 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -481,7 +481,7 @@ static void attempt_merge(request_queue_t * q,
elevator_merge_requests(&q->elevator, req, next);
req->bhtail->b_reqnext = next->bh;
req->bhtail = next->bhtail;
- req->nr_sectors += next->nr_sectors;
+ req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
next->rq_status = RQ_INACTIVE;
list_del(&next->queue);
wake_up (&wait_for_request);
@@ -685,7 +685,7 @@ static inline void __make_request(request_queue_t * q, int rw,
break;
req->bhtail->b_reqnext = bh;
req->bhtail = bh;
- req->nr_sectors += count;
+ req->nr_sectors = req->hard_nr_sectors += count;
drive_stat_acct(req, count, 0);
elevator_merge_after(elevator, req, latency);
@@ -714,8 +714,8 @@ static inline void __make_request(request_queue_t * q, int rw,
req->bh = bh;
req->buffer = bh->b_data;
req->current_nr_sectors = count;
- req->sector = sector;
- req->nr_sectors += count;
+ req->sector = req->hard_sector = sector;
+ req->nr_sectors = req->hard_nr_sectors += count;
drive_stat_acct(req, count, 0);
elevator_merge_before(elevator, req, latency);
@@ -754,8 +754,8 @@ get_rq:
/* fill up the request-info, and add it to the queue */
req->cmd = rw;
req->errors = 0;
- req->sector = sector;
- req->nr_sectors = count;
+ req->hard_sector = req->sector = sector;
+ req->hard_nr_sectors = req->nr_sectors = count;
req->current_nr_sectors = count;
req->nr_segments = 1; /* Always 1 for a new request. */
req->nr_hw_segments = 1; /* Always 1 for a new request. */
@@ -920,23 +920,21 @@ int end_that_request_first (struct request *req, int uptodate, char *name)
int nsect;
req->errors = 0;
- if (!uptodate) {
+ if (!uptodate)
printk("end_request: I/O error, dev %s (%s), sector %lu\n",
kdevname(req->rq_dev), name, req->sector);
- if ((bh = req->bh) != NULL) {
- nsect = bh->b_size >> 9;
- req->nr_sectors--;
- req->nr_sectors &= ~(nsect - 1);
- req->sector += nsect;
- req->sector &= ~(nsect - 1);
- }
- }
if ((bh = req->bh) != NULL) {
+ nsect = bh->b_size >> 9;
req->bh = bh->b_reqnext;
bh->b_reqnext = NULL;
bh->b_end_io(bh, uptodate);
if ((bh = req->bh) != NULL) {
+ req->hard_sector += nsect;
+ req->hard_nr_sectors -= nsect;
+ req->sector = req->hard_sector;
+ req->nr_sectors = req->hard_nr_sectors;
+
req->current_nr_sectors = bh->b_size >> 9;
if (req->nr_sectors < req->current_nr_sectors) {
req->nr_sectors = req->current_nr_sectors;
@@ -1073,6 +1071,12 @@ int __init blk_dev_init(void)
#ifdef CONFIG_BLK_DEV_NBD
nbd_init();
#endif
+#ifdef CONFIG_MDISK
+ mdisk_init();
+#endif
+#ifdef CONFIG_DASD
+ dasd_init();
+#endif
return 0;
};
diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c
index 0986ff7df..0c590db73 100644
--- a/drivers/block/lvm.c
+++ b/drivers/block/lvm.c
@@ -931,7 +931,7 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file,
printk(KERN_DEBUG
"%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
#endif
- if (put_user(lv->lv_read_ahead, (long *)arg))
+ if (put_user(lv_ptr->lv_read_ahead, (long *)arg))
return -EFAULT;
break;
diff --git a/drivers/block/md.c b/drivers/block/md.c
index dd8a83764..48796b402 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -1805,6 +1805,136 @@ out:
#undef OUT
+/* support old ioctls/init - cold add only */
+int do_md_add(mddev_t *mddev, kdev_t dev)
+{
+ int err;
+ mdk_rdev_t *rdev;
+
+ if (mddev->sb || mddev->pers)
+ return -EBUSY;
+ err = md_import_device(dev, 0);
+ if (err) return err;
+ rdev = find_rdev_all(dev);
+ if (!rdev) {
+ MD_BUG();
+ return -EINVAL;
+ }
+ rdev->old_dev = dev;
+ rdev->desc_nr = mddev->nb_dev;
+ bind_rdev_to_array(rdev, mddev);
+ return 0;
+}
+
+#define SET_SB(x,v) mddev->sb->x = v
+#define SET_RSB(x,y) mddev->sb->disks[nr].x = y
+static void autorun_array (mddev_t *mddev);
+int do_md_start(mddev_t *mddev, int info)
+{
+ int pers = (info & 0xFF0000UL)>>16;
+// int fault= (info & 0x00FF00UL)>>8;
+ int factor=(info & 0x0000FFUL);
+
+ struct md_list_head *tmp;
+ mdk_rdev_t *rdev, *rdev0=NULL;
+ int err = 0;
+
+ if (mddev->sb) {
+ printk("array md%d already has superbloc!!\n",
+ mdidx(mddev));
+ return -EBUSY;
+ }
+ if (pers==1 || pers==2) {
+ /* non-persistant super block */
+ int devs = mddev->nb_dev;
+ if (alloc_array_sb(mddev))
+ return -ENOMEM;
+ mddev->sb->major_version = MD_MAJOR_VERSION;
+ mddev->sb->minor_version = MD_MINOR_VERSION;
+ mddev->sb->patch_version = MD_PATCHLEVEL_VERSION;
+ mddev->sb->ctime = CURRENT_TIME;
+
+ SET_SB(level,pers_to_level(pers));
+ SET_SB(size,0);
+ SET_SB(nr_disks, devs);
+ SET_SB(raid_disks, devs);
+ SET_SB(md_minor,mdidx(mddev));
+ SET_SB(not_persistent, 1);
+
+
+ SET_SB(state, 1<<MD_SB_CLEAN);
+ SET_SB(active_disks, devs);
+ SET_SB(working_disks, devs);
+ SET_SB(failed_disks, 0);
+ SET_SB(spare_disks, 0);
+
+ SET_SB(layout,0);
+ SET_SB(chunk_size, 1<<(factor+PAGE_SHIFT));
+
+ mddev->sb->md_magic = MD_SB_MAGIC;
+
+ /*
+ * Generate a 128 bit UUID
+ */
+ get_random_bytes(&mddev->sb->set_uuid0, 4);
+ get_random_bytes(&mddev->sb->set_uuid1, 4);
+ get_random_bytes(&mddev->sb->set_uuid2, 4);
+ get_random_bytes(&mddev->sb->set_uuid3, 4);
+
+ /* add each disc */
+ ITERATE_RDEV(mddev,rdev,tmp) {
+ int nr, size;
+ nr = rdev->desc_nr;
+ SET_RSB(number,nr);
+ SET_RSB(major,MAJOR(rdev->dev));
+ SET_RSB(minor,MINOR(rdev->dev));
+ SET_RSB(raid_disk,nr);
+ SET_RSB(state,6); /* ACTIVE|SYNC */
+ size = calc_dev_size(rdev->dev, mddev, 0);
+ rdev->sb_offset = calc_dev_sboffset(rdev->dev, mddev, 0);
+
+ if (!mddev->sb->size || (mddev->sb->size > size))
+ mddev->sb->size = size;
+ }
+ sync_sbs(mddev);
+ err = do_md_run(mddev);
+ if (err)
+ do_md_stop(mddev, 0);
+ } else {
+ /* persistant super block - ignore the info and read the superblocks */
+ ITERATE_RDEV(mddev,rdev,tmp) {
+ if ((err = read_disk_sb(rdev))) {
+ printk("md: could not read %s's sb, not importing!\n",
+ partition_name(rdev->dev));
+ break;
+ }
+ if ((err = check_disk_sb(rdev))) {
+ printk("md: %s has invalid sb, not importing!\n",
+ partition_name(rdev->dev));
+ break;
+ }
+ rdev->desc_nr = rdev->sb->this_disk.number;
+ if (!rdev0) rdev0=rdev;
+ if (!uuid_equal(rdev0, rdev)) {
+ printk("%s has different UUID to %s .. dropping\n",
+ partition_name(rdev->dev),
+ partition_name(rdev0->dev));
+ err = -EINVAL;
+ break;
+ }
+ if (!sb_equal(rdev0->sb, rdev->sb)) {
+ printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev));
+ err = -EINVAL;
+ break;
+ }
+ }
+ if (!err)
+ autorun_array(mddev);
+ }
+ return err;
+}
+#undef SET_SB
+#undef SET_RSB
/*
* We have to safely support old arrays too.
*/
@@ -2573,6 +2703,58 @@ static int md_ioctl (struct inode *inode, struct file *file,
}
default:
}
+ /* handle "old style" ioctls */
+ switch (cmd)
+ {
+ case START_MD:
+ if (!mddev)
+ return -ENODEV;
+ err = lock_mddev(mddev);
+ if (err) {
+ printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
+ goto abort;
+ }
+ err = do_md_start(mddev, (int) arg);
+ if (err) {
+ printk("couldn't mdstart\n");
+ goto abort_unlock;
+ }
+ goto done_unlock;
+ case STOP_MD:
+ if (!mddev)
+ return -ENODEV;
+ err = lock_mddev(mddev);
+ if (err) {
+ printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
+ goto abort_unlock;
+ }
+ err = do_md_stop(mddev, 0);
+ if (err) {
+ printk("couldn't mdstop\n");
+ goto abort_unlock;
+ }
+ goto done_unlock;
+ case REGISTER_DEV:
+ /* add this device to an unstarted array,
+ * create the array if needed */
+ if (!mddev)
+ mddev = alloc_mddev(dev);
+ if (!mddev) {
+ err = -ENOMEM;
+ goto abort;
+ }
+ err = lock_mddev(mddev);
+ if (err) {
+ printk("ioctl, reason %d, cmd %d\n", err, cmd);
+ goto abort;
+ }
+ err = do_md_add(mddev, to_kdev_t((dev_t) arg));
+ if (err) {
+ printk("do_md_add failed %d\n", err);
+ goto abort_unlock;
+ }
+ goto done_unlock;
+ }
switch (cmd)
{
@@ -2593,7 +2775,7 @@ static int md_ioctl (struct inode *inode, struct file *file,
err = set_array_info(mddev, (void *)arg);
if (err) {
printk("couldnt set array info. %d\n", err);
- goto abort;
+ goto abort_unlock;
}
goto done_unlock;
@@ -3188,10 +3370,11 @@ void md__init raid_setup(char *str, int *ints)
}
#ifdef CONFIG_MD_BOOT
+#define MAX_MD_BOOT_DEVS 16
struct {
unsigned long set;
- int pers[MAX_MD_DEVS];
- kdev_t devices[MAX_MD_DEVS][MAX_REAL];
+ int pers[MAX_MD_BOOT_DEVS];
+ kdev_t devices[MAX_MD_BOOT_DEVS][MAX_REAL];
} md_setup_args md__initdata = {
0,{0},{{0}}
};
@@ -3219,7 +3402,7 @@ static int __init md_setup(char *str)
get_option(&str, &fault) != 2) {
printk("md: Too few arguments supplied to md=.\n");
return 0;
- } else if (minor >= MAX_MD_DEVS) {
+ } else if (minor >= MAX_MD_BOOT_DEVS) {
printk ("md: Minor device number too high.\n");
return 0;
} else if (md_setup_args.set & (1 << minor)) {
@@ -3229,13 +3412,13 @@ static int __init md_setup(char *str)
switch(level) {
#ifdef CONFIG_MD_LINEAR
case -1:
- level = LINEAR;
+ level = LINEAR<<16;
pername = "linear";
break;
#endif
#ifdef CONFIG_MD_STRIPED
case 0:
- level = STRIPED;
+ level = STRIPED<<16;
pername = "striped";
break;
#endif
@@ -3263,9 +3446,9 @@ static int __init md_setup(char *str)
printk ("md: Will configure md%d (%s) from %s, below.\n",
minor, pername, devnames);
md_setup_args.devices[minor][i] = (kdev_t) 0;
- md_setup_args.pers[minor] = level | factor | (fault << FAULT_SHIFT);
+ md_setup_args.pers[minor] = level | factor | (fault << 8);
md_setup_args.set |= (1 << minor);
- return 0;
+ return 1;
}
#endif
@@ -3273,7 +3456,7 @@ static void md_geninit (void)
{
int i;
- for(i = 0; i < MAX_MD_DEVS; i++) {
+ for(i = 0; i < MAX_MD_BOOT_DEVS; i++) {
md_blocksizes[i] = 1024;
md_size[i] = 0;
md_maxreadahead[i] = MD_READAHEAD;
@@ -3344,20 +3527,20 @@ int md__init md_init (void)
}
#ifdef CONFIG_MD_BOOT
-static void __init md_setup_drive(void)
+void __init md_setup_drive(void)
{
- if(md_setup_args.set)
- do_md_setup(md_setup_args.str, md_setup_args.ints);
int minor, i;
kdev_t dev;
+ mddev_t*mddev;
- for (minor = 0; minor < MAX_MD_DEVS; minor++) {
+ for (minor = 0; minor < MAX_MD_BOOT_DEVS; minor++) {
if ((md_setup_args.set & (1 << minor)) == 0)
continue;
printk("md: Loading md%d.\n", minor);
+ mddev = alloc_mddev(MKDEV(MD_MAJOR,minor));
for (i = 0; (dev = md_setup_args.devices[minor][i]); i++)
- do_md_add (minor, dev);
- do_md_run (minor, md_setup_args.pers[minor]);
+ do_md_add (mddev, dev);
+ do_md_start (mddev, md_setup_args.pers[minor]);
}
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 0c3f5429f..b21be6bd2 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -350,6 +350,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
{
struct nbd_device *lo;
int dev, error, temp;
+ struct request sreq ;
/* Anyone capable of this syscall can do *real bad* things */
@@ -363,6 +364,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
lo = &nbd_dev[dev];
switch (cmd) {
+ case NBD_DISCONNECT:
+ printk("NBD_DISCONNECT\n") ;
+ sreq.cmd=2 ; /* shutdown command */
+ if (!lo->sock) return -EINVAL ;
+ nbd_send_req(lo->sock,&sreq) ;
+ return 0 ;
+
case NBD_CLEAR_SOCK:
down(&lo->queue_lock);
nbd_clear_que(lo);
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 878709944..38279282f 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -765,7 +765,7 @@ static void do_pcd_request (request_queue_t * q)
pcd_unit = unit;
}
pcd_sector = CURRENT->sector;
- pcd_count = CURRENT->nr_sectors;
+ pcd_count = CURRENT->current_nr_sectors;
pcd_buf = CURRENT->buffer;
pcd_busy = 1;
ps_set_intr(do_pcd_read,0,0,nice);
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index f40958ecd..4676250dd 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -385,9 +385,62 @@ void pd_init_units( void )
}
}
+static inline int pd_new_segment(request_queue_t *q, struct request *req, int max_segments)
+{
+ if (max_segments > cluster)
+ max_segments = cluster;
+
+ if (req->nr_segments < max_segments) {
+ req->nr_segments++;
+ q->elevator.nr_segments++;
+ return 1;
+ }
+ return 0;
+}
+
+static int pd_back_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+ return 1;
+ return pd_new_segment(q, req, max_segments);
+}
+
+static int pd_front_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (bh->b_data + bh->b_size == req->bh->b_data)
+ return 1;
+ return pd_new_segment(q, req, max_segments);
+}
+
+static int pd_merge_requests_fn(request_queue_t *q, struct request *req,
+ struct request *next, int max_segments)
+{
+ int total_segments = req->nr_segments + next->nr_segments;
+ int same_segment;
+
+ if (max_segments > cluster)
+ max_segments = cluster;
+
+ same_segment = 0;
+ if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) {
+ total_segments--;
+ same_segment = 1;
+ }
+
+ if (total_segments > max_segments)
+ return 0;
+
+ q->elevator.nr_segments -= same_segment;
+ req->nr_segments = total_segments;
+ return 1;
+}
+
int pd_init (void)
{ int i;
+ request_queue_t * q;
if (disable) return -1;
if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) {
@@ -395,7 +448,11 @@ int pd_init (void)
name,major);
return -1;
}
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+ q = BLK_DEFAULT_QUEUE(MAJOR_NR);
+ blk_init_queue(q, DEVICE_REQUEST);
+ q->back_merge_fn = pd_back_merge_fn;
+ q->front_merge_fn = pd_front_merge_fn;
+ q->merge_requests_fn = pd_merge_requests_fn;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
pd_gendisk.major = major;
@@ -865,7 +922,6 @@ static int pd_ready( void )
static void do_pd_request (request_queue_t * q)
{ struct buffer_head * bh;
- struct request * req;
int unit;
if (pd_busy) return;
@@ -876,12 +932,10 @@ repeat:
pd_dev = MINOR(CURRENT->rq_dev);
pd_unit = unit = DEVICE_NR(CURRENT->rq_dev);
pd_block = CURRENT->sector;
- pd_count = CURRENT->nr_sectors;
+ pd_run = CURRENT->nr_sectors;
+ pd_count = CURRENT->current_nr_sectors;
bh = CURRENT->bh;
- req = CURRENT;
- if (bh->b_reqnext)
- printk("%s: OUCH: b_reqnext != NULL\n",PD.name);
if ((pd_dev >= PD_DEVS) ||
((pd_block+pd_count) > pd_hd[pd_dev].nr_sects)) {
@@ -890,14 +944,6 @@ repeat:
}
pd_cmd = CURRENT->cmd;
- pd_run = pd_count;
- while ((pd_run <= cluster) &&
- (req = blkdev_next_request(req)) &&
- (pd_block+pd_run == req->sector) &&
- (pd_cmd == req->cmd) &&
- (pd_dev == MINOR(req->rq_dev)))
- pd_run += req->nr_sectors;
-
pd_poffs = pd_hd[pd_dev].start_sect;
pd_block += pd_poffs;
pd_buf = CURRENT->buffer;
@@ -932,7 +978,7 @@ static void pd_next_buf( int unit )
printk("%s: OUCH: request list changed unexpectedly\n",
PD.name);
- pd_count = CURRENT->nr_sectors;
+ pd_count = CURRENT->current_nr_sectors;
pd_buf = CURRENT->buffer;
spin_unlock_irqrestore(&io_request_lock,saved_flags);
}
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 4e7a5aaf4..53f6ca3df 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -339,9 +339,62 @@ void pf_init_units( void )
}
}
+static inline int pf_new_segment(request_queue_t *q, struct request *req, int max_segments)
+{
+ if (max_segments > cluster)
+ max_segments = cluster;
+
+ if (req->nr_segments < max_segments) {
+ req->nr_segments++;
+ q->elevator.nr_segments++;
+ return 1;
+ }
+ return 0;
+}
+
+static int pf_back_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+ return 1;
+ return pf_new_segment(q, req, max_segments);
+}
+
+static int pf_front_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (bh->b_data + bh->b_size == req->bh->b_data)
+ return 1;
+ return pf_new_segment(q, req, max_segments);
+}
+
+static int pf_merge_requests_fn(request_queue_t *q, struct request *req,
+ struct request *next, int max_segments)
+{
+ int total_segments = req->nr_segments + next->nr_segments;
+ int same_segment;
+
+ if (max_segments > cluster)
+ max_segments = cluster;
+
+ same_segment = 0;
+ if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) {
+ total_segments--;
+ same_segment = 1;
+ }
+
+ if (total_segments > max_segments)
+ return 0;
+
+ q->elevator.nr_segments -= same_segment;
+ req->nr_segments = total_segments;
+ return 1;
+}
+
int pf_init (void) /* preliminary initialisation */
{ int i;
+ request_queue_t * q;
if (disable) return -1;
@@ -355,7 +408,11 @@ int pf_init (void) /* preliminary initialisation */
major);
return -1;
}
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+ q = BLK_DEFAULT_QUEUE(MAJOR_NR);
+ blk_init_queue(q, DEVICE_REQUEST);
+ q->back_merge_fn = pf_back_merge_fn;
+ q->front_merge_fn = pf_front_merge_fn;
+ q->merge_requests_fn = pf_merge_requests_fn;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024;
@@ -849,7 +906,6 @@ static int pf_ready( void )
static void do_pf_request (request_queue_t * q)
{ struct buffer_head * bh;
- struct request * req;
int unit;
if (pf_busy) return;
@@ -859,12 +915,10 @@ repeat:
pf_unit = unit = DEVICE_NR(CURRENT->rq_dev);
pf_block = CURRENT->sector;
- pf_count = CURRENT->nr_sectors;
+ pf_run = CURRENT->nr_sectors;
+ pf_count = CURRENT->current_nr_sectors;
bh = CURRENT->bh;
- req = CURRENT;
- if (bh->b_reqnext)
- printk("%s: OUCH: b_reqnext != NULL\n",PF.name);
if ((pf_unit >= PF_UNITS) || (pf_block+pf_count > PF.capacity)) {
end_request(0);
@@ -872,14 +926,6 @@ repeat:
}
pf_cmd = CURRENT->cmd;
- pf_run = pf_count;
- while ((pf_run <= cluster) &&
- (req = blkdev_next_request(req)) &&
- (pf_block+pf_run == req->sector) &&
- (pf_cmd == req->cmd) &&
- (pf_unit == DEVICE_NR(req->rq_dev)))
- pf_run += req->nr_sectors;
-
pf_buf = CURRENT->buffer;
pf_retries = 0;
@@ -912,7 +958,7 @@ static void pf_next_buf( int unit )
printk("%s: OUCH: request list changed unexpectedly\n",
PF.name);
- pf_count = CURRENT->nr_sectors;
+ pf_count = CURRENT->current_nr_sectors;
pf_buf = CURRENT->buffer;
spin_unlock_irqrestore(&io_request_lock,saved_flags);
}
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index a51dcd36f..11a06ef61 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -333,7 +333,8 @@ static int rd_open(struct inode * inode, struct file * filp)
* Immunize device against invalidate_buffers() and prune_icache().
*/
if (rd_inode[DEVICE_NR(inode->i_rdev)] == NULL) {
- if((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
+ if (!inode->i_bdev) return -ENXIO;
+ if ((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
atomic_inc(&rd_inode[DEVICE_NR(inode->i_rdev)]->i_bdev->bd_openers);
}
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index fde487ecd..65d87930d 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -1059,7 +1059,7 @@ static void __init xd_override_init_drive (u_char drive)
}
/* xd_setup: initialise controler from command line parameters */
-void __init xd_setup (char *command,int *integers)
+void __init do_xd_setup (int *integers)
{
switch (integers[0]) {
case 4: if (integers[4] < 0)
@@ -1079,21 +1079,6 @@ void __init xd_setup (char *command,int *integers)
xd_maxsectors = 0x01;
}
-#ifndef MODULE
-/* xd_manual_geo_init: initialise drive geometry from command line parameters
- (used only for WD drives) */
-void __init xd_manual_geo_init (char *command,int *integers)
-{
- int i;
- if (integers[0]%3 != 0) {
- printk("xd: incorrect number of parameters for xd_geo\n");
- return;
- }
- for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
- xd_geo[i] = integers[i+1];
-}
-#endif /* MODULE */
-
/* xd_setparam: set the drive characteristics */
static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
{
@@ -1149,7 +1134,7 @@ int init_module(void)
if(((xd[i] = xd[i-1]) >= 0) && !count)
count = i;
if((xd[0] = count))
- xd_setup(NULL, xd);
+ do_xd_setup(xd);
if (error = xd_init())
return error;
@@ -1191,6 +1176,30 @@ void cleanup_module(void)
}
#else
+static int __init xd_setup (char *str)
+{
+ int ints[5];
+ get_options (str, ARRAY_SIZE (ints), ints);
+ do_xd_setup (ints);
+ return 1;
+}
+
+/* xd_manual_geo_init: initialise drive geometry from command line parameters
+ (used only for WD drives) */
+static int __init xd_manual_geo_init (char *str)
+{
+ int i, integers[1 + 3*XD_MAXDRIVES];
+
+ get_options (str, ARRAY_SIZE (ints), ints);
+ if (integers[0]%3 != 0) {
+ printk("xd: incorrect number of parameters for xd_geo\n");
+ return 1;
+ }
+ for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
+ xd_geo[i] = integers[i+1];
+ return 1;
+}
+
__setup ("xd=", xd_setup);
__setup ("xd_geo=", xd_manual_geo_init);
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 21720c81a..d6e0a55bd 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -110,6 +110,7 @@ bool 'Watchdog Timer Support' CONFIG_WATCHDOG
if [ "$CONFIG_WATCHDOG" != "n" ]; then
bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
tristate ' WDT Watchdog timer' CONFIG_WDT
+ tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI
if [ "$CONFIG_WDT" != "n" ]; then
bool ' WDT501 features' CONFIG_WDT_501
if [ "$CONFIG_WDT_501" = "y" ]; then
@@ -152,7 +153,7 @@ comment 'Video For Linux'
tristate 'Video For Linux' CONFIG_VIDEO_DEV
if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
- dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT
+ dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C
comment 'Radio Adapters'
dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
@@ -209,6 +210,15 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
fi
fi
+ dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
+ if [ "CONFIG_PARPORT_1284" != "n" ]; then
+ dep_tristate 'CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
+ fi
+ if [ "$CONFIG_USB" != "n" ]; then
+ dep_tristate 'CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB
+ fi
+ fi
dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C
dep_tristate ' SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 32c66c442..879e2bb92 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -38,7 +38,7 @@ obj-y += tty_io.o n_tty.o tty_ioctl.o mem.o raw.o pty.o misc.o random.o
export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \
misc.o pty.o random.o selection.o serial.o videodev.o \
- tty_io.o bttv.o
+ tty_io.o bttv.o cpia.o
KEYMAP =defkeymap.o
KEYBD =pc_keyb.o
@@ -171,6 +171,7 @@ obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o
obj-$(CONFIG_PC110_PAD) += pc110pad.o
obj-$(CONFIG_WDT) += wdt.o
+obj-$(CONFIG_WDTPCI) += wdt_pci.o
obj-$(CONFIG_RTC) += rtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
ifeq ($(CONFIG_PPC),)
@@ -179,7 +180,7 @@ endif
obj-$(CONFIG_VIDEO_DEV) += videodev.o
-obj-$(CONFIG_21825_WATCHDOG) += wdt285.o
+obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_DS1620) += ds1620.o
@@ -252,6 +253,9 @@ obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
obj-$(CONFIG_VIDEO_VINO) += vino.o
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
+obj-$(CONFIG_VIDEO_CPIA) += cpia.o
+obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
+obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index fc4312f64..447716420 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -1764,6 +1764,30 @@ static struct {
#endif /* CONFIG_AGP_INTEL */
#ifdef CONFIG_AGP_SIS
+ { PCI_DEVICE_ID_SI_630,
+ PCI_VENDOR_ID_SI,
+ SIS_GENERIC,
+ "SiS",
+ "Generic",
+ sis_generic_setup },
+ { PCI_DEVICE_ID_SI_540,
+ PCI_VENDOR_ID_SI,
+ SIS_GENERIC,
+ "SiS",
+ "Generic",
+ sis_generic_setup },
+ { PCI_DEVICE_ID_SI_620,
+ PCI_VENDOR_ID_SI,
+ SIS_GENERIC,
+ "SiS",
+ "Generic",
+ sis_generic_setup },
+ { PCI_DEVICE_ID_SI_530,
+ PCI_VENDOR_ID_SI,
+ SIS_GENERIC,
+ "SiS",
+ "Generic",
+ sis_generic_setup },
{ 0,
PCI_VENDOR_ID_SI,
SIS_GENERIC,
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 65be2102f..3d84dd0ad 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -1,7 +1,7 @@
/* Derived from Applicom driver ac.c for SCO Unix */
/* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */
/* Dave@mvhi.com 30/8/98 */
-/* $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $ */
+/* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $ */
/* This module is for Linux 2.1 and 2.2 series kernels. */
/*****************************************************************************/
/* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt */
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/malloc.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -29,15 +30,29 @@
#include <linux/pci.h>
#include <linux/wait.h>
#include <linux/init.h>
+#include <linux/compatmac.h>
+
#include "applicom.h"
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < 0x20300
+/* These probably want adding to <linux/compatmac.h> */
+#define init_waitqueue_head(x) do { *(x) = NULL; } while (0);
+#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
+#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x
+#define __setup(x,y) /* */
+#else
+#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
#endif
+/* NOTE: We use for loops with {write,read}b() instead of
+ memcpy_{from,to}io throughout this driver. This is because
+ the board doesn't correctly handle word accesses - only
+ bytes.
+*/
+
+
#undef DEBUG
-#define DEVPRIO PZERO+8
-#define FALSE 0
-#define TRUE ~FALSE
+
#define MAX_BOARD 8 /* maximum of pc board possible */
#define MAX_ISA_BOARD 4
#define LEN_RAM_IO 0x800
@@ -52,7 +67,9 @@
#endif
static char *applicom_pci_devnames[] = {
- "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"
+ "PCI board",
+ "PCI2000IBS / PCI2000CAN",
+ "PCI2000PFB"
};
MODULE_AUTHOR("David Woodhouse & Applicom International");
@@ -68,12 +85,9 @@ MODULE_SUPPORTED_DEVICE("ac");
struct applicom_board {
unsigned long PhysIO;
unsigned long RamIO;
-#if LINUX_VERSION_CODE > 0x20300
wait_queue_head_t FlagSleepSend;
-#else
- struct wait_queue *FlagSleepSend;
-#endif
long irq;
+ spinlock_t mutex;
} apbs[MAX_BOARD];
static unsigned int irq = 0; /* interrupt number IRQ */
@@ -81,22 +95,19 @@ static unsigned long mem = 0; /* physical segment of board */
static unsigned int numboards; /* number of installed boards */
static volatile unsigned char Dummy;
-#if LINUX_VERSION_CODE > 0x20300
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 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 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);
+static loff_t ac_llseek(struct file *, loff_t, int);
+static int ac_open(struct inode *, struct file *);
+static ssize_t ac_read (struct file *, char *, size_t, loff_t *);
+static ssize_t ac_write (struct file *, const char *, size_t, loff_t *);
+static int ac_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static int ac_release(struct inode *, struct file *);
+static void ac_interrupt(int, void *, struct pt_regs *);
struct file_operations ac_fops = {
llseek:ac_llseek,
@@ -113,24 +124,29 @@ struct miscdevice ac_miscdev = {
&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))
+ 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);
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);
+ 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);
+ 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;
}
@@ -138,11 +154,8 @@ int ac_register_board(unsigned long physloc, unsigned long loc, unsigned char bo
apbs[boardno].PhysIO = physloc;
apbs[boardno].RamIO = loc;
-#if LINUX_VERSION_CODE > 0x20300
init_waitqueue_head(&apbs[boardno].FlagSleepSend);
-#else
- apbs[boardno].FlagSleepSend = NULL;
-#endif
+ spin_lock_init(&apbs[boardno].mutex);
byte_reset_it = readb(loc + RAM_IT_TO_PC);
numboards++;
@@ -158,14 +171,17 @@ 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");
}
#endif /* MODULE */
@@ -176,20 +192,19 @@ int __init applicom_init(void)
struct pci_dev *dev = NULL;
void *RamIO;
int boardno;
-#if LINUX_VERSION_CODE > 0x20300
-#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
-#else
-#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
-#endif
- printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $\n");
+ printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 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;
+ while ( (dev = pci_find_class(PCI_CLASS_OTHERS << 16, dev))) {
+ if (dev->vendor != PCI_VENDOR_ID_APPLICOM)
+ continue;
+
+ if (dev->device > MAX_PCI_DEVICE_NUM || dev->device == 0)
+ continue;
+
RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
if (!RamIO) {
@@ -197,9 +212,12 @@ int __init applicom_init(void)
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);
+ 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))) {
+ 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;
@@ -236,9 +254,8 @@ int __init applicom_init(void)
RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
- if (!RamIO) {
+ if (!RamIO)
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);
@@ -248,39 +265,38 @@ int __init applicom_init(void)
continue;
}
- if (!(boardno = ac_register_board((unsigned long) mem + (LEN_RAM_IO * i), (unsigned long) RamIO, i + 1))) {
+ 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);
+ printk(KERN_NOTICE "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);
+ printk(KERN_WARNING "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
+ }
+ 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(KERN_WARNING"ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem);
-#if LINUX_VERSION_CODE > 0x20300
+ fin:
init_waitqueue_head(&FlagSleepRec);
-#else
- FlagSleepRec = NULL;
-#endif
+
WriteErrorCount = 0;
ReadErrorCount = 0;
DeviceErrorCount = 0;
- fin:
if (numboards) {
misc_register(&ac_miscdev);
for (i = 0; i < MAX_BOARD; i++) {
@@ -292,12 +308,18 @@ int __init applicom_init(void)
for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
- boardname[serial] = 0;
+ 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));
+ 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);
@@ -342,35 +364,41 @@ static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t
unsigned long flags; /* Current priority */
struct st_ram_io st_loc;
struct mailbox tmpmailbox;
+#ifdef DEBUG
+ int c;
+#endif
+ DECLARE_WAITQUEUE(wait, current);
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));
+ static int warncount = 5;
+ if (warncount) {
+ printk(KERN_INFO "Hmmm. write() of Applicom card, length %d != expected %d\n",
+ count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ warncount--;
+ }
return -EINVAL;
}
- if (copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) {
+ 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))) {
+
+ 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);
+ if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)
+ return -EINVAL;
+#ifdef DEBUG
+ printk("Write to applicom card #%d. struct st_ram_io follows:",
+ IndexCard+1);
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++) {
@@ -389,36 +417,48 @@ static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t
}
printk("\n");
- }
-
#endif
- save_flags(flags);
- cli(); /* disable interrupt */
+ spin_lock_irqsave(&apbs[IndexCard].mutex, flags);
- if (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { /* Test octet ready correct */
+ /* Test octet ready correct */
+ if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) {
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));
+ spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
+ printk(KERN_WARNING "APPLICOM driver write error board %d, DataFromPcReady = %d\n",
+ IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
DeviceErrorCount++;
return -EIO;
}
+
+ /* Place ourselves on the wait queue */
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait);
+
+ /* Check whether the card is ready for us */
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))
+ /* It's busy. Sleep. */
+
+ spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&apbs[IndexCard].FlagSleepSend,
+ &wait);
return -EINTR;
- save_flags(flags);
- cli();
}
+ spin_lock_irqsave(&apbs[IndexCard].mutex, flags);
+ }
+
+ /* We may not have actually slept */
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait);
+
writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
- // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox));
+ /* Which is best - lock down the pages with rawio and then
+ copy directly, or use bounce buffers? For now we do the latter
+ because it works with 2.2 still */
{
unsigned char *from = (unsigned char *) &tmpmailbox;
unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC;
@@ -427,6 +467,7 @@ static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t
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);
@@ -434,75 +475,25 @@ static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t
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);
+ spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
return 0;
}
-static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr)
+static int do_ac_read(int IndexCard, char *buf)
{
- 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() */
+ unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC;
+ unsigned char *to = (unsigned char *)&tmpmailbox;
+#ifdef DEBUG
+ int c;
+#endif
-
- 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();
- }
- }
-
- 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++)
@@ -510,18 +501,15 @@ static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr)
}
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(IndexCard+1, 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;
-
printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard);
for (c = 0; c < sizeof(struct st_ram_io);) {
@@ -542,11 +530,8 @@ static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr)
}
}
printk("\n");
-
- }
#endif
-
/* Je suis stupide. DW. */
if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io)))
@@ -554,7 +539,82 @@ static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr)
if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
return -EFAULT;
- return 0;
+ return (sizeof(struct st_ram_io) + sizeof(struct mailbox));
+}
+
+static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr)
+{
+ unsigned long flags;
+ unsigned int i;
+ unsigned char tmp;
+ int ret = 0;
+ DECLARE_WAITQUEUE(wait, current);
+#ifdef DEBUG
+ int loopcount=0;
+#endif
+ /* No need to ratelimit this. Only root can trigger it anyway */
+ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+ printk( KERN_WARNING "Hmmm. read() of Applicom card, length %d != expected %d\n",
+ count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ return -EINVAL;
+ }
+
+ while(1) {
+ /* Stick ourself on the wait queue */
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&FlagSleepRec, &wait);
+
+ /* Scan each board, looking for one which has a packet for us */
+ for (i=0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+ spin_lock_irqsave(&apbs[i].mutex, flags);
+
+ tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
+
+ if (tmp == 2) {
+ /* Got a packet for us */
+ ret = do_ac_read(i, buf);
+ spin_unlock_irqrestore(&apbs[i].mutex, flags);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&FlagSleepRec, &wait);
+ return tmp;
+ }
+
+ if (tmp > 2) {
+ /* Got an error */
+ Dummy = readb(apbs[i].RamIO + VERS);
+
+ spin_unlock_irqrestore(&apbs[i].mutex, flags);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&FlagSleepRec, &wait);
+
+ 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;
+ }
+
+ /* Nothing for us. Try the next board */
+ Dummy = readb(apbs[i].RamIO + VERS);
+ spin_unlock_irqrestore(&apbs[i].mutex, flags);
+
+ } /* per board */
+
+ /* OK - No boards had data for us. Sleep now */
+
+ schedule();
+ remove_wait_queue(&FlagSleepRec, &wait);
+
+ if (signal_pending(current))
+ return -EINTR;
+
+#ifdef DEBUG
+ if (loopcount++ > 2) {
+ printk("Looping in ac_read. loopcount %d\n", loopcount);
+ }
+#endif
+ }
}
static void ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
@@ -562,36 +622,50 @@ 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;
+ FlagInt = 0;
for (i = 0; i < MAX_BOARD; i++) {
+
+ /* Skip if this board doesn't exist */
if (!apbs[i].RamIO)
continue;
- if (readb(apbs[i].RamIO + RAM_IT_TO_PC) != 0)
- FlagInt = TRUE;
+ spin_lock(&apbs[i].mutex);
+
+ /* Skip if this board doesn't want attention */
+ if(readb(apbs[i].RamIO + RAM_IT_TO_PC) == 0) {
+ spin_unlock(&apbs[i].mutex);
+ continue;
+ }
+
+ FlagInt = 1;
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));
+ 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));
+
+ if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) &&
+ (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) {
+
+ printk(KERN_WARNING "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 ? */
+ if (waitqueue_active(&FlagSleepRec)) {
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);
@@ -599,120 +673,123 @@ static void ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
}
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(readb(apbs[i].RamIO + RAM_IT_TO_PC)) {
+ /* There's another int waiting on this card */
+ spin_unlock(&apbs[i].mutex);
+ i--;
+ } else {
+ spin_unlock(&apbs[i].mutex);
+ }
}
if (FlagInt)
LoopCount = 0;
else
LoopCount++;
- }
- while (LoopCount < 2);
+ } 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;
+ int ret = 0;
volatile unsigned char byte_reset_it;
- struct st_ram_io adgl;
- unsigned char TmpRamIo[sizeof(struct st_ram_io)];
+ struct st_ram_io *adgl;
+ /* In general, the device is only openable by root anyway, so we're not
+ particularly concerned that bogus ioctls can flood the console. */
- if (copy_from_user(&adgl, (void *) arg, sizeof(struct st_ram_io)))
- return -EFAULT;
+ adgl = kmalloc(sizeof(struct st_ram_io), GFP_KERNEL);
+ if (!adgl)
+ return -ENOMEM;
- IndexCard = adgl.num_card - 1;
+ if (copy_from_user(adgl, (void *)arg,sizeof(struct st_ram_io))) {
+ kfree(adgl);
+ return -EFAULT;
+ }
- /*
- * FIXME: user can flood the console using bogus ioctls
- */
+ 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);
+ if(cmd != 0 && cmd != 6 &&
+ ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+ static int warncount = 10;
+ if (warncount) {
+ printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
+ warncount--;
+ }
+ kfree(adgl);
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;
+ ((unsigned char *)adgl)[i]=readb(pmem++);
+ if (copy_to_user((void *)arg, adgl, sizeof(struct st_ram_io)))
+ ret = -EFAULT;
break;
case 1:
pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
for (i = 0; i < 4; i++)
- adgl.conf_end_test[i] = readb(pmem++);
+ adgl->conf_end_test[i] = readb(pmem++);
for (i = 0; i < 2; i++)
- adgl.error_code[i] = readb(pmem++);
+ adgl->error_code[i] = readb(pmem++);
for (i = 0; i < 4; i++)
- adgl.parameter_error[i] = readb(pmem++);
+ adgl->parameter_error[i] = readb(pmem++);
pmem = apbs[IndexCard].RamIO + VERS;
- adgl.vers = readb(pmem);
+ 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;
+ 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)))
+ ret = -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(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);
-#else
- FlagSleepRec = NULL;
-#endif
for (i = 0; i < MAX_BOARD; i++) {
if (apbs[i].RamIO) {
-#if LINUX_VERSION_CODE > 0x20300
- init_waitqueue_head(&apbs[i].FlagSleepSend);
-#else
- 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);
+ 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;
+ 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)))
+ ret = -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(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 "APPLICOM driver release .... V2.8.0 ($Revision: 1.30 $)\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);
@@ -723,16 +800,20 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
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);
+ 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));
+ 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);
@@ -746,18 +827,19 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
if (WriteErrorCount != 0)
printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount);
if (waitqueue_active(&FlagSleepRec))
- printk("Process in read pending\n");
+ printk(KERN_INFO "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);
+ printk(KERN_INFO "Process in write pending board %d\n",i+1);
}
break;
default:
- printk("APPLICOM driver ioctl, unknown function code %d\n", cmd);
- return -EINVAL;
+ printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
+ ret = -EINVAL;
break;
}
Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ kfree(adgl);
return 0;
}
@@ -773,7 +855,7 @@ static int __init applicom_setup(char *str)
}
if (ints[0] < 2) {
- printk("applicom numargs: %d\n", ints[0]);
+ printk(KERN_INFO"applicom numargs: %d\n", ints[0]);
return 0;
}
@@ -782,7 +864,7 @@ static int __init applicom_setup(char *str)
return 1;
}
-#if LINUX_VERSION_CODE > 0x20300
__setup("applicom=", applicom_setup);
-#endif
+
#endif /* MODULE */
+
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index 59adf47bc..a3dfdfb04 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -490,7 +490,8 @@ static int init_bttv_i2c(struct bttv *btv)
bttv_bit_setscl(btv,1);
bttv_bit_setsda(btv,1);
- return i2c_bit_add_bus(&btv->i2c_adap);
+ btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap);
+ return btv->i2c_ok;
}
/* read I2C */
@@ -498,6 +499,8 @@ static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
{
unsigned char buffer = 0;
+ if (0 != btv->i2c_ok)
+ return -1;
if (verbose && NULL != probe_for)
printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
btv->nr,probe_for,addr);
@@ -523,11 +526,13 @@ static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char buffer[2];
int bytes = both ? 2 : 1;
+ if (0 != btv->i2c_ok)
+ return -1;
btv->i2c_client.addr = addr >> 1;
buffer[0] = b1;
buffer[1] = b2;
if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
- return -1;
+ return -1;
return 0;
}
@@ -702,42 +707,25 @@ static void init_PXC200(struct bttv *btv)
/* ----------------------------------------------------------------------- */
-/* for some vendors it is just the PCI ID */
-static struct VENDOR {
- int id;
- char *name;
-} vendors[] = {
- { 0x0001, "ATI Technologies Inc" },
- { 0x10b4, "STB Systems Inc" },
- { 0x1118, "Terratec" },
- { 0x13eb, "Hauppauge Computer Works Inc" },
- { 0x1461, "Avermedia" },
- { 0x1850, "Chronos" },
- { 0x1852, "Typhoon" },
- { 0x3000, "Askey" },
- { 0x3002, "Askey" },
- { 0x6606, "Leadtek" },
- { -1, NULL }
-};
-
static struct CARD {
- int vid;
- int id;
+ unsigned id;
int cardnr;
char *name;
} cards[] = {
- { 0x0001, 0x1002, BTTV_HAUPPAUGE878, "TV Wonder" },
- { 0x10b4, 0x2636, BTTV_HAUPPAUGE878, "???" },
- { 0x1118, 0x153b, BTTV_TERRATVALUE, "TV Value" },
- { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV" },
- { 0x1461, 0x0002, BTTV_AVERMEDIA98, "TVCapture 98" },
- { 0x1850, 0x1851, BTTV_CHRONOS_VS2, "Video Shuttle II" },
- { 0x1852, 0x1852, BTTV_TYPHOON_TVIEW, "TView TV/FM Tuner" },
- { 0x3000, 0x14ff, BTTV_MAGICTVIEW061, "TView 99" },
- { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" },
- { 0x3002, 0x14ff, BTTV_PHOEBE_TVMAS, "TV Master" },
- { 0x6606, 0x217d, BTTV_WINFAST2000, "WinFast TV 2000" },
- { -1, -1, -1, NULL }
+ { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" },
+ { 0x00031461, BTTV_AVERMEDIA98, "AVerMedia TVPhone98" },
+ { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" },
+ { 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" },
+ { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" },
+ { 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" },
+ { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" },
+ { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
+ { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" },
+ { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
+ { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
+ { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" },
+ { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
+ { 0, -1, NULL }
};
struct tvcard
@@ -869,7 +857,7 @@ static struct tvcard tvcards[] =
1,1,1,1,0 },
{ "FlyVideo 98",
3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1},
- { 0, 0x8dff00, 0x800, 0x400, 0x8dff00, 0 },0,
+ { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0,
1,1,1,1,0 },
{ "iProTV",
3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0,
@@ -893,9 +881,12 @@ static struct tvcard tvcards[] =
{ "Typhoon TView TV/FM Tuner",
3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0,
1,1,1,1,0 },
- { "PixelView PlayTV pro",
- 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },
- { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 }
+ { "PixelView PlayTV pro",
+ 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },
+ { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 },
+ { "TView99 CPH063",
+ 3, 1, 0, 2, 0x551e00, { 2, 0, 1, 1},
+ { 0x551400, 0x551200, 0, 0, 0x551200 }, 0,1,1,1,1,0 },
};
#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
@@ -920,39 +911,35 @@ dump_eeprom(struct bttv *btv,int addr)
static int
idcard_eeprom(struct bttv *btv)
{
- int i,id1,id2,n1,n2;
+ unsigned id;
+ int i,n;
- id1 = (eeprom_data[254] << 8) | (eeprom_data[255]);
- id2 = (eeprom_data[252] << 8) | (eeprom_data[253]);
- if (id1 == 0 || id1 == 0xffff ||
- id2 == 0 || id2 == 0xffff)
- return -1;
+ id = (eeprom_data[252] << 24) |
+ (eeprom_data[253] << 16) |
+ (eeprom_data[254] << 8) |
+ (eeprom_data[255]);
+ if (id == 0 || id == 0xffffffff)
+ return -1;
/* look for the card */
- n1 = -1; n2 = -1;
- for (i = 0; vendors[i].id != -1; i++)
- if (vendors[i].id == id2)
- n2 = i;
- for (i = 0; cards[i].id != -1; i++)
- if (cards[i].id == id1 &&
- cards[i].vid == id2)
- n1 = i;
-
- if (n1 != -1 && n2 != -1) {
+ for (n = -1, i = 0; cards[i].id != 0; i++)
+ if (cards[i].id == id)
+ n = i;
+
+ if (n != -1) {
/* found it */
- printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
- btv->nr,cards[n1].name,id1,vendors[n2].name,id2);
+ printk(KERN_INFO "bttv%d: id: %s (0x%08x)\n",
+ btv->nr,cards[n].name,id);
if (verbose)
printk(KERN_INFO "bttv%d: => card=%d (%s)\n",
- btv->nr,cards[n1].cardnr,
- tvcards[cards[n1].cardnr].name);
- return cards[n1].cardnr;
+ btv->nr,cards[n].cardnr,
+ tvcards[cards[n].cardnr].name);
+ return cards[n].cardnr;
} else {
/* 404 */
- printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n",
- btv->nr, "unknown", id1,
- (n2 != -1) ? vendors[n2].name : "unknown", id2);
- printk(KERN_INFO "please mail id + vendor, board name and "
+ printk(KERN_INFO "bttv%d: id: unknown (0x%08x)\n",
+ btv->nr, id);
+ printk(KERN_INFO "please mail id, board name and "
"the correct card= insmod option to "
"kraxel@goldbach.in-berlin.de\n");
return -1;
@@ -1670,30 +1657,48 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
* www.brooktree.com - nicely done those folks.
*/
-/* set geometry for even/odd frames
- just if you are wondering:
- handling of even and odd frames will be separated, e.g. for grabbing
- the even ones as RGB into videomem and the others as YUV in main memory for
- compressing and sending to the video conferencing partner.
-
-*/
-static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
- u16 hscale, u16 vscale,
- u16 hactive, u16 vactive,
- u16 hdelay, u16 vdelay,
- u8 crop)
+static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn,
+ int odd, int width, int height)
{
+ u16 vscale, hscale;
+ u32 xsf, sr;
+ u16 hdelay;
+ u8 crop, vtc;
+ int inter = (height>tvn->sheight/2) ? 0 : 1;
int off = odd ? 0x80 : 0x00;
-
+
+ xsf = (width*tvn->scaledtwidth)/tvn->swidth;
+ hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+ hdelay = tvn->hdelayx1;
+ hdelay = (hdelay*width)/tvn->swidth;
+ hdelay &= 0x3fe;
+ sr=((tvn->sheight>>inter)*512)/height-512;
+ vscale=(0x10000UL-sr)&0x1fff;
+ crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)|
+ ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
+ vscale |= inter ? (BT848_VSCALE_INT<<8) : 0;
+
+#if 0
+ /* Some people say interpolation looks bad ... */
+ vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+ if (width < 767)
+ btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+ else
+ btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+#else
+ vtc = 0;
+ btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+#endif
+
btwrite(vtc, BT848_E_VTC+off);
btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
btwrite(hscale&0xff, BT848_E_HSCALE_LO+off);
btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
btwrite(vscale&0xff, BT848_E_VSCALE_LO+off);
- btwrite(hactive&0xff, BT848_E_HACTIVE_LO+off);
+ btwrite(width&0xff, BT848_E_HACTIVE_LO+off);
btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off);
- btwrite(vactive&0xff, BT848_E_VACTIVE_LO+off);
- btwrite(vdelay&0xff, BT848_E_VDELAY_LO+off);
+ btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off);
+ btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off);
btwrite(crop, BT848_E_CROP+off);
}
@@ -1701,14 +1706,8 @@ static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
static void bt848_set_geo(struct bttv *btv,
int no_irq_context)
{
- u16 vscale, hscale;
- u32 xsf, sr;
u16 ewidth, eheight, owidth, oheight;
u16 format, bswap;
- u16 hdelay;
- u16 hactive;
- u16 inter;
- u8 crop, vtc;
struct tvnorm *tvn;
unsigned long flags;
@@ -1727,10 +1726,6 @@ static void bt848_set_geo(struct bttv *btv,
if (no_irq_context)
set_pll(btv);
- vtc=0;
- /* Some people say interpolation looks bad ... */
- /* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */
-
btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0;
if (0 == btv->risc_cap_odd &&
@@ -1762,40 +1757,11 @@ static void bt848_set_geo(struct bttv *btv,
eheight = btv->gbuf[btv->gq_grab].height;
format = btv->gbuf[btv->gq_grab].fmt;
bswap = 0;
- inter = (btv->win.height>tvn->sheight/2) ? 0 : 1;
}
- inter = (oheight>tvn->sheight/2) ? 0 : 1;
-
- /* odd field */
- hactive=owidth;
- xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
- hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
- hdelay = tvn->hdelayx1;
- hdelay = (hdelay*hactive)/tvn->swidth;
- hdelay &= 0x3fe;
- sr=((tvn->sheight>>inter)*512)/oheight-512;
- vscale=(0x10000UL-sr)&0x1fff;
- crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
- ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
- vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
- bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, tvn->sheight,
- hdelay, tvn->vdelay, crop);
-
- /* even field */
- hactive=ewidth;
- xsf = (hactive*tvn->scaledtwidth)/tvn->swidth;
- hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
- hdelay = tvn->hdelayx1;
- hdelay = (hdelay*hactive)/tvn->swidth;
- hdelay &= 0x3fe;
- sr=((tvn->sheight>>inter)*512)/eheight-512;
- vscale=(0x10000UL-sr)&0x1fff;
- crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
- ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0);
- vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
- bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, tvn->sheight,
- hdelay, tvn->vdelay, crop);
+ /* program odd + even fields */
+ bt848_set_eogeo(btv, tvn, 1, owidth, oheight);
+ bt848_set_eogeo(btv, tvn, 0, ewidth, eheight);
btwrite(format, BT848_COLOR_FMT);
btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
@@ -1897,8 +1863,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 (%dx%d)\n",
- btv->nr,mp->frame,mp->width,mp->height);
+ printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n",
+ btv->nr,mp->frame,mp->format,mp->width,mp->height);
cli();
btv->gbuf[mp->frame].stat = GBUFFER_GRABBING;
btv->gbuf[mp->frame].fmt = palette2fmt[mp->format];
@@ -1914,10 +1880,6 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
#endif
if (btv->gq_in == btv->gq_out) {
- if(mp->format>=VIDEO_PALETTE_COMPONENT) {
- btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
- btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
- }
btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
}
btv->gqueue[btv->gq_in++] = mp->frame;
@@ -2317,7 +2279,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
btv->win.height=vw.height;
bt848_set_risc_jmps(btv,0);
-
+
bt848_set_winsize(btv);
up(&btv->lock);
@@ -2573,10 +2535,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (debug)
printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i);
interruptible_sleep_on(&btv->capq);
- if(signal_pending(current)) {
- ret = -EINTR;
- break;
- }
+ if(signal_pending(current))
+ return -EINTR;
}
/* fall throuth */
case GBUFFER_DONE:
@@ -2649,9 +2609,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
else
vu.radio=VIDEO_NO_UNIT;
vu.audio=VIDEO_NO_UNIT;
-#if 0
- AUDIO(AUDC_GET_UNIT, &vu.audio);
-#endif
vu.teletext=VIDEO_NO_UNIT;
if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
return -EFAULT;
@@ -3054,17 +3011,6 @@ static void handle_chipset(void)
}
}
-#if 0
-#warning please use tda8425.c instead
-static void init_tda8425(struct bttv *btv)
-{
- I2CWrite(btv, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */
- I2CWrite(btv, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */
- I2CWrite(btv, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */
- I2CWrite(btv, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB */
- I2CWrite(btv, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */
-}
-#endif
/* can tda9855.c handle this too maybe? */
static void init_tda9840(struct bttv *btv)
@@ -3164,6 +3110,7 @@ static void idcard(int i)
btv->type == BTTV_PIXVIEWPLAYTV ||
btv->type == BTTV_AVERMEDIA98 ||
btv->type == BTTV_MAGICTVIEW061 ||
+ btv->type == BTTV_MAGICTVIEW063 ||
btv->type == BTTV_CHRONOS_VS2 ||
btv->type == BTTV_TYPHOON_TVIEW ||
btv->type == BTTV_PXELVWPLTVPRO ||
@@ -3600,8 +3547,6 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->risc_cap_odd = 0;
btv->risc_cap_even = 0;
bt848_set_risc_jmps(btv,-1);
- btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
- btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
bt848_set_geo(btv,0);
btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA,
BT848_COLOR_CTL);
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index c1e9b3e9a..7dd6f046b 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,24)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,25)
#include <linux/types.h>
#include <linux/wait.h>
@@ -138,7 +138,7 @@ struct bttv {
struct i2c_adapter i2c_adap;
struct i2c_algo_bit_data i2c_algo;
struct i2c_client i2c_client;
- int i2c_state;
+ int i2c_state, i2c_ok;
struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
int tuner_type;
@@ -270,6 +270,7 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
#define BTTV_CHRONOS_VS2 0x23
#define BTTV_TYPHOON_TVIEW 0x24
#define BTTV_PXELVWPLTVPRO 0x25
+#define BTTV_MAGICTVIEW063 0x26
#define AUDIO_TUNER 0x00
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 93e710188..4e69f8f4b 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -121,8 +121,6 @@ struct consw *conswitchp = NULL;
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
-extern int tty_register_devfs (struct tty_driver *driver, unsigned int flags,
- unsigned int minor);
extern void vcs_make_devfs (unsigned int index, int unregister);
#ifndef MIN
diff --git a/drivers/char/cpia.c b/drivers/char/cpia.c
new file mode 100644
index 000000000..4efbabe9b
--- /dev/null
+++ b/drivers/char/cpia.c
@@ -0,0 +1,3319 @@
+/*
+ * cpia CPiA driver
+ *
+ * Supports CPiA based Video Camera's.
+ *
+ * (C) Copyright 1999-2000 Peter Pregler,
+ * (C) Copyright 1999-2000 Scott J. Bertin,
+ * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* #define _CPIA_DEBUG_ define for verbose debug output */
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "cpia.h"
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+extern int cpia_pp_init(void);
+#endif
+#ifdef CONFIG_VIDEO_CPIA_USB
+extern int cpia_usb_init(void);
+#endif
+
+#ifdef MODULE
+MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
+MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+#endif
+
+#define ABOUT "V4L-Driver for Vision CPiA based cameras"
+
+#ifndef VID_HARDWARE_CPIA
+#define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
+#endif
+
+#define CPIA_MODULE_CPIA (0<<5)
+#define CPIA_MODULE_SYSTEM (1<<5)
+#define CPIA_MODULE_VP_CTRL (5<<5)
+#define CPIA_MODULE_CAPTURE (6<<5)
+#define CPIA_MODULE_DEBUG (7<<5)
+
+#define INPUT (DATA_IN << 8)
+#define OUTPUT (DATA_OUT << 8)
+
+#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
+#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
+#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
+#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
+#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
+#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
+#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
+#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
+
+#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
+#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
+#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
+#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
+#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
+#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
+#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
+#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
+#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
+#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
+#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
+#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
+#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
+
+#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
+#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
+#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
+#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
+#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
+#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
+#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
+#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
+#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
+#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
+#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
+#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
+#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
+#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
+#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
+#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
+
+#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
+#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
+#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
+#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
+#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
+#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
+#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
+#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
+#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
+#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
+#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
+#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
+#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
+#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
+
+#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
+#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
+#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
+#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
+#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
+#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
+#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
+
+enum {
+ FRAME_READY, /* Ready to grab into */
+ FRAME_GRABBING, /* In the process of being grabbed into */
+ FRAME_DONE, /* Finished grabbing, but not been synced yet */
+ FRAME_UNUSED, /* Unused (no MCAPTURE) */
+};
+
+#define COMMAND_NONE 0x0000
+#define COMMAND_SETCOMPRESSION 0x0001
+#define COMMAND_SETCOMPRESSIONTARGET 0x0002
+#define COMMAND_SETCOLOURPARAMS 0x0004
+#define COMMAND_SETFORMAT 0x0008
+#define COMMAND_PAUSE 0x0010
+#define COMMAND_RESUME 0x0020
+#define COMMAND_SETYUVTHRESH 0x0040
+#define COMMAND_SETECPTIMING 0x0080
+#define COMMAND_SETCOMPRESSIONPARAMS 0x0100
+#define COMMAND_SETEXPOSURE 0x0200
+#define COMMAND_SETCOLOURBALANCE 0x0400
+#define COMMAND_SETSENSORFPS 0x0800
+#define COMMAND_SETAPCOR 0x1000
+#define COMMAND_SETFLICKERCTRL 0x2000
+#define COMMAND_SETVLOFFSET 0x4000
+
+/* Developer's Guide Table 5 p 3-34
+ * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
+static u8 flicker_jumps[2][2][4] =
+{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
+ { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
+};
+
+/* forward declaration of local function */
+static void reset_camera_struct(struct cam_data *cam);
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet - jerdfelt
+ *
+ **********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+ unsigned long ret = 0UL;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, adr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset(pmd, adr);
+ pte = *ptep;
+ if (pte_present(pte))
+ ret = page_address(pte_page(pte)) |
+ (adr & (PAGE_SIZE-1));
+ }
+ }
+ return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR(adr);
+ kva = uvirt_to_kva(pgd_offset_k(va), va);
+ ret = __pa(kva);
+ return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+ void *mem;
+ unsigned long adr, page;
+
+ /* Round it off to PAGE_SIZE */
+ size += (PAGE_SIZE - 1);
+ size &= ~(PAGE_SIZE - 1);
+
+ mem = vmalloc(size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa(adr);
+ mem_map_reserve(MAP_NR(__va(page)));
+ adr += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+ unsigned long adr, page;
+
+ if (!mem)
+ return;
+
+ size += (PAGE_SIZE - 1);
+ size &= ~(PAGE_SIZE - 1);
+
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa(adr);
+ mem_map_unreserve(MAP_NR(__va(page)));
+ adr += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+ vfree(mem);
+}
+
+/**********************************************************************
+ *
+ * /proc interface
+ *
+ **********************************************************************/
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *cpia_proc_root=NULL;
+
+static int cpia_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ char *out = page;
+ int len, tmp;
+ struct cam_data *cam = data;
+ char tmpstr[20];
+
+ /* IMPORTANT: This output MUST be kept under PAGE_SIZE
+ * or we need to get more sophisticated. */
+
+ out += sprintf(out, "read-only\n-----------------------\n");
+ out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
+ CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+ out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
+ cam->params.version.firmwareVersion,
+ cam->params.version.firmwareRevision,
+ cam->params.version.vcVersion,
+ cam->params.version.vcRevision);
+ out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
+ cam->params.pnpID.vendor, cam->params.pnpID.product,
+ cam->params.pnpID.deviceRevision);
+ out += sprintf(out, "VP-Version: %d.%d %04x\n",
+ cam->params.vpVersion.vpVersion,
+ cam->params.vpVersion.vpRevision,
+ cam->params.vpVersion.cameraHeadID);
+
+ out += sprintf(out, "system_state: %#04x\n",
+ cam->params.status.systemState);
+ out += sprintf(out, "grab_state: %#04x\n",
+ cam->params.status.grabState);
+ out += sprintf(out, "stream_state: %#04x\n",
+ cam->params.status.streamState);
+ out += sprintf(out, "fatal_error: %#04x\n",
+ cam->params.status.fatalError);
+ out += sprintf(out, "cmd_error: %#04x\n",
+ cam->params.status.cmdError);
+ out += sprintf(out, "debug_flags: %#04x\n",
+ cam->params.status.debugFlags);
+ out += sprintf(out, "vp_status: %#04x\n",
+ cam->params.status.vpStatus);
+ out += sprintf(out, "error_code: %#04x\n",
+ cam->params.status.errorCode);
+ out += sprintf(out, "video_size: %s\n",
+ cam->params.format.videoSize == VIDEOSIZE_CIF ?
+ "CIF " : "QCIF");
+ out += sprintf(out, "sub_sample: %s\n",
+ cam->params.format.subSample == SUBSAMPLE_420 ?
+ "420" : "422");
+ out += sprintf(out, "yuv_order: %s\n",
+ cam->params.format.yuvOrder == YUVORDER_YUYV ?
+ "YUYV" : "UYVY");
+ out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
+ cam->params.roi.colStart*8,
+ cam->params.roi.rowStart*4,
+ cam->params.roi.colEnd*8,
+ cam->params.roi.rowEnd*4);
+ out += sprintf(out, "actual_fps: %3d\n", cam->fps);
+ out += sprintf(out, "transfer_rate: %4dkB/s\n",
+ cam->transfer_rate);
+
+ out += sprintf(out, "\nread-write\n");
+ out += sprintf(out, "----------------------- current min"
+ " max default comment\n");
+ out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
+ cam->params.colourParams.brightness, 0, 100, 50);
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits contrast to 80 */
+ tmp = 80;
+ else
+ tmp = 96;
+
+ out += sprintf(out, "contrast: %8d %8d %8d %8d"
+ " steps of 8\n",
+ cam->params.colourParams.contrast, 0, tmp, 48);
+ out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
+ cam->params.colourParams.saturation, 0, 100, 50);
+ tmp = (25000+5000*cam->params.sensorFps.baserate)/
+ (1<<cam->params.sensorFps.divisor);
+ out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
+ tmp/1000, tmp%1000, 3, 30, 15);
+ out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
+ 2*cam->params.streamStartLine, 0,
+ cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
+ cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
+ out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
+ cam->params.ecpTiming ? "slow" : "normal", "slow",
+ "normal", "normal");
+
+ if (cam->params.colourBalance.balanceModeIsAuto) {
+ sprintf(tmpstr, "auto");
+ } else {
+ sprintf(tmpstr, "manual");
+ }
+ out += sprintf(out, "color_balance_mode: %8s %8s %8s"
+ " %8s\n", tmpstr, "manual", "auto", "auto");
+ out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.redGain, 0, 212, 32);
+ out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.greenGain, 0, 212, 6);
+ out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
+ cam->params.colourBalance.blueGain, 0, 212, 92);
+
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits gain to 2 */
+ sprintf(tmpstr, "%8d %8d", 1, 2);
+ else
+ sprintf(tmpstr, "1,2,4,8");
+
+ if (cam->params.exposure.gainMode == 0)
+ out += sprintf(out, "max_gain: unknown %18s"
+ " %8d\n", tmpstr, 2);
+ else
+ out += sprintf(out, "max_gain: %8d %18s %8d\n",
+ 1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
+
+ switch(cam->params.exposure.expMode) {
+ case 1:
+ case 3:
+ sprintf(tmpstr, "manual");
+ break;
+ case 2:
+ sprintf(tmpstr, "auto");
+ break;
+ default:
+ sprintf(tmpstr, "unknown");
+ break;
+ }
+ out += sprintf(out, "exposure_mode: %8s %8s %8s"
+ " %8s\n", tmpstr, "manual", "auto", "auto");
+ out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
+ (2-cam->params.exposure.centreWeight) ? "on" : "off",
+ "off", "on", "on");
+ out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
+ 1<<cam->params.exposure.gain, 1, 1);
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits fineExp to 127 */
+ tmp = 255;
+ else
+ tmp = 511;
+
+ out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
+ cam->params.exposure.fineExp*2, 0, tmp, 0);
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2)
+ /* 1-02 firmware limits coarseExpHi to 0 */
+ tmp = 255;
+ else
+ tmp = 65535;
+
+ out += sprintf(out, "coarse_exp: %8d %8d %8d"
+ " %8d\n", cam->params.exposure.coarseExpLo+
+ 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
+ out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.redComp, 220, 255, 220);
+ out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.green1Comp, 214, 255, 214);
+ out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.green2Comp, 214, 255, 214);
+ out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
+ cam->params.exposure.blueComp, 230, 255, 230);
+
+ out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain1, 0, 0xff, 0x1c);
+ out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain2, 0, 0xff, 0x1a);
+ out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain4, 0, 0xff, 0x2d);
+ out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
+ cam->params.apcor.gain8, 0, 0xff, 0x2a);
+ out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain1, 0, 255, 24);
+ out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain2, 0, 255, 28);
+ out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain4, 0, 255, 30);
+ out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
+ cam->params.vlOffset.gain8, 0, 255, 30);
+ out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
+ cam->params.flickerControl.flickerMode ? "on" : "off",
+ "off", "on", "off");
+ out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
+ " only 50/60\n",
+ cam->mainsFreq ? 60 : 50, 50, 60, 50);
+ out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n",
+ cam->params.flickerControl.allowableOverExposure, 0,
+ 255, 0);
+ out += sprintf(out, "compression_mode: ");
+ switch(cam->params.compression.mode) {
+ case CPIA_COMPRESSION_NONE:
+ out += sprintf(out, "%8s", "none");
+ break;
+ case CPIA_COMPRESSION_AUTO:
+ out += sprintf(out, "%8s", "auto");
+ break;
+ case CPIA_COMPRESSION_MANUAL:
+ out += sprintf(out, "%8s", "manual");
+ break;
+ default:
+ out += sprintf(out, "%8s", "unknown");
+ break;
+ }
+ out += sprintf(out, " none,auto,manual auto\n");
+ out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
+ cam->params.compression.decimation ==
+ DECIMATION_ENAB ? "on":"off", "off", "off",
+ "off");
+ out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
+ cam->params.compressionTarget.frTargeting ==
+ CPIA_COMPRESSION_TARGET_FRAMERATE ?
+ "framerate":"quality",
+ "framerate", "quality", "quality");
+ out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
+ cam->params.compressionTarget.targetFR, 0, 30, 7);
+ out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
+ cam->params.compressionTarget.targetQ, 0, 255, 10);
+ out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
+ cam->params.yuvThreshold.yThreshold, 0, 31, 15);
+ out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
+ cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
+ out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.hysteresis, 0, 255, 3);
+ out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.threshMax, 0, 255, 11);
+ out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.smallStep, 0, 255, 1);
+ out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.largeStep, 0, 255, 3);
+ out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.decimationHysteresis,
+ 0, 255, 2);
+ out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.frDiffStepThresh,
+ 0, 255, 5);
+ out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.qDiffStepThresh,
+ 0, 255, 3);
+ out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
+ cam->params.compressionParams.decimationThreshMod,
+ 0, 255, 2);
+
+ len = out - page;
+ len -= off;
+ if (len < count) {
+ *eof = 1;
+ if (len <= 0) return 0;
+ } else
+ len = count;
+
+ *start = page + off;
+ return len;
+}
+
+static int cpia_write_proc(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct cam_data *cam = data;
+ struct cam_params new_params;
+ int retval, find_colon;
+ int size = count;
+ unsigned long val;
+ u32 command_flags = 0;
+ u8 new_mains;
+
+ if (down_interruptible(&cam->param_lock))
+ return -ERESTARTSYS;
+
+ /*
+ * Skip over leading whitespace
+ */
+ while (count && isspace(*buffer)) {
+ --count;
+ ++buffer;
+ }
+
+ memcpy(&new_params, &cam->params, sizeof(struct cam_params));
+ new_mains = cam->mainsFreq;
+
+#define MATCH(x) \
+ ({ \
+ int _len = strlen(x), _ret, _colon_found; \
+ _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
+ if (_ret) { \
+ buffer += _len; \
+ count -= _len; \
+ if (find_colon) { \
+ _colon_found = 0; \
+ while (count && (*buffer == ' ' || *buffer == '\t' || \
+ (!_colon_found && *buffer == ':'))) { \
+ if (*buffer == ':') \
+ _colon_found = 1; \
+ --count; \
+ ++buffer; \
+ } \
+ if (!count || !_colon_found) \
+ retval = -EINVAL; \
+ find_colon = 0; \
+ } \
+ } \
+ _ret; \
+ })
+#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
+ new_params.version.firmwareRevision == (y))
+#define VALUE \
+ ({ \
+ char *_p; \
+ unsigned long int _ret; \
+ _ret = simple_strtoul(buffer, &_p, 0); \
+ if (_p == buffer) \
+ retval = -EINVAL; \
+ else { \
+ count -= _p - buffer; \
+ buffer = _p; \
+ } \
+ _ret; \
+ })
+
+ retval = 0;
+ while (count && !retval) {
+ find_colon = 1;
+ if (MATCH("brightness")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 100)
+ new_params.colourParams.brightness = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURPARAMS;
+ } else if (MATCH("contrast")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 100) {
+ /* contrast is in steps of 8, so round*/
+ val = ((val + 3) / 8) * 8;
+ /* 1-02 firmware limits contrast to 80*/
+ if (FIRMWARE_VERSION(1,2) && val > 80)
+ val = 80;
+
+ new_params.colourParams.contrast = val;
+ } else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURPARAMS;
+ } else if (MATCH("saturation")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 100)
+ new_params.colourParams.saturation = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURPARAMS;
+ } else if (MATCH("sensor_fps")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ /* find values so that sensorFPS is minimized,
+ * but >= val */
+ if (val > 30)
+ retval = -EINVAL;
+ else if (val > 25) {
+ new_params.sensorFps.divisor = 0;
+ new_params.sensorFps.baserate = 1;
+ } else if (val > 15) {
+ new_params.sensorFps.divisor = 0;
+ new_params.sensorFps.baserate = 0;
+ } else if (val > 12) {
+ new_params.sensorFps.divisor = 1;
+ new_params.sensorFps.baserate = 1;
+ } else if (val > 7) {
+ new_params.sensorFps.divisor = 1;
+ new_params.sensorFps.baserate = 0;
+ } else if (val > 6) {
+ new_params.sensorFps.divisor = 2;
+ new_params.sensorFps.baserate = 1;
+ } else if (val > 3) {
+ new_params.sensorFps.divisor = 2;
+ new_params.sensorFps.baserate = 0;
+ } else {
+ new_params.sensorFps.divisor = 3;
+ /* Either base rate would work here */
+ new_params.sensorFps.baserate = 1;
+ }
+ new_params.flickerControl.coarseJump =
+ flicker_jumps[new_mains]
+ [new_params.sensorFps.baserate]
+ [new_params.sensorFps.divisor];
+ if (new_params.flickerControl.flickerMode)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ }
+ command_flags |= COMMAND_SETSENSORFPS;
+ } else if (MATCH("stream_start_line")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ int max_line = 288;
+
+ if (new_params.format.videoSize == VIDEOSIZE_QCIF)
+ max_line = 144;
+ if (val <= max_line)
+ new_params.streamStartLine = val/2;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("ecp_timing")) {
+ if (!retval && MATCH("normal"))
+ new_params.ecpTiming = 0;
+ else if (!retval && MATCH("slow"))
+ new_params.ecpTiming = 1;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETECPTIMING;
+ } else if (MATCH("color_balance_mode")) {
+ if (!retval && MATCH("manual"))
+ new_params.colourBalance.balanceModeIsAuto = 0;
+ else if (!retval && MATCH("auto"))
+ new_params.colourBalance.balanceModeIsAuto = 1;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("red_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 212)
+ new_params.colourBalance.redGain = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("green_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 212)
+ new_params.colourBalance.greenGain = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("blue_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 212)
+ new_params.colourBalance.blueGain = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOLOURBALANCE;
+ } else if (MATCH("max_gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ /* 1-02 firmware limits gain to 2 */
+ if (FIRMWARE_VERSION(1,2) && val > 2)
+ val = 2;
+ switch(val) {
+ case 1:
+ new_params.exposure.gainMode = 1;
+ break;
+ case 2:
+ new_params.exposure.gainMode = 2;
+ break;
+ case 4:
+ new_params.exposure.gainMode = 3;
+ break;
+ case 8:
+ new_params.exposure.gainMode = 4;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ }
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else if (MATCH("exposure_mode")) {
+ if (!retval && MATCH("auto"))
+ new_params.exposure.expMode = 2;
+ else if (!retval && MATCH("manual")) {
+ if (new_params.exposure.expMode == 2)
+ new_params.exposure.expMode = 3;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else if (MATCH("centre_weight")) {
+ if (!retval && MATCH("on"))
+ new_params.exposure.centreWeight = 1;
+ else if (!retval && MATCH("off"))
+ new_params.exposure.centreWeight = 2;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else if (MATCH("gain")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ switch(val) {
+ case 1:
+ new_params.exposure.gain = 0;
+ new_params.exposure.expMode = 1;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ break;
+ case 2:
+ new_params.exposure.gain = 1;
+ new_params.exposure.expMode = 1;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ break;
+ case 4:
+ new_params.exposure.gain = 2;
+ new_params.exposure.expMode = 1;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ break;
+ case 8:
+ new_params.exposure.gain = 3;
+ new_params.exposure.expMode = 1;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ command_flags |= COMMAND_SETEXPOSURE;
+ if (new_params.exposure.gain >
+ new_params.exposure.gainMode-1)
+ retval = -EINVAL;
+ }
+ } else if (MATCH("fine_exp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val < 256) {
+ /* 1-02 firmware limits fineExp to 127*/
+ if (FIRMWARE_VERSION(1,2) && val > 127)
+ val = 127;
+ new_params.exposure.fineExp = val;
+ new_params.exposure.expMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("coarse_exp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val < 65536) {
+ /* 1-02 firmware limits
+ * coarseExp to 255 */
+ if (FIRMWARE_VERSION(1,2) && val > 255)
+ val = 255;
+ new_params.exposure.coarseExpLo =
+ val & 0xff;
+ new_params.exposure.coarseExpHi =
+ val >> 8;
+ new_params.exposure.expMode = 1;
+ command_flags |= COMMAND_SETEXPOSURE;
+ new_params.flickerControl.flickerMode = 0;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("red_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= 220 && val <= 255) {
+ new_params.exposure.redComp = val;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("green1_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= 214 && val <= 255) {
+ new_params.exposure.green1Comp = val;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("green2_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= 214 && val <= 255) {
+ new_params.exposure.green2Comp = val;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("blue_comp")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val >= 230 && val <= 255) {
+ new_params.exposure.blueComp = val;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain1")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain1 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain2")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain2 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain4")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain4 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("apcor_gain8")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ command_flags |= COMMAND_SETAPCOR;
+ if (val <= 0xff)
+ new_params.apcor.gain8 = val;
+ else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("vl_offset_gain1")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain1 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("vl_offset_gain2")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain2 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("vl_offset_gain4")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain4 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("vl_offset_gain8")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.vlOffset.gain8 = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETVLOFFSET;
+ } else if (MATCH("flicker_control")) {
+ if (!retval && MATCH("on")) {
+ new_params.flickerControl.flickerMode = 1;
+ new_params.exposure.expMode = 2;
+ command_flags |= COMMAND_SETEXPOSURE;
+ } else if (!retval && MATCH("off"))
+ new_params.flickerControl.flickerMode = 0;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else if (MATCH("mains_frequency")) {
+ if (!retval && MATCH("50")) {
+ new_mains = 0;
+ new_params.flickerControl.coarseJump =
+ flicker_jumps[new_mains]
+ [new_params.sensorFps.baserate]
+ [new_params.sensorFps.divisor];
+ if (new_params.flickerControl.flickerMode)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else if (!retval && MATCH("60")) {
+ new_mains = 1;
+ new_params.flickerControl.coarseJump =
+ flicker_jumps[new_mains]
+ [new_params.sensorFps.baserate]
+ [new_params.sensorFps.divisor];
+ if (new_params.flickerControl.flickerMode)
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ } else if (MATCH("allowable_overexposure")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff) {
+ new_params.flickerControl.
+ allowableOverExposure = val;
+ command_flags |= COMMAND_SETFLICKERCTRL;
+ } else
+ retval = -EINVAL;
+ }
+ } else if (MATCH("compression_mode")) {
+ if (!retval && MATCH("none"))
+ new_params.compression.mode =
+ CPIA_COMPRESSION_NONE;
+ else if (!retval && MATCH("auto"))
+ new_params.compression.mode =
+ CPIA_COMPRESSION_AUTO;
+ else if (!retval && MATCH("manual"))
+ new_params.compression.mode =
+ CPIA_COMPRESSION_MANUAL;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOMPRESSION;
+ } else if (MATCH("decimation_enable")) {
+ if (!retval && MATCH("off"))
+ new_params.compression.decimation = 0;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOMPRESSION;
+ } else if (MATCH("compression_target")) {
+ if (!retval && MATCH("quality"))
+ new_params.compressionTarget.frTargeting =
+ CPIA_COMPRESSION_TARGET_QUALITY;
+ else if (!retval && MATCH("framerate"))
+ new_params.compressionTarget.frTargeting =
+ CPIA_COMPRESSION_TARGET_FRAMERATE;
+ else
+ retval = -EINVAL;
+
+ command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+ } else if (MATCH("target_framerate")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval)
+ new_params.compressionTarget.targetFR = val;
+ command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+ } else if (MATCH("target_quality")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval)
+ new_params.compressionTarget.targetQ = val;
+
+ command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+ } else if (MATCH("y_threshold")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val < 32)
+ new_params.yuvThreshold.yThreshold = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETYUVTHRESH;
+ } else if (MATCH("uv_threshold")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val < 32)
+ new_params.yuvThreshold.uvThreshold = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETYUVTHRESH;
+ } else if (MATCH("hysteresis")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.hysteresis = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("threshold_max")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.threshMax = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("small_step")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.smallStep = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("large_step")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.largeStep = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("decimation_hysteresis")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.decimationHysteresis = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("fr_diff_step_thresh")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.frDiffStepThresh = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("q_diff_step_thresh")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.qDiffStepThresh = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else if (MATCH("decimation_thresh_mod")) {
+ if (!retval)
+ val = VALUE;
+
+ if (!retval) {
+ if (val <= 0xff)
+ new_params.compressionParams.decimationThreshMod = val;
+ else
+ retval = -EINVAL;
+ }
+ command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+ } else {
+ DBG("No match found\n");
+ retval = -EINVAL;
+ }
+
+ if (!retval) {
+ while (count && isspace(*buffer) && *buffer != '\n') {
+ --count;
+ ++buffer;
+ }
+ if (count) {
+ if (*buffer != '\n' && *buffer != ';')
+ retval = -EINVAL;
+ else {
+ --count;
+ ++buffer;
+ }
+ }
+ }
+ }
+#undef MATCH
+#undef FIRMWARE_VERSION
+#undef VALUE
+#undef FIND_VALUE
+#undef FIND_END
+ if (!retval) {
+ if (command_flags & COMMAND_SETCOLOURPARAMS) {
+ /* Adjust cam->vp to reflect these changes */
+ cam->vp.brightness =
+ new_params.colourParams.brightness*65535/100;
+ cam->vp.contrast =
+ new_params.colourParams.contrast*65535/100;
+ cam->vp.colour =
+ new_params.colourParams.saturation*65535/100;
+ }
+
+ memcpy(&cam->params, &new_params, sizeof(struct cam_params));
+ cam->mainsFreq = new_mains;
+ cam->cmd_queue |= command_flags;
+ retval = size;
+ } else
+ DBG("error: %d\n", retval);
+
+ up(&cam->param_lock);
+
+ return retval;
+}
+
+static void create_proc_cpia_cam(struct cam_data *cam)
+{
+ char name[7];
+ struct proc_dir_entry *ent;
+
+ if (!cpia_proc_root || !cam)
+ return;
+
+ sprintf(name, "video%d", cam->vdev.minor);
+
+ ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
+ if (!ent)
+ return;
+
+ ent->data = cam;
+ ent->read_proc = cpia_read_proc;
+ ent->write_proc = cpia_write_proc;
+ ent->size = 3626;
+ cam->proc_entry = ent;
+}
+
+static void destroy_proc_cpia_cam(struct cam_data *cam)
+{
+ char name[7];
+
+ if (!cam || !cam->proc_entry)
+ return;
+
+ sprintf(name, "video%d", cam->vdev.minor);
+ remove_proc_entry(name, cpia_proc_root);
+ cam->proc_entry = NULL;
+}
+
+static void proc_cpia_create(void)
+{
+ cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
+
+ if (cpia_proc_root)
+ cpia_proc_root->owner = THIS_MODULE;
+ else
+ LOG("Unable to initialise /proc/cpia\n");
+}
+
+static void proc_cpia_destroy(void)
+{
+ remove_proc_entry("cpia", 0);
+}
+#endif /* CONFIG_PROC_FS */
+
+/* ----------------------- debug functions ---------------------- */
+
+#define printstatus(cam) \
+ DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
+ cam->params.status.systemState, cam->params.status.grabState, \
+ cam->params.status.streamState, cam->params.status.fatalError, \
+ cam->params.status.cmdError, cam->params.status.debugFlags, \
+ cam->params.status.vpStatus, cam->params.status.errorCode);
+
+/* ----------------------- v4l helpers -------------------------- */
+
+/* supported frame palettes and depths */
+static inline int valid_mode(u16 palette, u16 depth)
+{
+ return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
+ (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
+ (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
+ (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
+ (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
+ (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
+ (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
+ (palette == VIDEO_PALETTE_UYVY && depth == 16);
+}
+
+static int match_videosize( int width, int height )
+{
+ /* return the best match, where 'best' is as always
+ * the largest that is not bigger than what is requested. */
+ if (width>=352 && height>=288)
+ return VIDEOSIZE_352_288; /* CIF */
+
+ if (width>=320 && height>=240)
+ return VIDEOSIZE_320_240; /* SIF */
+
+ if (width>=288 && height>=216)
+ return VIDEOSIZE_288_216;
+
+ if (width>=256 && height>=192)
+ return VIDEOSIZE_256_192;
+
+ if (width>=224 && height>=168)
+ return VIDEOSIZE_224_168;
+
+ if (width>=192 && height>=144)
+ return VIDEOSIZE_192_144;
+
+ if (width>=176 && height>=144)
+ return VIDEOSIZE_176_144; /* QCIF */
+
+ if (width>=160 && height>=120)
+ return VIDEOSIZE_160_120; /* QSIF */
+
+ if (width>=128 && height>=96)
+ return VIDEOSIZE_128_96;
+
+ if (width>=88 && height>=72)
+ return VIDEOSIZE_88_72;
+
+ if (width>=64 && height>=48)
+ return VIDEOSIZE_64_48;
+
+ if (width>=48 && height>=48)
+ return VIDEOSIZE_48_48;
+
+ return -1;
+}
+
+/* these are the capture sizes we support */
+static void set_vw_size(struct cam_data *cam)
+{
+ /* the col/row/start/end values are the result of simple math */
+ /* study the SetROI-command in cpia developers guide p 2-22 */
+ /* streamStartLine is set to the recommended value in the cpia */
+ /* developers guide p 3-37 */
+ switch(cam->video_size) {
+ case VIDEOSIZE_CIF:
+ cam->vw.width = 352;
+ cam->vw.height = 288;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=0;
+ cam->params.roi.colEnd=44;
+ cam->params.roi.rowStart=0;
+ cam->params.roi.rowEnd=72;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_SIF:
+ cam->vw.width = 320;
+ cam->vw.height = 240;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=2;
+ cam->params.roi.colEnd=42;
+ cam->params.roi.rowStart=6;
+ cam->params.roi.rowEnd=66;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_288_216:
+ cam->vw.width = 288;
+ cam->vw.height = 216;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=4;
+ cam->params.roi.colEnd=40;
+ cam->params.roi.rowStart=9;
+ cam->params.roi.rowEnd=63;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_256_192:
+ cam->vw.width = 256;
+ cam->vw.height = 192;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=6;
+ cam->params.roi.colEnd=38;
+ cam->params.roi.rowStart=12;
+ cam->params.roi.rowEnd=60;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_224_168:
+ cam->vw.width = 224;
+ cam->vw.height = 168;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=8;
+ cam->params.roi.colEnd=36;
+ cam->params.roi.rowStart=15;
+ cam->params.roi.rowEnd=57;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_192_144:
+ cam->vw.width = 192;
+ cam->vw.height = 144;
+ cam->params.format.videoSize=VIDEOSIZE_CIF;
+ cam->params.roi.colStart=10;
+ cam->params.roi.colEnd=34;
+ cam->params.roi.rowStart=18;
+ cam->params.roi.rowEnd=54;
+ cam->params.streamStartLine = 120;
+ break;
+ case VIDEOSIZE_QCIF:
+ cam->vw.width = 176;
+ cam->vw.height = 144;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=0;
+ cam->params.roi.colEnd=22;
+ cam->params.roi.rowStart=0;
+ cam->params.roi.rowEnd=36;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_QSIF:
+ cam->vw.width = 160;
+ cam->vw.height = 120;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=1;
+ cam->params.roi.colEnd=21;
+ cam->params.roi.rowStart=3;
+ cam->params.roi.rowEnd=33;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_128_96:
+ cam->vw.width = 128;
+ cam->vw.height = 96;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=3;
+ cam->params.roi.colEnd=19;
+ cam->params.roi.rowStart=6;
+ cam->params.roi.rowEnd=30;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_88_72:
+ cam->vw.width = 88;
+ cam->vw.height = 72;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=5;
+ cam->params.roi.colEnd=16;
+ cam->params.roi.rowStart=9;
+ cam->params.roi.rowEnd=27;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_64_48:
+ cam->vw.width = 64;
+ cam->vw.height = 48;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=7;
+ cam->params.roi.colEnd=15;
+ cam->params.roi.rowStart=12;
+ cam->params.roi.rowEnd=24;
+ cam->params.streamStartLine = 60;
+ break;
+ case VIDEOSIZE_48_48:
+ cam->vw.width = 48;
+ cam->vw.height = 48;
+ cam->params.format.videoSize=VIDEOSIZE_QCIF;
+ cam->params.roi.colStart=8;
+ cam->params.roi.colEnd=14;
+ cam->params.roi.rowStart=6;
+ cam->params.roi.rowEnd=30;
+ cam->params.streamStartLine = 60;
+ break;
+ default:
+ LOG("bad videosize value: %d\n", cam->video_size);
+ }
+
+ return;
+}
+
+static int allocate_frame_buf(struct cam_data *cam)
+{
+ int i;
+
+ cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
+ if (!cam->frame_buf)
+ return -ENOBUFS;
+
+ for (i = 0; i < FRAME_NUM; i++)
+ cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
+
+ return 0;
+}
+
+static int free_frame_buf(struct cam_data *cam)
+{
+ int i;
+
+ rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
+ cam->frame_buf = 0;
+ for (i=0; i < FRAME_NUM; i++)
+ cam->frame[i].data = NULL;
+
+ return 0;
+}
+
+
+static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
+{
+ int i;
+
+ for (i=0; i < FRAME_NUM; i++)
+ frame[i].state = FRAME_UNUSED;
+ return;
+}
+
+/**********************************************************************
+ *
+ * General functions
+ *
+ **********************************************************************/
+/* send an arbitrary command to the camera */
+static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
+{
+ int retval, datasize;
+ u8 cmd[8], data[8];
+
+ switch(command) {
+ case CPIA_COMMAND_GetCPIAVersion:
+ case CPIA_COMMAND_GetPnPID:
+ case CPIA_COMMAND_GetCameraStatus:
+ case CPIA_COMMAND_GetVPVersion:
+ datasize=8;
+ break;
+ case CPIA_COMMAND_GetColourParams:
+ case CPIA_COMMAND_GetColourBalance:
+ case CPIA_COMMAND_GetExposure:
+ down(&cam->param_lock);
+ datasize=8;
+ break;
+ default:
+ datasize=0;
+ break;
+ }
+
+ cmd[0] = command>>8;
+ cmd[1] = command&0xff;
+ cmd[2] = a;
+ cmd[3] = b;
+ cmd[4] = c;
+ cmd[5] = d;
+ cmd[6] = datasize;
+ cmd[7] = 0;
+
+ retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+ if (retval)
+ DBG("%x - failed, retval=%d\n", command, retval);
+ else {
+ switch(command) {
+ case CPIA_COMMAND_GetCPIAVersion:
+ cam->params.version.firmwareVersion = data[0];
+ cam->params.version.firmwareRevision = data[1];
+ cam->params.version.vcVersion = data[2];
+ cam->params.version.vcRevision = data[3];
+ break;
+ case CPIA_COMMAND_GetPnPID:
+ cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
+ cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
+ cam->params.pnpID.deviceRevision =
+ data[4]+(((u16)data[5])<<8);
+ break;
+ case CPIA_COMMAND_GetCameraStatus:
+ cam->params.status.systemState = data[0];
+ cam->params.status.grabState = data[1];
+ cam->params.status.streamState = data[2];
+ cam->params.status.fatalError = data[3];
+ cam->params.status.cmdError = data[4];
+ cam->params.status.debugFlags = data[5];
+ cam->params.status.vpStatus = data[6];
+ cam->params.status.errorCode = data[7];
+ break;
+ case CPIA_COMMAND_GetVPVersion:
+ cam->params.vpVersion.vpVersion = data[0];
+ cam->params.vpVersion.vpRevision = data[1];
+ cam->params.vpVersion.cameraHeadID =
+ data[2]+(((u16)data[3])<<8);
+ break;
+ case CPIA_COMMAND_GetColourParams:
+ cam->params.colourParams.brightness = data[0];
+ cam->params.colourParams.contrast = data[1];
+ cam->params.colourParams.saturation = data[2];
+ up(&cam->param_lock);
+ break;
+ case CPIA_COMMAND_GetColourBalance:
+ cam->params.colourBalance.redGain = data[0];
+ cam->params.colourBalance.greenGain = data[1];
+ cam->params.colourBalance.blueGain = data[2];
+ up(&cam->param_lock);
+ break;
+ case CPIA_COMMAND_GetExposure:
+ cam->params.exposure.gain = data[0];
+ cam->params.exposure.fineExp = data[1];
+ cam->params.exposure.coarseExpLo = data[2];
+ cam->params.exposure.coarseExpHi = data[3];
+ cam->params.exposure.redComp = data[4];
+ cam->params.exposure.green1Comp = data[5];
+ cam->params.exposure.green2Comp = data[6];
+ cam->params.exposure.blueComp = data[7];
+ /* If the *Comp parameters are wacko, generate
+ * a warning, and reset them back to default
+ * values. - rich@annexia.org
+ */
+ if (cam->params.exposure.redComp < 220 ||
+ cam->params.exposure.redComp > 255 ||
+ cam->params.exposure.green1Comp < 214 ||
+ cam->params.exposure.green1Comp > 255 ||
+ cam->params.exposure.green2Comp < 214 ||
+ cam->params.exposure.green2Comp > 255 ||
+ cam->params.exposure.blueComp < 230 ||
+ cam->params.exposure.blueComp > 255)
+ {
+ printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
+ cam->params.exposure.redComp,
+ cam->params.exposure.green1Comp,
+ cam->params.exposure.green2Comp,
+ cam->params.exposure.blueComp);
+ cam->params.exposure.redComp = 220;
+ cam->params.exposure.green1Comp = 214;
+ cam->params.exposure.green2Comp = 214;
+ cam->params.exposure.blueComp = 230;
+ }
+ up(&cam->param_lock);
+ break;
+ default:
+ break;
+ }
+ }
+ return retval;
+}
+
+/* send a command to the camera with an additional data transaction */
+static int do_command_extended(struct cam_data *cam, u16 command,
+ u8 a, u8 b, u8 c, u8 d,
+ u8 e, u8 f, u8 g, u8 h,
+ u8 i, u8 j, u8 k, u8 l)
+{
+ int retval;
+ u8 cmd[8], data[8];
+
+ cmd[0] = command>>8;
+ cmd[1] = command&0xff;
+ cmd[2] = a;
+ cmd[3] = b;
+ cmd[4] = c;
+ cmd[5] = d;
+ cmd[6] = 8;
+ cmd[7] = 0;
+ data[0] = e;
+ data[1] = f;
+ data[2] = g;
+ data[3] = h;
+ data[4] = i;
+ data[5] = j;
+ data[6] = k;
+ data[7] = l;
+
+ retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+ if (retval)
+ LOG("%x - failed\n", command);
+
+ return retval;
+}
+
+/**********************************************************************
+ *
+ * Colorspace conversion
+ *
+ **********************************************************************/
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+
+static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
+ int in_uyvy, int mmap_kludge)
+{
+ int y, u, v, r, g, b, y1;
+
+ switch(out_fmt) {
+ case VIDEO_PALETTE_RGB555:
+ case VIDEO_PALETTE_RGB565:
+ case VIDEO_PALETTE_RGB24:
+ case VIDEO_PALETTE_RGB32:
+ if (in_uyvy) {
+ u = *yuv++ - 128;
+ y = (*yuv++ - 16) * 76310;
+ v = *yuv++ - 128;
+ y1 = (*yuv - 16) * 76310;
+ } else {
+ y = (*yuv++ - 16) * 76310;
+ u = *yuv++ - 128;
+ y1 = (*yuv++ - 16) * 76310;
+ v = *yuv - 128;
+ }
+ r = 104635 * v;
+ g = -25690 * u + -53294 * v;
+ b = 132278 * u;
+ break;
+ default:
+ y = *yuv++;
+ u = *yuv++;
+ y1 = *yuv++;
+ v = *yuv;
+ /* Just to avoid compiler warnings */
+ r = 0;
+ g = 0;
+ b = 0;
+ break;
+ }
+ switch(out_fmt) {
+ case VIDEO_PALETTE_RGB555:
+ *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
+ *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
+ *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
+ *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
+ return 4;
+ case VIDEO_PALETTE_RGB565:
+ *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
+ *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
+ *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
+ *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
+ return 4;
+ case VIDEO_PALETTE_RGB24:
+ if (mmap_kludge) {
+ *rgb++ = LIMIT(b+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(r+y);
+ *rgb++ = LIMIT(b+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(r+y1);
+ } else {
+ *rgb++ = LIMIT(r+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(b+y);
+ *rgb++ = LIMIT(r+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(b+y1);
+ }
+ return 6;
+ case VIDEO_PALETTE_RGB32:
+ if (mmap_kludge) {
+ *rgb++ = LIMIT(b+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(r+y);
+ rgb++;
+ *rgb++ = LIMIT(b+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(r+y1);
+ } else {
+ *rgb++ = LIMIT(r+y);
+ *rgb++ = LIMIT(g+y);
+ *rgb++ = LIMIT(b+y);
+ rgb++;
+ *rgb++ = LIMIT(r+y1);
+ *rgb++ = LIMIT(g+y1);
+ *rgb = LIMIT(b+y1);
+ }
+ return 8;
+ case VIDEO_PALETTE_GREY:
+ *rgb++ = y;
+ *rgb = y1;
+ return 2;
+ case VIDEO_PALETTE_YUV422:
+ case VIDEO_PALETTE_YUYV:
+ *rgb++ = y;
+ *rgb++ = u;
+ *rgb++ = y1;
+ *rgb = v;
+ return 4;
+ case VIDEO_PALETTE_UYVY:
+ *rgb++ = u;
+ *rgb++ = y;
+ *rgb++ = v;
+ *rgb = y1;
+ return 4;
+ default:
+ DBG("Empty: %d\n", out_fmt);
+ return 0;
+ }
+}
+
+static int skipcount(int count, int fmt)
+{
+ switch(fmt) {
+ case VIDEO_PALETTE_GREY:
+ case VIDEO_PALETTE_RGB555:
+ case VIDEO_PALETTE_RGB565:
+ case VIDEO_PALETTE_YUV422:
+ case VIDEO_PALETTE_YUYV:
+ case VIDEO_PALETTE_UYVY:
+ return 2*count;
+ case VIDEO_PALETTE_RGB24:
+ return 3*count;
+ case VIDEO_PALETTE_RGB32:
+ return 4*count;
+ default:
+ return 0;
+ }
+}
+
+static int parse_picture(struct cam_data *cam, int size)
+{
+ u8 *obuf, *ibuf, *end_obuf;
+ int ll, in_uyvy, compressed, origsize, out_fmt;
+
+ /* make sure params don't change while we are decoding */
+ down(&cam->param_lock);
+
+ obuf = cam->decompressed_frame.data;
+ end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
+ ibuf = cam->raw_image;
+ origsize = size;
+ out_fmt = cam->vp.palette;
+
+ if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
+ LOG("header not found\n");
+ up(&cam->param_lock);
+ return -1;
+ }
+
+ if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
+ LOG("wrong video size\n");
+ up(&cam->param_lock);
+ return -1;
+ }
+
+ if (ibuf[17] != SUBSAMPLE_422) {
+ LOG("illegal subtype %d\n",ibuf[17]);
+ up(&cam->param_lock);
+ return -1;
+ }
+
+ if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
+ LOG("illegal yuvorder %d\n",ibuf[18]);
+ up(&cam->param_lock);
+ return -1;
+ }
+ in_uyvy = ibuf[18] == YUVORDER_UYVY;
+
+#if 0
+ /* FIXME: ROI mismatch occurs when switching capture sizes */
+ if ((ibuf[24] != cam->params.roi.colStart) ||
+ (ibuf[25] != cam->params.roi.colEnd) ||
+ (ibuf[26] != cam->params.roi.rowStart) ||
+ (ibuf[27] != cam->params.roi.rowEnd)) {
+ LOG("ROI mismatch\n");
+ up(&cam->param_lock);
+ return -1;
+ }
+#endif
+
+ if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
+ LOG("illegal compression %d\n",ibuf[28]);
+ up(&cam->param_lock);
+ return -1;
+ }
+ compressed = (ibuf[28] == COMPRESSED);
+
+ if (ibuf[29] != NO_DECIMATION) {
+ LOG("decimation not supported\n");
+ up(&cam->param_lock);
+ return -1;
+ }
+
+ cam->params.yuvThreshold.yThreshold = ibuf[30];
+ cam->params.yuvThreshold.uvThreshold = ibuf[31];
+ cam->params.status.systemState = ibuf[32];
+ cam->params.status.grabState = ibuf[33];
+ cam->params.status.streamState = ibuf[34];
+ cam->params.status.fatalError = ibuf[35];
+ cam->params.status.cmdError = ibuf[36];
+ cam->params.status.debugFlags = ibuf[37];
+ cam->params.status.vpStatus = ibuf[38];
+ cam->params.status.errorCode = ibuf[39];
+ cam->fps = ibuf[41];
+ up(&cam->param_lock);
+
+ ibuf += FRAME_HEADER_SIZE;
+ size -= FRAME_HEADER_SIZE;
+ ll = ibuf[0] | (ibuf[1] << 8);
+ ibuf += 2;
+
+ while (size > 0) {
+ size -= (ll+2);
+ if (size < 0) {
+ LOG("Insufficient data in buffer\n");
+ return -1;
+ }
+
+ while (ll > 1) {
+ if (!compressed || (compressed && !(*ibuf & 1))) {
+ obuf += yuvconvert(ibuf, obuf, out_fmt,
+ in_uyvy, cam->mmap_kludge);
+ ibuf += 4;
+ ll -= 4;
+ } else {
+ /*skip compressed interval from previous frame*/
+ int skipsize = skipcount(*ibuf >> 1, out_fmt);
+ obuf += skipsize;
+ if (obuf > end_obuf) {
+ LOG("Insufficient data in buffer\n");
+ return -1;
+ }
+ ++ibuf;
+ ll--;
+ }
+ }
+ if (ll == 1) {
+ if (*ibuf != EOL) {
+ LOG("EOL not found giving up after %d/%d"
+ " bytes\n", origsize-size, origsize);
+ return -1;
+ }
+
+ ibuf++; /* skip over EOL */
+
+ if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
+ (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
+ size -= 4;
+ break;
+ }
+
+ if (size > 1) {
+ ll = ibuf[0] | (ibuf[1] << 8);
+ ibuf += 2; /* skip over line length */
+ }
+ } else {
+ LOG("line length was not 1 but %d after %d/%d bytes\n",
+ ll, origsize-size, origsize);
+ return -1;
+ }
+ }
+
+ cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
+
+ return cam->decompressed_frame.count;
+}
+
+/* InitStreamCap wrapper to select correct start line */
+static inline int init_stream_cap(struct cam_data *cam)
+{
+ return do_command(cam, CPIA_COMMAND_InitStreamCap,
+ 0, cam->params.streamStartLine, 0, 0);
+}
+
+/* update various camera modes and settings */
+static void dispatch_commands(struct cam_data *cam)
+{
+ down(&cam->param_lock);
+ if (cam->cmd_queue==COMMAND_NONE) {
+ up(&cam->param_lock);
+ return;
+ }
+ DEB_BYTE(cam->cmd_queue);
+ DEB_BYTE(cam->cmd_queue>>8);
+ if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
+ do_command(cam, CPIA_COMMAND_SetColourParams,
+ cam->params.colourParams.brightness,
+ cam->params.colourParams.contrast,
+ cam->params.colourParams.saturation, 0);
+
+ if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
+ do_command(cam, CPIA_COMMAND_SetCompression,
+ cam->params.compression.mode,
+ cam->params.compression.decimation, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_SETFORMAT) {
+ do_command(cam, CPIA_COMMAND_SetFormat,
+ cam->params.format.videoSize,
+ cam->params.format.subSample,
+ cam->params.format.yuvOrder, 0);
+ do_command(cam, CPIA_COMMAND_SetROI,
+ cam->params.roi.colStart, cam->params.roi.colEnd,
+ cam->params.roi.rowStart, cam->params.roi.rowEnd);
+ cam->first_frame = 1;
+ }
+
+ if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
+ do_command(cam, CPIA_COMMAND_SetCompressionTarget,
+ cam->params.compressionTarget.frTargeting,
+ cam->params.compressionTarget.targetFR,
+ cam->params.compressionTarget.targetQ, 0);
+
+ if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
+ do_command(cam, CPIA_COMMAND_SetYUVThresh,
+ cam->params.yuvThreshold.yThreshold,
+ cam->params.yuvThreshold.uvThreshold, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_SETECPTIMING)
+ do_command(cam, CPIA_COMMAND_SetECPTiming,
+ cam->params.ecpTiming, 0, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
+ do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
+ 0, 0, 0, 0,
+ cam->params.compressionParams.hysteresis,
+ cam->params.compressionParams.threshMax,
+ cam->params.compressionParams.smallStep,
+ cam->params.compressionParams.largeStep,
+ cam->params.compressionParams.decimationHysteresis,
+ cam->params.compressionParams.frDiffStepThresh,
+ cam->params.compressionParams.qDiffStepThresh,
+ cam->params.compressionParams.decimationThreshMod);
+
+ if (cam->cmd_queue & COMMAND_SETEXPOSURE)
+ do_command_extended(cam, CPIA_COMMAND_SetExposure,
+ cam->params.exposure.gainMode,
+ cam->params.exposure.expMode,
+ cam->params.exposure.compMode,
+ cam->params.exposure.centreWeight,
+ cam->params.exposure.gain,
+ cam->params.exposure.fineExp,
+ cam->params.exposure.coarseExpLo,
+ cam->params.exposure.coarseExpHi,
+ cam->params.exposure.redComp,
+ cam->params.exposure.green1Comp,
+ cam->params.exposure.green2Comp,
+ cam->params.exposure.blueComp);
+
+ if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
+ if (cam->params.colourBalance.balanceModeIsAuto) {
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 2, 0, 0, 0);
+ } else {
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 1,
+ cam->params.colourBalance.redGain,
+ cam->params.colourBalance.greenGain,
+ cam->params.colourBalance.blueGain);
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 3, 0, 0, 0);
+ }
+ }
+
+ if (cam->cmd_queue & COMMAND_SETSENSORFPS)
+ do_command(cam, CPIA_COMMAND_SetSensorFPS,
+ cam->params.sensorFps.divisor,
+ cam->params.sensorFps.baserate, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_SETAPCOR)
+ do_command(cam, CPIA_COMMAND_SetApcor,
+ cam->params.apcor.gain1,
+ cam->params.apcor.gain2,
+ cam->params.apcor.gain4,
+ cam->params.apcor.gain8);
+
+ if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
+ do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
+ cam->params.flickerControl.flickerMode,
+ cam->params.flickerControl.coarseJump,
+ cam->params.flickerControl.allowableOverExposure, 0);
+
+ if (cam->cmd_queue & COMMAND_SETVLOFFSET)
+ do_command(cam, CPIA_COMMAND_SetVLOffset,
+ cam->params.vlOffset.gain1,
+ cam->params.vlOffset.gain2,
+ cam->params.vlOffset.gain4,
+ cam->params.vlOffset.gain8);
+
+ if (cam->cmd_queue & COMMAND_PAUSE)
+ do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
+
+ if (cam->cmd_queue & COMMAND_RESUME)
+ init_stream_cap(cam);
+
+ up(&cam->param_lock);
+ cam->cmd_queue = COMMAND_NONE;
+ return;
+}
+
+/* kernel thread function to read image from camera */
+static void fetch_frame(void *data)
+{
+ int image_size, retry;
+ struct cam_data *cam = (struct cam_data *)data;
+ unsigned long oldjif, rate, diff;
+
+ /* Allow up to two bad images in a row to be read and
+ * ignored before an error is reported */
+ for (retry = 0; retry < 3; ++retry) {
+ if (retry)
+ DBG("retry=%d\n", retry);
+
+ if (!cam->ops)
+ continue;
+
+ /* load first frame always uncompressed */
+ if (cam->first_frame &&
+ cam->params.compression.mode != CPIA_COMPRESSION_NONE)
+ do_command(cam, CPIA_COMMAND_SetCompression,
+ CPIA_COMPRESSION_NONE,
+ NO_DECIMATION, 0, 0);
+
+ /* init camera upload */
+ if (do_command(cam, CPIA_COMMAND_SetGrabMode,
+ CPIA_GRAB_CONTINUOUS, 0, 0, 0))
+ continue;
+
+ if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
+ cam->params.streamStartLine, 0, 0))
+ continue;
+
+ if (cam->ops->wait_for_stream_ready) {
+ /* loop until image ready */
+ do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
+ while (cam->params.status.streamState != STREAM_READY) {
+ if (current->need_resched)
+ schedule();
+
+ current->state = TASK_INTERRUPTIBLE;
+
+ /* sleep for 10 ms, hopefully ;) */
+ schedule_timeout(10*HZ/1000);
+ if (signal_pending(current))
+ return;
+
+ do_command(cam, CPIA_COMMAND_GetCameraStatus,
+ 0, 0, 0, 0);
+ }
+ }
+
+ /* grab image from camera */
+ if (current->need_resched)
+ schedule();
+
+ oldjif = jiffies;
+ image_size = cam->ops->streamRead(cam->lowlevel_data,
+ cam->raw_image, 0);
+ if (image_size <= 0) {
+ DBG("streamRead failed: %d\n", image_size);
+ continue;
+ }
+
+ rate = image_size * HZ / 1024;
+ diff = jiffies-oldjif;
+ cam->transfer_rate = diff==0 ? rate : rate/diff;
+ /* diff==0 ? unlikely but possible */
+
+ /* camera idle now so dispatch queued commands */
+ dispatch_commands(cam);
+
+ /* Update our knowledge of the camera state - FIXME: necessary? */
+ do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+ do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+
+ /* decompress and convert image to by copying it from
+ * raw_image to decompressed_frame
+ */
+ if (current->need_resched)
+ schedule();
+
+ cam->image_size = parse_picture(cam, image_size);
+ if (cam->image_size <= 0)
+ DBG("parse_picture failed %d\n", cam->image_size);
+ else
+ break;
+ }
+
+ if (retry < 3) {
+ /* FIXME: this only works for double buffering */
+ if (cam->frame[cam->curframe].state == FRAME_READY) {
+ memcpy(cam->frame[cam->curframe].data,
+ cam->decompressed_frame.data,
+ cam->decompressed_frame.count);
+ cam->frame[cam->curframe].state = FRAME_DONE;
+ } else
+ cam->decompressed_frame.state = FRAME_DONE;
+
+#if 0
+ if (cam->first_frame &&
+ cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
+ cam->first_frame = 0;
+ cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+ }
+#else
+ if (cam->first_frame) {
+ cam->first_frame = 0;
+ cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+ cam->cmd_queue |= COMMAND_SETEXPOSURE;
+ }
+#endif
+ }
+}
+
+static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
+{
+ int retval = 0;
+
+ if (!cam->frame_buf) {
+ /* we do lazy allocation */
+ if ((retval = allocate_frame_buf(cam)))
+ return retval;
+ }
+
+ /* FIXME: the first frame seems to be captured by the camera
+ without regards to any initial settings, so we throw away
+ that one, the next one is generated with our settings
+ (exposure, color balance, ...)
+ */
+ if (cam->first_frame) {
+ cam->curframe = vm->frame;
+ cam->frame[cam->curframe].state = FRAME_READY;
+ fetch_frame(cam);
+ if (cam->frame[cam->curframe].state != FRAME_DONE)
+ retval = -EIO;
+ }
+ cam->curframe = vm->frame;
+ cam->frame[cam->curframe].state = FRAME_READY;
+ fetch_frame(cam);
+ if (cam->frame[cam->curframe].state != FRAME_DONE)
+ retval=-EIO;
+
+ return retval;
+}
+
+static int goto_high_power(struct cam_data *cam)
+{
+ if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
+ return -1;
+ mdelay(100); /* windows driver does it too */
+ if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+ return -1;
+ if (cam->params.status.systemState == HI_POWER_STATE) {
+ DBG("camera now in HIGH power state\n");
+ return 0;
+ }
+ printstatus(cam);
+ return -1;
+}
+
+static int goto_low_power(struct cam_data *cam)
+{
+ if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
+ return -1;
+ if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+ return -1;
+ if (cam->params.status.systemState == LO_POWER_STATE) {
+ DBG("camera now in LOW power state\n");
+ return 0;
+ }
+ printstatus(cam);
+ return -1;
+}
+
+static void save_camera_state(struct cam_data *cam)
+{
+ do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+ do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+
+ DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
+ cam->params.exposure.gain,
+ cam->params.exposure.fineExp,
+ cam->params.exposure.coarseExpLo,
+ cam->params.exposure.coarseExpHi,
+ cam->params.exposure.redComp,
+ cam->params.exposure.green1Comp,
+ cam->params.exposure.green2Comp,
+ cam->params.exposure.blueComp);
+ DBG("%d/%d/%d\n",
+ cam->params.colourBalance.redGain,
+ cam->params.colourBalance.greenGain,
+ cam->params.colourBalance.blueGain);
+}
+
+static void set_camera_state(struct cam_data *cam)
+{
+ if(cam->params.colourBalance.balanceModeIsAuto) {
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 2, 0, 0, 0);
+ } else {
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 1,
+ cam->params.colourBalance.redGain,
+ cam->params.colourBalance.greenGain,
+ cam->params.colourBalance.blueGain);
+ do_command(cam, CPIA_COMMAND_SetColourBalance,
+ 3, 0, 0, 0);
+ }
+
+
+ do_command_extended(cam, CPIA_COMMAND_SetExposure,
+ cam->params.exposure.gainMode, 1, 1,
+ cam->params.exposure.centreWeight,
+ cam->params.exposure.gain,
+ cam->params.exposure.fineExp,
+ cam->params.exposure.coarseExpLo,
+ cam->params.exposure.coarseExpHi,
+ cam->params.exposure.redComp,
+ cam->params.exposure.green1Comp,
+ cam->params.exposure.green2Comp,
+ cam->params.exposure.blueComp);
+ do_command_extended(cam, CPIA_COMMAND_SetExposure,
+ 0, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+
+ if (!cam->params.exposure.gainMode)
+ cam->params.exposure.gainMode = 2;
+ if (!cam->params.exposure.expMode)
+ cam->params.exposure.expMode = 2;
+ if (!cam->params.exposure.centreWeight)
+ cam->params.exposure.centreWeight = 1;
+
+ cam->cmd_queue = COMMAND_SETCOMPRESSION |
+ COMMAND_SETCOMPRESSIONTARGET |
+ COMMAND_SETCOLOURPARAMS |
+ COMMAND_SETFORMAT |
+ COMMAND_SETYUVTHRESH |
+ COMMAND_SETECPTIMING |
+ COMMAND_SETCOMPRESSIONPARAMS |
+#if 0
+ COMMAND_SETEXPOSURE |
+#endif
+ COMMAND_SETCOLOURBALANCE |
+ COMMAND_SETSENSORFPS |
+ COMMAND_SETAPCOR |
+ COMMAND_SETFLICKERCTRL |
+ COMMAND_SETVLOFFSET;
+ dispatch_commands(cam);
+ save_camera_state(cam);
+
+ return;
+}
+
+static void get_version_information(struct cam_data *cam)
+{
+ /* GetCPIAVersion */
+ do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
+
+ /* GetPnPID */
+ do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
+}
+
+/* initialize camera */
+static int reset_camera(struct cam_data *cam)
+{
+ /* Start the camera in low power mode */
+ if (goto_low_power(cam)) {
+ if (cam->params.status.systemState != WARM_BOOT_STATE)
+ return -ENODEV;
+
+ /* FIXME: this is just dirty trial and error */
+ reset_camera_struct(cam);
+ goto_high_power(cam);
+ do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
+ if (goto_low_power(cam))
+ return -NODEV;
+ }
+
+ /* procedure described in developer's guide p3-28 */
+
+ /* Check the firmware version FIXME: should we check PNPID? */
+ cam->params.version.firmwareVersion = 0;
+ get_version_information(cam);
+ if (cam->params.version.firmwareVersion != 1)
+ return -ENODEV;
+
+ /* The fatal error checking should be done after
+ * the camera powers up (developer's guide p 3-38) */
+
+ /* Set streamState before transition to high power to avoid bug
+ * in firmware 1-02 */
+ do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
+ STREAM_NOT_READY, 0);
+
+ /* GotoHiPower */
+ if (goto_high_power(cam))
+ return -ENODEV;
+
+ /* Check the camera status */
+ if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+ return -EIO;
+
+ if (cam->params.status.fatalError) {
+ DBG("fatal_error: %#04x\n",
+ cam->params.status.fatalError);
+ DBG("vp_status: %#04x\n",
+ cam->params.status.vpStatus);
+ if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
+ /* Fatal error in camera */
+ return -EIO;
+ } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
+ /* Firmware 1-02 may do this for parallel port cameras,
+ * just clear the flags (developer's guide p 3-38) */
+ do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
+ FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
+ }
+ }
+
+ /* Check the camera status again */
+ if (cam->params.status.fatalError) {
+ if (cam->params.status.fatalError)
+ return -EIO;
+ }
+
+ /* VPVersion can't be retrieved before the camera is in HiPower,
+ * so get it here instead of in get_version_information. */
+ do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
+
+ /* set camera to a known state */
+ set_camera_state(cam);
+
+ return 0;
+}
+
+/* ------------------------- V4L interface --------------------- */
+static int cpia_open(struct video_device *dev, int flags)
+{
+ int i;
+ struct cam_data *cam = dev->priv;
+
+ if (!cam) {
+ DBG("Internal error, cam_data not found!\n");
+ return -EBUSY;
+ }
+
+ if (cam->open_count > 0) {
+ DBG("Camera already open\n");
+ return -EBUSY;
+ }
+
+ if (!cam->raw_image) {
+ cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
+ if (!cam->raw_image)
+ return -ENOMEM;
+ }
+
+ if (!cam->decompressed_frame.data) {
+ cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
+ if (!cam->decompressed_frame.data) {
+ rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+ cam->raw_image = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ /* open cpia */
+ if (cam->ops->open(cam->lowlevel_data)) {
+ rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+ cam->decompressed_frame.data = NULL;
+ rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+ cam->raw_image = NULL;
+ return -ENODEV;
+ }
+
+ /* reset the camera */
+ if ((i = reset_camera(cam)) != 0) {
+ cam->ops->close(cam->lowlevel_data);
+ rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+ cam->decompressed_frame.data = NULL;
+ rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+ cam->raw_image = NULL;
+ return i;
+ }
+
+ /* Set ownership of /proc/cpia/videoX to current user */
+ if(cam->proc_entry)
+ cam->proc_entry->uid = current->uid;
+
+ /* set mark for loading first frame uncompressed */
+ cam->first_frame = 1;
+
+ /* init it to something */
+ cam->mmap_kludge = 0;
+
+ ++cam->open_count;
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static void cpia_close(struct video_device *dev)
+{
+ struct cam_data *cam;
+
+ cam = dev->priv;
+
+ if (cam->ops) {
+ /* Return ownership of /proc/cpia/videoX to root */
+ if(cam->proc_entry)
+ cam->proc_entry->uid = 0;
+
+ /* save camera state for later open (developers guide ch 3.5.3) */
+ save_camera_state(cam);
+
+ /* GotoLoPower */
+ goto_low_power(cam);
+
+ /* Update the camera ststus */
+ do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+
+ /* cleanup internal state stuff */
+ free_frames(cam->frame);
+
+ /* close cpia */
+ cam->ops->close(cam->lowlevel_data);
+ }
+
+ if (--cam->open_count == 0) {
+ /* clean up capture-buffers */
+ if (cam->raw_image) {
+ rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+ cam->raw_image = NULL;
+ }
+
+ if (cam->decompressed_frame.data) {
+ rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+ cam->decompressed_frame.data = NULL;
+ }
+
+ if (cam->frame_buf)
+ free_frame_buf(cam);
+
+ if (!cam->ops) {
+ video_unregister_device(dev);
+ kfree(cam);
+ }
+ }
+
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return;
+}
+
+static long cpia_read(struct video_device *dev, char *buf,
+ unsigned long count, int noblock)
+{
+ struct cam_data *cam = dev->priv;
+
+ /* make this _really_ smp and multithredi-safe */
+ if (down_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ if (!buf) {
+ DBG("buf NULL\n");
+ up(&cam->busy_lock);
+ return -EINVAL;
+ }
+
+ if (!count) {
+ DBG("count 0\n");
+ up(&cam->busy_lock);
+ return 0;
+ }
+
+ if (!cam->ops) {
+ DBG("ops NULL\n");
+ up(&cam->busy_lock);
+ return -ENODEV;
+ }
+
+ /* upload frame */
+ cam->decompressed_frame.state = FRAME_READY;
+ cam->mmap_kludge=0;
+ fetch_frame(cam);
+ if (cam->decompressed_frame.state != FRAME_DONE) {
+ DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
+ cam->decompressed_frame.state);
+ up(&cam->busy_lock);
+ return -EIO;
+ }
+ cam->decompressed_frame.state = FRAME_UNUSED;
+
+ /* copy data to user space */
+ if (cam->decompressed_frame.count > count) {
+ DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
+ count);
+ up(&cam->busy_lock);
+ return -EFAULT;
+ }
+ if (copy_to_user(buf, cam->decompressed_frame.data,
+ cam->decompressed_frame.count)) {
+ DBG("copy_to_user failed\n");
+ up(&cam->busy_lock);
+ return -EFAULT;
+ }
+
+ up(&cam->busy_lock);
+ return cam->decompressed_frame.count;
+}
+
+static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
+{
+ struct cam_data *cam = dev->priv;
+ int retval = 0;
+
+ if (!cam || !cam->ops)
+ return -ENODEV;
+
+ /* make this _really_ smp-safe */
+ if (down_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ //DBG("cpia_ioctl: %u\n", ioctlnr);
+
+ switch (ioctlnr) {
+ /* query capabilites */
+ case VIDIOCGCAP:
+ {
+ struct video_capability b;
+
+ DBG("VIDIOCGCAP\n");
+ strcpy(b.name, "CPiA Camera");
+ b.type = VID_TYPE_CAPTURE;
+ b.channels = 1;
+ b.audios = 0;
+ b.maxwidth = 352; /* VIDEOSIZE_CIF */
+ b.maxheight = 288;
+ b.minwidth = 48; /* VIDEOSIZE_48_48 */
+ b.minheight = 48;
+
+ if (copy_to_user(arg, &b, sizeof(b)))
+ retval = -EFAULT;
+
+ break;
+ }
+
+ /* get/set video source - we are a camera and nothing else */
+ case VIDIOCGCHAN:
+ {
+ struct video_channel v;
+
+ DBG("VIDIOCGCHAN\n");
+ if (copy_from_user(&v, arg, sizeof(v))) {
+ retval = -EFAULT;
+ break;
+ }
+ if (v.channel != 0) {
+ retval = -EINVAL;
+ break;
+ }
+
+ v.channel = 0;
+ strcpy(v.name, "Camera");
+ v.tuners = 0;
+ v.flags = 0;
+ v.type = VIDEO_TYPE_CAMERA;
+ v.norm = 0;
+
+ if (copy_to_user(arg, &v, sizeof(v)))
+ retval = -EFAULT;
+ break;
+ }
+
+ case VIDIOCSCHAN:
+ {
+ int v;
+
+ DBG("VIDIOCSCHAN\n");
+ if (copy_from_user(&v, arg, sizeof(v)))
+ retval = -EFAULT;
+
+ if (retval == 0 && v != 0)
+ retval = -EINVAL;
+
+ break;
+ }
+
+ /* image properties */
+ case VIDIOCGPICT:
+ DBG("VIDIOCGPICT\n");
+ if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
+ retval = -EFAULT;
+ break;
+
+ case VIDIOCSPICT:
+ {
+ struct video_picture vp;
+
+ DBG("VIDIOCSPICT\n");
+
+ /* copy_from_user */
+ if (copy_from_user(&vp, arg, sizeof(vp))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ /* check validity */
+ DBG("palette: %d\n", vp.palette);
+ DBG("depth: %d\n", vp.depth);
+ if (!valid_mode(vp.palette, vp.depth)) {
+ retval = -EINVAL;
+ break;
+ }
+
+ down(&cam->param_lock);
+ /* brightness, colour, contrast need no check 0-65535 */
+ memcpy( &cam->vp, &vp, sizeof(vp) );
+ /* update cam->params.colourParams */
+ cam->params.colourParams.brightness = vp.brightness*100/65535;
+ cam->params.colourParams.contrast = vp.contrast*100/65535;
+ cam->params.colourParams.saturation = vp.colour*100/65535;
+ /* contrast is in steps of 8, so round */
+ cam->params.colourParams.contrast =
+ ((cam->params.colourParams.contrast + 3) / 8) * 8;
+ if (cam->params.version.firmwareVersion == 1 &&
+ cam->params.version.firmwareRevision == 2 &&
+ cam->params.colourParams.contrast > 80) {
+ /* 1-02 firmware limits contrast to 80 */
+ cam->params.colourParams.contrast = 80;
+ }
+
+ /* queue command to update camera */
+ cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
+ up(&cam->param_lock);
+ DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
+ vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
+ vp.contrast);
+ break;
+ }
+
+ /* get/set capture window */
+ case VIDIOCGWIN:
+ DBG("VIDIOCGWIN\n");
+
+ if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
+ retval = -EFAULT;
+ break;
+
+ case VIDIOCSWIN:
+ {
+ /* copy_from_user, check validity, copy to internal structure */
+ struct video_window vw;
+ DBG("VIDIOCSWIN\n");
+ if (copy_from_user(&vw, arg, sizeof(vw))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (vw.clipcount != 0) { /* clipping not supported */
+ retval = -EINVAL;
+ break;
+ }
+ if (vw.clips != NULL) { /* clipping not supported */
+ retval = -EINVAL;
+ break;
+ }
+
+ /* we set the video window to something smaller or equal to what
+ * is requested by the user???
+ */
+ down(&cam->param_lock);
+ if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
+ int video_size = match_videosize(vw.width, vw.height);
+
+ if (video_size < 0) {
+ retval = -EINVAL;
+ up(&cam->param_lock);
+ break;
+ }
+ cam->video_size = video_size;
+ set_vw_size(cam);
+ DBG("%d / %d\n", cam->vw.width, cam->vw.height);
+ cam->cmd_queue |= COMMAND_SETFORMAT;
+ }
+
+ // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
+ up(&cam->param_lock);
+
+ /* setformat ignored by camera during streaming,
+ * so stop/dispatch/start */
+ if (cam->cmd_queue & COMMAND_SETFORMAT) {
+ DBG("\n");
+ dispatch_commands(cam);
+ }
+ DBG("%d/%d:%d\n", cam->video_size,
+ cam->vw.width, cam->vw.height);
+ break;
+ }
+
+ /* mmap interface */
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf vm;
+ int i;
+
+ DBG("VIDIOCGMBUF\n");
+ memset(&vm, 0, sizeof(vm));
+ vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
+ vm.frames = FRAME_NUM;
+ for (i = 0; i < FRAME_NUM; i++)
+ vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
+
+ if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+ retval = -EFAULT;
+
+ break;
+ }
+
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap vm;
+ int video_size;
+
+ if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
+ retval = -EFAULT;
+ break;
+ }
+#if 1
+ DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
+ vm.width, vm.height);
+#endif
+ if (vm.frame<0||vm.frame>FRAME_NUM) {
+ retval = -EINVAL;
+ break;
+ }
+
+ /* set video format */
+ cam->vp.palette = vm.format;
+ switch(vm.format) {
+ case VIDEO_PALETTE_GREY:
+ case VIDEO_PALETTE_RGB555:
+ case VIDEO_PALETTE_RGB565:
+ case VIDEO_PALETTE_YUV422:
+ case VIDEO_PALETTE_YUYV:
+ case VIDEO_PALETTE_UYVY:
+ cam->vp.depth = 16;
+ break;
+ case VIDEO_PALETTE_RGB24:
+ cam->vp.depth = 24;
+ break;
+ case VIDEO_PALETTE_RGB32:
+ cam->vp.depth = 32;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ if (retval)
+ break;
+
+ /* set video size */
+ video_size = match_videosize(vm.width, vm.height);
+ if (cam->video_size < 0) {
+ retval = -EINVAL;
+ break;
+ }
+ if (video_size != cam->video_size) {
+ cam->video_size = video_size;
+ set_vw_size(cam);
+ cam->cmd_queue |= COMMAND_SETFORMAT;
+ dispatch_commands(cam);
+ }
+#if 0
+ DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
+ cam->vw.width, cam->vw.height);
+#endif
+ /* according to v4l-spec we must start streaming here */
+ cam->mmap_kludge = 1;
+ retval = capture_frame(cam, &vm);
+
+ break;
+ }
+
+ case VIDIOCSYNC:
+ {
+ int frame;
+
+ if (copy_from_user((void *)&frame, arg, sizeof(int))) {
+ retval = -EFAULT;
+ break;
+ }
+ //DBG("VIDIOCSYNC: %d\n", frame);
+
+ if (frame<0 || frame >= FRAME_NUM) {
+ retval = -EINVAL;
+ break;
+ }
+
+ switch (cam->frame[frame].state) {
+ case FRAME_UNUSED:
+ case FRAME_READY:
+ case FRAME_GRABBING:
+ DBG("sync to unused frame %d\n", frame);
+ retval = -EINVAL;
+ break;
+
+ case FRAME_DONE:
+ cam->frame[frame].state = FRAME_UNUSED;
+ //DBG("VIDIOCSYNC: %d synced\n", frame);
+ break;
+ }
+ if (retval == -EINTR) {
+ /* FIXME - xawtv does not handle this nice */
+ retval = 0;
+ }
+ break;
+ }
+
+ /* pointless to implement overlay with this camera */
+ case VIDIOCCAPTURE:
+ retval = -EINVAL;
+ break;
+ case VIDIOCGFBUF:
+ retval = -EINVAL;
+ break;
+ case VIDIOCSFBUF:
+ retval = -EINVAL;
+ break;
+ case VIDIOCKEY:
+ retval = -EINVAL;
+ break;
+
+ /* tuner interface - we have none */
+ case VIDIOCGTUNER:
+ retval = -EINVAL;
+ break;
+ case VIDIOCSTUNER:
+ retval = -EINVAL;
+ break;
+ case VIDIOCGFREQ:
+ retval = -EINVAL;
+ break;
+ case VIDIOCSFREQ:
+ retval = -EINVAL;
+ break;
+
+ /* audio interface - we have none */
+ case VIDIOCGAUDIO:
+ retval = -EINVAL;
+ break;
+ case VIDIOCSAUDIO:
+ retval = -EINVAL;
+ break;
+ default:
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+
+ up(&cam->param_lock);
+ up(&cam->busy_lock);
+ return retval;
+}
+
+/* FIXME */
+static int cpia_mmap(struct video_device *dev, const char *adr,
+ unsigned long size)
+{
+ unsigned long start = (unsigned long)adr;
+ unsigned long page, pos;
+ struct cam_data *cam = dev->priv;
+ int retval;
+
+ if (!cam || !cam->ops)
+ return -ENODEV;
+
+ DBG("cpia_mmap: %ld\n", size);
+
+ if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
+ return -EINVAL;
+
+ if (!cam || !cam->ops)
+ return -ENODEV;
+
+ /* make this _really_ smp-safe */
+ if (down_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ if (!cam->frame_buf) { /* we do lazy allocation */
+ if ((retval = allocate_frame_buf(cam))) {
+ up(&cam->busy_lock);
+ return retval;
+ }
+ }
+
+ pos = (unsigned long)(cam->frame_buf);
+ while (size > 0) {
+ page = kvirt_to_pa(pos);
+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+ up(&cam->busy_lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ DBG("cpia_mmap: %ld\n", size);
+ up(&cam->busy_lock);
+
+ return 0;
+}
+
+int cpia_video_init(struct video_device *vdev)
+{
+#ifdef CONFIG_PROC_FS
+ create_proc_cpia_cam(vdev->priv);
+#endif
+ return 0;
+}
+
+static struct video_device cpia_template = {
+ "CPiA Camera",
+ VID_TYPE_CAPTURE,
+ VID_HARDWARE_CPIA, /* FIXME */
+ cpia_open, /* open */
+ cpia_close, /* close */
+ cpia_read, /* read */
+ NULL, /* no write */
+ NULL, /* no poll */
+ cpia_ioctl, /* ioctl */
+ cpia_mmap, /* mmap */
+ cpia_video_init, /* initialize */
+ NULL, /* priv */
+ 0, /* busy */
+ -1 /* minor - unset */
+};
+
+/* initialise cam_data structure */
+static void reset_camera_struct(struct cam_data *cam)
+{
+ /* The following parameter values are the defaults from
+ * "Software Developer's Guide for CPiA Cameras". Any changes
+ * to the defaults are noted in comments. */
+ cam->params.colourParams.brightness = 50;
+ cam->params.colourParams.contrast = 48;
+ cam->params.colourParams.saturation = 50;
+ cam->params.exposure.gainMode = 2;
+ cam->params.exposure.expMode = 2; /* AEC */
+ cam->params.exposure.compMode = 1;
+ cam->params.exposure.centreWeight = 1;
+ cam->params.exposure.gain = 0;
+ cam->params.exposure.fineExp = 0;
+ cam->params.exposure.coarseExpLo = 185;
+ cam->params.exposure.coarseExpHi = 0;
+ cam->params.exposure.redComp = 220;
+ cam->params.exposure.green1Comp = 214;
+ cam->params.exposure.green2Comp = 214;
+ cam->params.exposure.blueComp = 230;
+ cam->params.colourBalance.balanceModeIsAuto = 1;
+ cam->params.colourBalance.redGain = 32;
+ cam->params.colourBalance.greenGain = 6;
+ cam->params.colourBalance.blueGain = 92;
+ cam->params.apcor.gain1 = 0x1c;
+ cam->params.apcor.gain2 = 0x1a;
+ cam->params.apcor.gain4 = 0x2d;
+ cam->params.apcor.gain8 = 0x2a;
+ cam->params.flickerControl.flickerMode = 0;
+ cam->params.flickerControl.coarseJump =
+ flicker_jumps[cam->mainsFreq]
+ [cam->params.sensorFps.baserate]
+ [cam->params.sensorFps.divisor];
+ cam->params.vlOffset.gain1 = 24;
+ cam->params.vlOffset.gain2 = 28;
+ cam->params.vlOffset.gain4 = 30;
+ cam->params.vlOffset.gain8 = 30;
+ cam->params.compressionParams.hysteresis = 3;
+ cam->params.compressionParams.threshMax = 11;
+ cam->params.compressionParams.smallStep = 1;
+ cam->params.compressionParams.largeStep = 3;
+ cam->params.compressionParams.decimationHysteresis = 2;
+ cam->params.compressionParams.frDiffStepThresh = 5;
+ cam->params.compressionParams.qDiffStepThresh = 3;
+ cam->params.compressionParams.decimationThreshMod = 2;
+ /* End of default values from Software Developer's Guide */
+
+ cam->transfer_rate = 0;
+
+ /* Set Sensor FPS to 15fps. This seems better than 30fps
+ * for indoor lighting. */
+ cam->params.sensorFps.divisor = 1;
+ cam->params.sensorFps.baserate = 1;
+
+ cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
+ cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+
+ cam->params.format.subSample = SUBSAMPLE_422;
+ cam->params.format.yuvOrder = YUVORDER_YUYV;
+
+ cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
+ cam->params.compressionTarget.frTargeting =
+ CPIA_COMPRESSION_TARGET_QUALITY;
+ cam->params.compressionTarget.targetFR = 7; /* FIXME? */
+ cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+
+ cam->video_size = VIDEOSIZE_CIF;
+
+ cam->vp.colour = 32768; /* 50% */
+ cam->vp.hue = 32768; /* 50% */
+ cam->vp.brightness = 32768; /* 50% */
+ cam->vp.contrast = 32768; /* 50% */
+ cam->vp.whiteness = 0; /* not used -> grayscale only */
+ cam->vp.depth = 0; /* FIXME: to be set by user? */
+ cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */
+
+ cam->vw.x = 0;
+ cam->vw.y = 0;
+ set_vw_size(cam);
+ cam->vw.chromakey = 0;
+ /* PP NOTE: my extension to use vw.flags for this, bear it! */
+ cam->vw.flags = 0;
+ cam->vw.clipcount = 0;
+ cam->vw.clips = NULL;
+
+ cam->cmd_queue = COMMAND_NONE;
+ cam->first_frame = 0;
+
+ return;
+}
+
+/* initialize cam_data structure */
+static void init_camera_struct(struct cam_data *cam,
+ struct cpia_camera_ops *ops )
+{
+ int i;
+
+ /* Default everything to 0 */
+ memset(cam, 0, sizeof(struct cam_data));
+
+ cam->ops = ops;
+ init_MUTEX(&cam->param_lock);
+ init_MUTEX(&cam->busy_lock);
+
+ reset_camera_struct(cam);
+
+ cam->proc_entry = NULL;
+
+ memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
+ cam->vdev.priv = cam;
+
+ cam->curframe = 0;
+ for (i = 0; i < FRAME_NUM; i++) {
+ cam->frame[i].width = 0;
+ cam->frame[i].height = 0;
+ cam->frame[i].state = FRAME_UNUSED;
+ cam->frame[i].data = NULL;
+ }
+ cam->decompressed_frame.width = 0;
+ cam->decompressed_frame.height = 0;
+ cam->decompressed_frame.state = FRAME_UNUSED;
+ cam->decompressed_frame.data = NULL;
+}
+
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
+{
+ struct cam_data *camera;
+
+ /* Need a lock when adding/removing cameras. This doesn't happen
+ * often and doesn't take very long, so grabbing the kernel lock
+ * should be OK. */
+
+ if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
+ unlock_kernel();
+ return NULL;
+ }
+
+ init_camera_struct( camera, ops );
+ camera->lowlevel_data = lowlevel;
+
+ /* register v4l device */
+ if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) {
+ kfree(camera);
+ unlock_kernel();
+ printk(KERN_DEBUG "video_register_device failed\n");
+ return NULL;
+ }
+
+ /* get version information from camera: open/reset/close */
+
+ /* open cpia */
+ if (camera->ops->open(camera->lowlevel_data))
+ return camera;
+
+ /* reset the camera */
+ if (reset_camera(camera) != 0) {
+ camera->ops->close(camera->lowlevel_data);
+ return camera;
+ }
+
+ /* close cpia */
+ camera->ops->close(camera->lowlevel_data);
+
+/* Eh? Feeling happy? - jerdfelt */
+/*
+ camera->ops->open(camera->lowlevel_data);
+ camera->ops->close(camera->lowlevel_data);
+*/
+
+ printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
+ camera->params.version.firmwareVersion,
+ camera->params.version.firmwareRevision,
+ camera->params.version.vcVersion,
+ camera->params.version.vcRevision);
+ printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
+ camera->params.pnpID.vendor,
+ camera->params.pnpID.product,
+ camera->params.pnpID.deviceRevision);
+ printk(KERN_INFO " VP-Version: %d.%d %04x\n",
+ camera->params.vpVersion.vpVersion,
+ camera->params.vpVersion.vpRevision,
+ camera->params.vpVersion.cameraHeadID);
+
+ return camera;
+}
+
+void cpia_unregister_camera(struct cam_data *cam)
+{
+ if (!cam->open_count) {
+ DBG("unregistering video\n");
+ video_unregister_device(&cam->vdev);
+ } else {
+ LOG("/dev/video%d removed while open, "
+ "deferring video_unregister_device\n", cam->vdev.minor);
+ DBG("camera open -- setting ops to NULL\n");
+ cam->ops = NULL;
+ }
+
+#ifdef CONFIG_PROC_FS
+ DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
+ destroy_proc_cpia_cam(cam);
+#endif
+ if (!cam->open_count) {
+ DBG("freeing camera\n");
+ kfree(cam);
+ }
+}
+
+/****************************************************************************
+ *
+ * Module routines
+ *
+ ***************************************************************************/
+
+#ifdef MODULE
+int init_module(void)
+{
+ printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
+ CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
+ proc_cpia_create();
+#endif
+#ifdef CONFIG_KMOD
+#ifdef CONFIG_VIDEO_CPIA_PP_MODULE
+ request_module("cpia_pp");
+#endif
+#ifdef CONFIG_VIDEO_CPIA_USB_MODULE
+ request_module("cpia_usb");
+#endif
+#endif
+return 0;
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_PROC_FS
+ proc_cpia_destroy();
+#endif
+}
+
+#else
+
+int cpia_init(struct video_init *unused)
+{
+ printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
+ CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
+ proc_cpia_create();
+#endif
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+ cpia_pp_init();
+#endif
+#ifdef CONFIG_KMOD
+#ifdef CONFIG_VIDEO_CPIA_PP_MODULE
+ request_module("cpia_pp");
+#endif
+
+#ifdef CONFIG_VIDEO_CPIA_USB_MODULE
+ request_module("cpia_usb");
+#endif
+#endif /* CONFIG_KMOD */
+#ifdef CONFIG_VIDEO_CPIA_USB
+ cpia_usb_init();
+#endif
+ return 0;
+}
+
+/* Exported symbols for modules. */
+
+EXPORT_SYMBOL(cpia_register_camera);
+EXPORT_SYMBOL(cpia_unregister_camera);
+
+#endif
diff --git a/drivers/char/cpia.h b/drivers/char/cpia.h
new file mode 100644
index 000000000..579b5e153
--- /dev/null
+++ b/drivers/char/cpia.h
@@ -0,0 +1,421 @@
+#ifndef cpia_h
+#define cpia_h
+
+/*
+ * CPiA Parallel Port Video4Linux driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman,
+ * Peter Pregler,
+ * Scott J. Bertin,
+ * VLSI Vision Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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.
+ */
+
+#define CPIA_MAJ_VER 0
+#define CPIA_MIN_VER 7
+#define CPIA_PATCH_VER 4
+
+#define CPIA_PP_MAJ_VER 0
+#define CPIA_PP_MIN_VER 7
+#define CPIA_PP_PATCH_VER 4
+
+#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */
+#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
+
+#ifdef __KERNEL__
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+struct cpia_camera_ops
+{
+ /* open sets privdata to point to structure for this camera.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*open)(void *privdata);
+
+ /* Registers callback function cb to be called with cbdata
+ * when an image is ready. If cb is NULL, only single image grabs
+ * should be used. cb should immediately call streamRead to read
+ * the data or data may be lost. Returns negative value on error,
+ * otherwise 0.
+ */
+ int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
+ void *cbdata);
+
+ /* transferCmd sends commands to the camera. command MUST point to
+ * an 8 byte buffer in kernel space. data can be NULL if no extra
+ * data is needed. The size of the data is given by the last 2
+ * bytes of comand. data must also point to memory in kernel space.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*transferCmd)(void *privdata, u8 *command, u8 *data);
+
+ /* streamStart initiates stream capture mode.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*streamStart)(void *privdata);
+
+ /* streamStop terminates stream capture mode.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*streamStop)(void *privdata);
+
+ /* streamRead reads a frame from the camera. buffer points to a
+ * buffer large enough to hold a complete frame in kernel space.
+ * noblock indicates if this should be a non blocking read.
+ * Returns the number of bytes read, or negative value on error.
+ */
+ int (*streamRead)(void *privdata, u8 *buffer, int noblock);
+
+ /* close disables the device until open() is called again.
+ * Returns negative value on error, otherwise 0.
+ */
+ int (*close)(void *privdata);
+
+ /* If wait_for_stream_ready is non-zero, wait until the streamState
+ * is STREAM_READY before calling streamRead.
+ */
+ int wait_for_stream_ready;
+};
+
+struct cpia_frame {
+ u8 *data;
+ int count;
+ int width;
+ int height;
+ volatile int state;
+};
+
+struct cam_params {
+ struct {
+ u8 firmwareVersion;
+ u8 firmwareRevision;
+ u8 vcVersion;
+ u8 vcRevision;
+ } version;
+ struct {
+ u16 vendor;
+ u16 product;
+ u16 deviceRevision;
+ } pnpID;
+ struct {
+ u8 vpVersion;
+ u8 vpRevision;
+ u16 cameraHeadID;
+ } vpVersion;
+ struct {
+ u8 systemState;
+ u8 grabState;
+ u8 streamState;
+ u8 fatalError;
+ u8 cmdError;
+ u8 debugFlags;
+ u8 vpStatus;
+ u8 errorCode;
+ } status;
+ struct {
+ u8 brightness;
+ u8 contrast;
+ u8 saturation;
+ } colourParams;
+ struct {
+ u8 gainMode;
+ u8 expMode;
+ u8 compMode;
+ u8 centreWeight;
+ u8 gain;
+ u8 fineExp;
+ u8 coarseExpLo;
+ u8 coarseExpHi;
+ u8 redComp;
+ u8 green1Comp;
+ u8 green2Comp;
+ u8 blueComp;
+ } exposure;
+ struct {
+ u8 balanceModeIsAuto;
+ u8 redGain;
+ u8 greenGain;
+ u8 blueGain;
+ } colourBalance;
+ struct {
+ u8 divisor;
+ u8 baserate;
+ } sensorFps;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } apcor;
+ struct {
+ u8 flickerMode;
+ u8 coarseJump;
+ u8 allowableOverExposure;
+ } flickerControl;
+ struct {
+ u8 gain1;
+ u8 gain2;
+ u8 gain4;
+ u8 gain8;
+ } vlOffset;
+ struct {
+ u8 mode;
+ u8 decimation;
+ } compression;
+ struct {
+ u8 frTargeting;
+ u8 targetFR;
+ u8 targetQ;
+ } compressionTarget;
+ struct {
+ u8 yThreshold;
+ u8 uvThreshold;
+ } yuvThreshold;
+ struct {
+ u8 hysteresis;
+ u8 threshMax;
+ u8 smallStep;
+ u8 largeStep;
+ u8 decimationHysteresis;
+ u8 frDiffStepThresh;
+ u8 qDiffStepThresh;
+ u8 decimationThreshMod;
+ } compressionParams;
+ struct {
+ u8 videoSize; /* CIF/QCIF */
+ u8 subSample;
+ u8 yuvOrder;
+ } format;
+ struct {
+ u8 colStart; /* skip first 8*colStart pixels */
+ u8 colEnd; /* finish at 8*colEnd pixels */
+ u8 rowStart; /* skip first 4*rowStart lines */
+ u8 rowEnd; /* finish at 4*rowEnd lines */
+ } roi;
+ u8 ecpTiming;
+ u8 streamStartLine;
+};
+
+enum v4l_camstates {
+ CPIA_V4L_IDLE = 0,
+ CPIA_V4L_ERROR,
+ CPIA_V4L_COMMAND,
+ CPIA_V4L_GRABBING,
+ CPIA_V4L_STREAMING,
+ CPIA_V4L_STREAMING_PAUSED,
+};
+
+#define FRAME_NUM 2 /* double buffering for now */
+
+struct cam_data {
+ struct cam_data **previous;
+ struct cam_data *next;
+
+ struct semaphore busy_lock; /* guard against SMP multithreading */
+ struct cpia_camera_ops *ops; /* lowlevel driver operations */
+ void *lowlevel_data; /* private data for lowlevel driver */
+ u8 *raw_image; /* buffer for raw image data */
+ struct cpia_frame decompressed_frame;
+ /* buffer to hold decompressed frame */
+ int image_size; /* sizeof last decompressed image */
+ int open_count; /* # of process that have camera open */
+
+ /* camera status */
+ int fps; /* actual fps reported by the camera */
+ int transfer_rate; /* transfer rate from camera in kB/s */
+ u8 mainsFreq; /* for flicker control */
+
+ /* proc interface */
+ struct semaphore param_lock; /* params lock for this camera */
+ struct cam_params params; /* camera settings */
+ struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */
+
+ /* v4l */
+ int video_size; /* VIDEO_SIZE_ */
+ volatile enum v4l_camstates camstate; /* v4l layer status */
+ struct video_device vdev; /* v4l videodev */
+ struct video_picture vp; /* v4l camera settings */
+ struct video_window vw; /* v4l capture area */
+
+ /* mmap interface */
+ int curframe; /* the current frame to grab into */
+ u8 *frame_buf; /* frame buffer data */
+ struct cpia_frame frame[FRAME_NUM];
+ /* FRAME_NUM-buffering, so we need a array */
+
+ int first_frame;
+ int mmap_kludge; /* 'wrong' byte order for mmap */
+ volatile u32 cmd_queue; /* queued commands */
+};
+
+/* cpia_register_camera is called by low level driver for each camera.
+ * A unique camera number is returned, or a negative value on error */
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
+
+/* cpia_unregister_camera is called by low level driver when a camera
+ * is removed. This must not fail. */
+void cpia_unregister_camera(struct cam_data *cam);
+
+/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
+ * one byte 16bit DMA alignment
+ */
+#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
+
+/* constant value's */
+#define MAGIC_0 0x19
+#define MAGIC_1 0x68
+#define DATA_IN 0xC0
+#define DATA_OUT 0x40
+#define VIDEOSIZE_QCIF 0 /* 176x144 */
+#define VIDEOSIZE_CIF 1 /* 352x288 */
+#define VIDEOSIZE_SIF 2 /* 320x240 */
+#define VIDEOSIZE_QSIF 3 /* 160x120 */
+#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */
+#define VIDEOSIZE_64_48 5
+#define VIDEOSIZE_128_96 6
+#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF
+#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF
+#define VIDEOSIZE_192_144 7
+#define VIDEOSIZE_224_168 8
+#define VIDEOSIZE_256_192 9
+#define VIDEOSIZE_288_216 10
+#define VIDEOSIZE_320_240 VIDEOSIZE_SIF
+#define VIDEOSIZE_352_288 VIDEOSIZE_CIF
+#define VIDEOSIZE_88_72 11 /* quarter CIF */
+#define SUBSAMPLE_420 0
+#define SUBSAMPLE_422 1
+#define YUVORDER_YUYV 0
+#define YUVORDER_UYVY 1
+#define NOT_COMPRESSED 0
+#define COMPRESSED 1
+#define NO_DECIMATION 0
+#define DECIMATION_ENAB 1
+#define EOI 0xff /* End Of Image */
+#define EOL 0xfd /* End Of Line */
+#define FRAME_HEADER_SIZE 64
+
+/* Image grab modes */
+#define CPIA_GRAB_SINGLE 0
+#define CPIA_GRAB_CONTINUOUS 1
+
+/* Compression parameters */
+#define CPIA_COMPRESSION_NONE 0
+#define CPIA_COMPRESSION_AUTO 1
+#define CPIA_COMPRESSION_MANUAL 2
+#define CPIA_COMPRESSION_TARGET_QUALITY 0
+#define CPIA_COMPRESSION_TARGET_FRAMERATE 1
+
+/* Return offsets for GetCameraState */
+#define SYSTEMSTATE 0
+#define GRABSTATE 1
+#define STREAMSTATE 2
+#define FATALERROR 3
+#define CMDERROR 4
+#define DEBUGFLAGS 5
+#define VPSTATUS 6
+#define ERRORCODE 7
+
+/* SystemState */
+#define UNINITIALISED_STATE 0
+#define PASS_THROUGH_STATE 1
+#define LO_POWER_STATE 2
+#define HI_POWER_STATE 3
+#define WARM_BOOT_STATE 4
+
+/* GrabState */
+#define GRAB_IDLE 0
+#define GRAB_ACTIVE 1
+#define GRAB_DONE 2
+
+/* StreamState */
+#define STREAM_NOT_READY 0
+#define STREAM_READY 1
+#define STREAM_OPEN 2
+#define STREAM_PAUSED 3
+#define STREAM_FINISHED 4
+
+/* Fatal Error, CmdError, and DebugFlags */
+#define CPIA_FLAG 1
+#define SYSTEM_FLAG 2
+#define INT_CTRL_FLAG 4
+#define PROCESS_FLAG 8
+#define COM_FLAG 16
+#define VP_CTRL_FLAG 32
+#define CAPTURE_FLAG 64
+#define DEBUG_FLAG 128
+
+/* VPStatus */
+#define VP_STATE_OK 0x00
+
+#define VP_STATE_FAILED_VIDEOINIT 0x01
+#define VP_STATE_FAILED_AECACBINIT 0x02
+#define VP_STATE_AEC_MAX 0x04
+#define VP_STATE_ACB_BMAX 0x08
+
+#define VP_STATE_ACB_RMIN 0x10
+#define VP_STATE_ACB_GMIN 0x20
+#define VP_STATE_ACB_RMAX 0x40
+#define VP_STATE_ACB_GMAX 0x80
+
+/* ErrorCode */
+#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */
+
+#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args)
+#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args)
+
+#ifdef _CPIA_DEBUG_
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
+
+#define DEB_BYTE(p)\
+ DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
+ (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
+ (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
+
+#define ADD_TO_LIST(l, drv) \
+ {\
+ lock_kernel();\
+ (drv)->next = l;\
+ (drv)->previous = &(l);\
+ (l) = drv;\
+ unlock_kernel();\
+ } while(0)
+
+#define REMOVE_FROM_LIST(drv) \
+ {\
+ if ((drv)->previous != NULL) {\
+ lock_kernel();\
+ if ((drv)->next != NULL)\
+ (drv)->next->previous = (drv)->previous;\
+ *((drv)->previous) = (drv)->next;\
+ (drv)->previous = NULL;\
+ (drv)->next = NULL;\
+ unlock_kernel();\
+ }\
+ } while (0)
+
+
+#endif /* __KERNEL__ */
+
+#endif /* cpia_h */
diff --git a/drivers/char/cpia_pp.c b/drivers/char/cpia_pp.c
new file mode 100644
index 000000000..7d4be2744
--- /dev/null
+++ b/drivers/char/cpia_pp.c
@@ -0,0 +1,745 @@
+/*
+ * cpia_pp CPiA Parallel Port driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
+ * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@mindspring.com>,
+ * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+/* #define _CPIA_DEBUG_ define for verbose debug output */
+#include "cpia.h"
+
+static int cpia_pp_open(void *privdata);
+static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
+ void *cbdata);
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_pp_streamStart(void *privdata);
+static int cpia_pp_streamStop(void *privdata);
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);
+static int cpia_pp_close(void *privdata);
+
+#define ABOUT "Parallel port driver for Vision CPiA based cameras"
+
+/* IEEE 1284 Compatiblity Mode signal names */
+#define nStrobe PARPORT_CONTROL_STROBE /* inverted */
+#define nAutoFd PARPORT_CONTROL_AUTOFD /* inverted */
+#define nInit PARPORT_CONTROL_INIT
+#define nSelectIn PARPORT_CONTROL_SELECT
+#define IntrEnable PARPORT_CONTROL_INTEN /* normally zero for no IRQ */
+#define DirBit PARPORT_CONTROL_DIRECTION /* 0 = Forward, 1 = Reverse */
+
+#define nFault PARPORT_STATUS_ERROR
+#define Select PARPORT_STATUS_SELECT
+#define PError PARPORT_STATUS_PAPEROUT
+#define nAck PARPORT_STATUS_ACK
+#define Busy PARPORT_STATUS_BUSY /* inverted */
+
+/* some more */
+#define HostClk nStrobe
+#define HostAck nAutoFd
+#define nReverseRequest nInit
+#define Active_1284 nSelectIn
+#define nPeriphRequest nFault
+#define XFlag Select
+#define nAckReverse PError
+#define PeriphClk nAck
+#define PeriphAck Busy
+
+/* these can be used to correct for the inversion on some bits */
+#define STATUS_INVERSION_MASK (Busy)
+#define CONTROL_INVERSION_MASK (nStrobe|nAutoFd|nSelectIn)
+
+#define ECR_empty 0x01
+#define ECR_full 0x02
+#define ECR_serviceIntr 0x04
+#define ECR_dmaEn 0x08
+#define ECR_nErrIntrEn 0x10
+
+#define ECR_mode_mask 0xE0
+#define ECR_SPP_mode 0x00
+#define ECR_PS2_mode 0x20
+#define ECR_FIFO_mode 0x40
+#define ECR_ECP_mode 0x60
+
+#define ECP_FIFO_SIZE 16
+#define DMA_BUFFER_SIZE PAGE_SIZE
+ /* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */
+#define PARPORT_CHUNK_SIZE PAGE_SIZE/* >=2.3.x */
+ /* we read this many bytes at once */
+
+#define GetECRMasked(port,mask) (parport_read_econtrol(port) & (mask))
+#define GetStatus(port) ((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8))
+#define SetStatus(port,val) parport_write_status(port,(val)^STATUS_INVERSION_MASK)
+#define GetControl(port) ((parport_read_control(port)^CONTROL_INVERSION_MASK)&(0x3f))
+#define SetControl(port,val) parport_write_control(port,(val)^CONTROL_INVERSION_MASK)
+
+#define GetStatusMasked(port,mask) (GetStatus(port) & (mask))
+#define GetControlMasked(port,mask) (GetControl(port) & (mask))
+#define SetControlMasked(port,mask) SetControl(port,GetControl(port) | (mask));
+#define ClearControlMasked(port,mask) SetControl(port,GetControl(port)&~(mask));
+#define FrobControlBit(port,mask,value) SetControl(port,(GetControl(port)&~(mask))|((value)&(mask)));
+
+#define PACKET_LENGTH 8
+
+/* Magic numbers for defining port-device mappings */
+#define PPCPIA_PARPORT_UNSPEC -4
+#define PPCPIA_PARPORT_AUTO -3
+#define PPCPIA_PARPORT_OFF -2
+#define PPCPIA_PARPORT_NONE -1
+
+#ifdef MODULE
+static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
+static char *parport[PARPORT_MAX] = {NULL,};
+
+MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");
+MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
+MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s");
+MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
+#else
+static int parport_nr[PARPORT_MAX] __initdata =
+ {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
+static int parport_ptr = 0;
+#endif
+
+struct pp_cam_entry {
+ struct pardevice *pdev;
+ struct parport *port;
+ struct tq_struct cb_task;
+ int open_count;
+ wait_queue_head_t wq_stream;
+ /* image state flags */
+ int image_ready; /* we got an interrupt */
+ int image_complete; /* we have seen 4 EOI */
+
+ int streaming; /* we are in streaming mode */
+ int stream_irq;
+};
+
+static struct cpia_camera_ops cpia_pp_ops =
+{
+ cpia_pp_open,
+ cpia_pp_registerCallback,
+ cpia_pp_transferCmd,
+ cpia_pp_streamStart,
+ cpia_pp_streamStop,
+ cpia_pp_streamRead,
+ cpia_pp_close,
+ 1
+};
+
+static struct cam_data *cam_list;
+
+#ifdef _CPIA_DEBUG_
+#define DEB_PORT(port) { \
+u8 controll = GetControl(port); \
+u8 statusss = GetStatus(port); \
+DBG("nsel %c per %c naut %c nstrob %c nak %c busy %c nfaul %c sel %c init %c dir %c\n",\
+((controll & nSelectIn) ? 'U' : 'D'), \
+((statusss & PError) ? 'U' : 'D'), \
+((controll & nAutoFd) ? 'U' : 'D'), \
+((controll & nStrobe) ? 'U' : 'D'), \
+((statusss & nAck) ? 'U' : 'D'), \
+((statusss & Busy) ? 'U' : 'D'), \
+((statusss & nFault) ? 'U' : 'D'), \
+((statusss & Select) ? 'U' : 'D'), \
+((controll & nInit) ? 'U' : 'D'), \
+((controll & DirBit) ? 'R' : 'F') \
+); }
+#else
+#define DEB_PORT(port) {}
+#endif
+
+#define WHILE_OUT_TIMEOUT (HZ/10)
+#define DMA_TIMEOUT 10*HZ
+
+/* FIXME */
+static void cpia_parport_enable_irq( struct parport *port ) {
+ parport_enable_irq(port);
+ mdelay(10);
+ return;
+}
+
+static void cpia_parport_disable_irq( struct parport *port ) {
+ parport_disable_irq(port);
+ mdelay(10);
+ return;
+}
+
+/****************************************************************************
+ *
+ * EndTransferMode
+ *
+ ***************************************************************************/
+static void EndTransferMode(struct pp_cam_entry *cam)
+{
+ parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+}
+
+/****************************************************************************
+ *
+ * ForwardSetup
+ *
+ ***************************************************************************/
+static int ForwardSetup(struct pp_cam_entry *cam)
+{
+ int retry;
+
+ /* After some commands the camera needs extra time before
+ * it will respond again, so we try up to 3 times */
+ for(retry=0; retry<3; ++retry) {
+ if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
+ break;
+ }
+ }
+ if(retry == 3) {
+ DBG("Unable to negotiate ECP mode\n");
+ return -1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * ReverseSetup
+ *
+ ***************************************************************************/
+static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
+{
+ int retry;
+ int mode = IEEE1284_MODE_ECP;
+ if(extensibility) mode = 8|3|IEEE1284_EXT_LINK;
+
+ /* After some commands the camera needs extra time before
+ * it will respond again, so we try up to 3 times */
+ for(retry=0; retry<3; ++retry) {
+ if(!parport_negotiate(cam->port, mode)) {
+ break;
+ }
+ }
+ if(retry == 3) {
+ if(extensibility)
+ DBG("Unable to negotiate extensibility mode\n");
+ else
+ DBG("Unable to negotiate ECP mode\n");
+ return -1;
+ }
+ if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP;
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
+{
+ int retval=0;
+ int size_written;
+
+ if (packet == NULL) {
+ return -EINVAL;
+ }
+ if (ForwardSetup(cam)) {
+ DBG("Write failed in setup\n");
+ return -EIO;
+ }
+ size_written = parport_write(cam->port, packet, size);
+ if(size_written != size) {
+ DBG("Write failed, wrote %d/%d\n", size_written, size);
+ retval = -EIO;
+ }
+ EndTransferMode(cam);
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
+{
+ int retval=0;
+ if (packet == NULL) {
+ return -EINVAL;
+ }
+ if (ReverseSetup(cam, 0)) {
+ return -EIO;
+ }
+ if(parport_read(cam->port, packet, size) != size) {
+ retval = -EIO;
+ }
+ EndTransferMode(cam);
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_streamStart
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStart(void *privdata)
+{
+ struct pp_cam_entry *cam = privdata;
+ DBG("\n");
+ cam->streaming=1;
+ cam->image_ready=0;
+ //if (ReverseSetup(cam,1)) return -EIO;
+ if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_streamStop
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStop(void *privdata)
+{
+ struct pp_cam_entry *cam = privdata;
+
+ DBG("\n");
+ cam->streaming=0;
+ cpia_parport_disable_irq(cam->port);
+ //EndTransferMode(cam);
+
+ return 0;
+}
+
+static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
+{
+ int bytes_read, new_bytes;
+ for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
+ new_bytes = parport_read(port, buffer+bytes_read,
+ len-bytes_read);
+ if(new_bytes < 0) break;
+ }
+ return bytes_read;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_streamRead
+ *
+ ***************************************************************************/
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
+{
+ struct pp_cam_entry *cam = privdata;
+ int read_bytes = 0;
+ int i, endseen, block_size, new_bytes;
+
+ if(cam == NULL) {
+ DBG("Internal driver error: cam is NULL\n");
+ return -EINVAL;
+ }
+ if(buffer == NULL) {
+ DBG("Internal driver error: buffer is NULL\n");
+ return -EINVAL;
+ }
+ //if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
+ if( cam->stream_irq ) {
+ DBG("%d\n", cam->image_ready);
+ cam->image_ready--;
+ }
+ cam->image_complete=0;
+ if (0/*cam->streaming*/) {
+ if(!cam->image_ready) {
+ if(noblock) return -EWOULDBLOCK;
+ interruptible_sleep_on(&cam->wq_stream);
+ if( signal_pending(current) ) return -EINTR;
+ DBG("%d\n", cam->image_ready);
+ }
+ } else {
+ if (ReverseSetup(cam, 1)) {
+ DBG("unable to ReverseSetup\n");
+ return -EIO;
+ }
+ }
+ endseen = 0;
+ block_size = PARPORT_CHUNK_SIZE;
+ while( !cam->image_complete ) {
+ if(current->need_resched) schedule();
+
+ new_bytes = cpia_pp_read(cam->port, buffer, block_size );
+ if( new_bytes <= 0 ) {
+ break;
+ }
+ i=-1;
+ while(++i<new_bytes && endseen<4) {
+ if(*buffer==EOI) {
+ endseen++;
+ } else {
+ endseen=0;
+ }
+ buffer++;
+ }
+ read_bytes += i;
+ if( endseen==4 ) {
+ cam->image_complete=1;
+ break;
+ }
+ if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
+ block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
+ }
+ }
+ EndTransferMode(cam);
+ return cam->image_complete ? read_bytes : -EIO;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_transferCmd
+ *
+ ***************************************************************************/
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+ int err;
+ int retval=0;
+ int databytes;
+ struct pp_cam_entry *cam = privdata;
+
+ if(cam == NULL) {
+ DBG("Internal driver error: cam is NULL\n");
+ return -EINVAL;
+ }
+ if(command == NULL) {
+ DBG("Internal driver error: command is NULL\n");
+ return -EINVAL;
+ }
+ databytes = (((int)command[7])<<8) | command[6];
+ if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
+ DBG("Error writing command\n");
+ return err;
+ }
+ if(command[0] == DATA_IN) {
+ u8 buffer[8];
+ if(data == NULL) {
+ DBG("Internal driver error: data is NULL\n");
+ return -EINVAL;
+ }
+ if((err = ReadPacket(cam, buffer, 8)) < 0) {
+ return err;
+ DBG("Error reading command result\n");
+ }
+ memcpy(data, buffer, databytes);
+ } else if(command[0] == DATA_OUT) {
+ if(databytes > 0) {
+ if(data == NULL) {
+ DBG("Internal driver error: data is NULL\n");
+ retval = -EINVAL;
+ } else {
+ if((err=WritePacket(cam, data, databytes)) < 0){
+ DBG("Error writing command data\n");
+ return err;
+ }
+ }
+ }
+ } else {
+ DBG("Unexpected first byte of command: %x\n", command[0]);
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_open
+ *
+ ***************************************************************************/
+static int cpia_pp_open(void *privdata)
+{
+ struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
+
+ if (cam == NULL)
+ return -EINVAL;
+
+ if(cam->open_count == 0) {
+ if (parport_claim(cam->pdev)) {
+ DBG("failed to claim the port\n");
+ return -EBUSY;
+ }
+ parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+ parport_data_forward(cam->port);
+ parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
+ udelay(50);
+ parport_write_control(cam->port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT);
+ }
+
+ ++cam->open_count;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_registerCallback
+ *
+ ***************************************************************************/
+static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata)
+{
+ struct pp_cam_entry *cam = privdata;
+ int retval = 0;
+
+ if(cam->port->irq != PARPORT_IRQ_NONE) {
+ cam->cb_task.routine = cb;
+ cam->cb_task.data = cbdata;
+ } else {
+ retval = -1;
+ }
+ return retval;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_close
+ *
+ ***************************************************************************/
+static int cpia_pp_close(void *privdata)
+{
+ struct pp_cam_entry *cam = privdata;
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ if (--cam->open_count == 0) {
+ parport_release(cam->pdev);
+ }
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * cpia_pp_register
+ *
+ ***************************************************************************/
+static int cpia_pp_register(struct parport *port)
+{
+ struct pardevice *pdev = NULL;
+ struct pp_cam_entry *cam;
+ struct cam_data *cpia;
+
+ if (!(port->modes & PARPORT_MODE_ECP) &&
+ !(port->modes & PARPORT_MODE_TRISTATE)) {
+ LOG("port is not ECP capable\n");
+ return -ENXIO;
+ }
+
+ cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
+ if (cam == NULL) {
+ LOG("failed to allocate camera structure\n");
+ return -ENOMEM;
+ }
+ memset(cam,0,sizeof(struct pp_cam_entry));
+
+ pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
+ NULL, 0, cam);
+
+ if (!pdev) {
+ LOG("failed to parport_register_device\n");
+ kfree(cam);
+ return -ENXIO;
+ }
+
+ cam->pdev = pdev;
+ cam->port = port;
+ init_waitqueue_head(&cam->wq_stream);
+
+ cam->streaming = 0;
+ cam->stream_irq = 0;
+
+ if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
+ LOG("failed to cpia_register_camera\n");
+ parport_unregister_device(pdev);
+ kfree(cam);
+ return -ENXIO;
+ }
+ ADD_TO_LIST(cam_list, cpia);
+
+ return 0;
+}
+
+static void cpia_pp_detach (struct parport *port)
+{
+ struct cam_data *cpia;
+
+ for(cpia = cam_list; cpia != NULL; cpia = cpia->next) {
+ struct pp_cam_entry *cam = cpia->lowlevel_data;
+ if (cam && cam->port->number == port->number) {
+ REMOVE_FROM_LIST(cpia);
+
+ cpia_unregister_camera(cpia);
+
+ if(cam->open_count > 0) {
+ cpia_pp_close(cam);
+ }
+
+ parport_unregister_device(cam->pdev);
+
+ kfree(cam);
+ cpia->lowlevel_data = NULL;
+ break;
+ }
+ }
+}
+
+static void cpia_pp_attach (struct parport *port)
+{
+ unsigned int i;
+
+ switch (parport_nr[0])
+ {
+ case PPCPIA_PARPORT_UNSPEC:
+ case PPCPIA_PARPORT_AUTO:
+ if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
+ port->probe_info[0].cmdset == NULL ||
+ strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
+ return;
+
+ cpia_pp_register(port);
+
+ break;
+
+ default:
+ for (i = 0; i < PARPORT_MAX; ++i) {
+ if (port->number == parport_nr[i]) {
+ cpia_pp_register(port);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+static struct parport_driver cpia_pp_driver = {
+ "cpia_pp",
+ cpia_pp_attach,
+ cpia_pp_detach,
+ NULL
+};
+
+int cpia_pp_init(void)
+{
+ printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
+ CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
+
+ if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
+ printk(" disabled\n");
+ return 0;
+ }
+
+ if (parport_register_driver (&cpia_pp_driver)) {
+ LOG ("unable to register with parport\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ if (parport[0]) {
+ /* The user gave some parameters. Let's see what they were. */
+ if (!strncmp(parport[0], "auto", 4)) {
+ parport_nr[0] = PPCPIA_PARPORT_AUTO;
+ } else {
+ int n;
+ for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
+ if (!strncmp(parport[n], "none", 4)) {
+ parport_nr[n] = PPCPIA_PARPORT_NONE;
+ } else {
+ char *ep;
+ unsigned long r = simple_strtoul(parport[n], &ep, 0);
+ if (ep != parport[n]) {
+ parport_nr[n] = r;
+ } else {
+ LOG("bad port specifier `%s'\n", parport[n]);
+ return -ENODEV;
+ }
+ }
+ }
+ }
+ }
+#if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE)
+ if(parport_enumerate() && !parport_enumerate()->probe_info.model) {
+ request_module("parport_probe");
+ }
+#endif
+ return cpia_pp_init();
+}
+
+void cleanup_module(void)
+{
+ parport_unregister_driver (&cpia_pp_driver);
+ return;
+}
+
+#else /* !MODULE */
+
+static int __init cpia_pp_setup(char *str)
+{
+#if 0
+ /* Is this only a 2.2ism? -jerdfelt */
+ if (!str) {
+ if (ints[0] == 0 || ints[1] == 0) {
+ /* disable driver on "cpia_pp=" or "cpia_pp=0" */
+ parport_nr[0] = PPCPIA_PARPORT_OFF;
+ }
+ } else
+#endif
+ if (!strncmp(str, "parport", 7)) {
+ int n = simple_strtoul(str + 7, NULL, 10);
+ if (parport_ptr < PARPORT_MAX) {
+ parport_nr[parport_ptr++] = n;
+ } else {
+ LOG("too many ports, %s ignored.\n", str);
+ }
+ } else if (!strcmp(str, "auto")) {
+ parport_nr[0] = PPCPIA_PARPORT_AUTO;
+ } else if (!strcmp(str, "none")) {
+ parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
+ }
+
+ return 0;
+}
+
+__setup("cpia_pp=", cpia_pp_setup);
+
+#endif /* !MODULE */
diff --git a/drivers/char/cpia_usb.c b/drivers/char/cpia_usb.c
new file mode 100644
index 000000000..6b67fbc81
--- /dev/null
+++ b/drivers/char/cpia_usb.c
@@ -0,0 +1,626 @@
+/*
+ * cpia_usb CPiA USB driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * Copyright (C) 1999 Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
+ * Copyright (C) 1999, 2000 Johannes Erdfelt <jerdfelt@valinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+
+#include "cpia.h"
+
+#define USB_REQ_CPIA_GRAB_FRAME 0xC1
+#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
+#define WAIT_FOR_NEXT_FRAME 0
+#define FORCE_FRAME_UPLOAD 1
+
+#define FRAMES_PER_DESC 10
+#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
+#define CPIA_NUMSBUF 2
+#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
+#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
+
+struct cpia_sbuf {
+ char *data;
+ urb_t *urb;
+};
+
+#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
+enum framebuf_status {
+ FRAME_EMPTY,
+ FRAME_READING,
+ FRAME_READY,
+ FRAME_ERROR,
+};
+
+struct framebuf {
+ int length;
+ enum framebuf_status status;
+ u8 data[FRAMEBUF_LEN];
+ struct framebuf *next;
+};
+
+struct usb_cpia {
+ /* Device structure */
+ struct usb_device *dev;
+
+ unsigned char iface;
+ wait_queue_head_t wq_stream;
+
+ int cursbuf; /* Current receiving sbuf */
+ struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
+
+ int streaming;
+ int open;
+ int present;
+ struct framebuf *buffers[3];
+ struct framebuf *curbuff, *workbuff;
+};
+
+static int cpia_usb_open(void *privdata);
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+ void *cbdata);
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_usb_streamStart(void *privdata);
+static int cpia_usb_streamStop(void *privdata);
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
+static int cpia_usb_close(void *privdata);
+
+#define ABOUT "USB driver for Vision CPiA based cameras"
+
+static struct cpia_camera_ops cpia_usb_ops = {
+ cpia_usb_open,
+ cpia_usb_registerCallback,
+ cpia_usb_transferCmd,
+ cpia_usb_streamStart,
+ cpia_usb_streamStop,
+ cpia_usb_streamRead,
+ cpia_usb_close,
+ 0
+};
+
+static struct cam_data *cam_list;
+
+static void cpia_usb_complete(struct urb *urb)
+{
+ int i;
+ char *cdata;
+ struct usb_cpia *ucpia;
+
+ if (!urb || !urb->context)
+ return;
+
+ ucpia = (struct usb_cpia *) urb->context;
+
+ if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
+ return;
+
+ if (ucpia->workbuff->status == FRAME_EMPTY) {
+ ucpia->workbuff->status = FRAME_READING;
+ ucpia->workbuff->length = 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int n = urb->iso_frame_desc[i].actual_length;
+ int st = urb->iso_frame_desc[i].status;
+
+ cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ if (st)
+ printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st);
+
+ if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
+ printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
+ return;
+ }
+
+ if (n) {
+ if ((ucpia->workbuff->length > 0) ||
+ (0x19 == cdata[0] && 0x68 == cdata[1])) {
+ memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
+ ucpia->workbuff->length += n;
+ } else
+ DBG("Ignoring packet!\n");
+ } else {
+ if (ucpia->workbuff->length > 4 &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
+ 0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
+ ucpia->workbuff->status = FRAME_READY;
+ ucpia->curbuff = ucpia->workbuff;
+ ucpia->workbuff = ucpia->workbuff->next;
+ ucpia->workbuff->status = FRAME_EMPTY;
+ ucpia->workbuff->length = 0;
+
+ if (waitqueue_active(&ucpia->wq_stream))
+ wake_up_interruptible(&ucpia->wq_stream);
+ }
+ }
+ }
+}
+
+static int cpia_usb_open(void *privdata)
+{
+ struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+ urb_t *urb;
+ int ret, retval = 0, fx, err;
+
+ if (!ucpia)
+ return -EINVAL;
+
+ ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ if (!ucpia->sbuf[0].data)
+ return -EINVAL;
+
+ ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ if (!ucpia->sbuf[1].data) {
+ retval = -EINVAL;
+ goto error_0;
+ }
+
+ ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
+ if (ret < 0) {
+ printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
+ retval = -EBUSY;
+ goto error_all;
+ }
+
+ ucpia->buffers[0]->status = FRAME_EMPTY;
+ ucpia->buffers[0]->length = 0;
+ ucpia->buffers[1]->status = FRAME_EMPTY;
+ ucpia->buffers[1]->length = 0;
+ ucpia->buffers[2]->status = FRAME_EMPTY;
+ ucpia->buffers[2]->length = 0;
+ ucpia->curbuff = ucpia->buffers[0];
+ ucpia->workbuff = ucpia->buffers[1];
+
+ /* We double buffer the Iso lists */
+ urb = usb_alloc_urb(FRAMES_PER_DESC);
+ if (!urb) {
+ printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+ retval = -ENOMEM;
+ goto error_all;
+ }
+
+ ucpia->sbuf[0].urb = urb;
+ urb->dev = ucpia->dev;
+ urb->context = ucpia;
+ urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+ urb->transfer_flags = USB_ISO_ASAP;
+ urb->transfer_buffer = ucpia->sbuf[0].data;
+ urb->complete = cpia_usb_complete;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+ urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+ urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ }
+
+ urb = usb_alloc_urb(FRAMES_PER_DESC);
+ if (!urb) {
+ printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+ retval = -ENOMEM;
+ goto error_all;
+ }
+
+ ucpia->sbuf[1].urb = urb;
+ urb->dev = ucpia->dev;
+ urb->context = ucpia;
+ urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+ urb->transfer_flags = USB_ISO_ASAP;
+ urb->transfer_buffer = ucpia->sbuf[1].data;
+ urb->complete = cpia_usb_complete;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+ urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+ urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ }
+
+ ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb;
+ ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb;
+
+ err = usb_submit_urb(ucpia->sbuf[0].urb);
+ if (err)
+ printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
+ err);
+ err = usb_submit_urb(ucpia->sbuf[1].urb);
+ if (err)
+ printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
+ err);
+
+ ucpia->streaming = 1;
+ ucpia->open = 1;
+
+ return 0;
+
+error_all:
+ kfree (ucpia->sbuf[1].data);
+error_0:
+ kfree (ucpia->sbuf[0].data);
+
+ return retval;
+}
+
+//
+// convenience functions
+//
+
+/****************************************************************************
+ *
+ * WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size)
+{
+ if (!packet)
+ return -EINVAL;
+
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ packet[1] + (packet[0] << 8),
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ packet[2] + (packet[3] << 8),
+ packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+/****************************************************************************
+ *
+ * ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
+{
+ if (!packet || size <= 0)
+ return -EINVAL;
+
+ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ packet[1] + (packet[0] << 8),
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ packet[2] + (packet[3] << 8),
+ packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+ int err = 0;
+ int databytes;
+ struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
+ struct usb_device *udev = ucpia->dev;
+
+ if (!udev) {
+ DBG("Internal driver error: udev is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!command) {
+ DBG("Internal driver error: command is NULL\n");
+ return -EINVAL;
+ }
+
+ databytes = (((int)command[7])<<8) | command[6];
+
+ if (command[0] == DATA_IN) {
+ u8 buffer[8];
+
+ if (!data) {
+ DBG("Internal driver error: data is NULL\n");
+ return -EINVAL;
+ }
+
+ err = ReadPacket(udev, command, buffer, 8);
+ if (err < 0)
+ return err;
+
+ memcpy(data, buffer, databytes);
+ } else if(command[0] == DATA_OUT)
+ WritePacket(udev, command, data, databytes);
+ else {
+ DBG("Unexpected first byte of command: %x\n", command[0]);
+ err = -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+ void *cbdata)
+{
+ return -ENODEV;
+}
+
+static int cpia_usb_streamStart(void *privdata)
+{
+ return -ENODEV;
+}
+
+static int cpia_usb_streamStop(void *privdata)
+{
+ return -ENODEV;
+}
+
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
+{
+ struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+ struct framebuf *mybuff;
+
+ if (!ucpia || !ucpia->present)
+ return -1;
+
+ if (ucpia->curbuff->status != FRAME_READY)
+ interruptible_sleep_on(&ucpia->wq_stream);
+ else
+ DBG("Frame already waiting!\n");
+
+ mybuff = ucpia->curbuff;
+
+ if (!mybuff)
+ return -1;
+
+ if (mybuff->status != FRAME_READY || mybuff->length < 4) {
+ DBG("Something went wrong!\n");
+ return -1;
+ }
+
+ memcpy(frame, mybuff->data, mybuff->length);
+ mybuff->status = FRAME_EMPTY;
+
+/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */
+/* mybuff->length, frame[0], frame[1], */
+/* frame[mybuff->length-4], frame[mybuff->length-3], */
+/* frame[mybuff->length-2], frame[mybuff->length-1]); */
+
+ return mybuff->length;
+}
+
+static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
+{
+ if (!ucpia->streaming)
+ return;
+
+ ucpia->streaming = 0;
+
+ /* Set packet size to 0 */
+ if (try) {
+ int ret;
+
+ ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
+ return;
+ }
+ }
+
+ /* Unschedule all of the iso td's */
+ if (ucpia->sbuf[1].urb) {
+ usb_unlink_urb(ucpia->sbuf[1].urb);
+ usb_free_urb(ucpia->sbuf[1].urb);
+ ucpia->sbuf[1].urb = NULL;
+ }
+
+ if (ucpia->sbuf[0].urb) {
+ usb_unlink_urb(ucpia->sbuf[0].urb);
+ usb_free_urb(ucpia->sbuf[0].urb);
+ ucpia->sbuf[0].urb = NULL;
+ }
+}
+
+static int cpia_usb_close(void *privdata)
+{
+ struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+
+ ucpia->open = 0;
+
+ cpia_usb_free_resources(ucpia, 1);
+
+ if (!ucpia->present)
+ kfree(ucpia);
+
+ return 0;
+}
+
+int cpia_usb_init(void)
+{
+ /* return -ENODEV; */
+ return 0;
+}
+
+/* Probing and initializing */
+
+static void *cpia_probe(struct usb_device *udev, unsigned int ifnum)
+{
+ struct usb_interface_descriptor *interface;
+ struct usb_cpia *ucpia;
+ struct cam_data *cam;
+ int ret;
+
+ /* A multi-config CPiA camera? */
+ if (udev->descriptor.bNumConfigurations != 1)
+ return NULL;
+
+ interface = &udev->actconfig->interface[ifnum].altsetting[0];
+
+ /* Is it a CPiA? */
+ if (udev->descriptor.idVendor != 0x0553)
+ return NULL;
+ if (udev->descriptor.idProduct != 0x0002)
+ return NULL;
+
+ /* We found a CPiA */
+ printk(KERN_INFO "USB CPiA camera found\n");
+
+ ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL);
+ if (!ucpia) {
+ printk(KERN_ERR "couldn't kmalloc cpia struct\n");
+ return NULL;
+ }
+
+ memset(ucpia, 0, sizeof(*ucpia));
+
+ ucpia->dev = udev;
+ ucpia->iface = interface->bInterfaceNumber;
+ init_waitqueue_head(&ucpia->wq_stream);
+
+ ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
+ if (!ucpia->buffers[0]) {
+ printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
+ goto fail_alloc_0;
+ }
+
+ ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
+ if (!ucpia->buffers[1]) {
+ printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
+ goto fail_alloc_1;
+ }
+
+ ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
+ if (!ucpia->buffers[2]) {
+ printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
+ goto fail_alloc_2;
+ }
+
+ ucpia->buffers[0]->next = ucpia->buffers[1];
+ ucpia->buffers[1]->next = ucpia->buffers[2];
+ ucpia->buffers[2]->next = ucpia->buffers[0];
+
+ ret = usb_set_interface(udev, ucpia->iface, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret);
+ /* goto fail_all; */
+ }
+
+ /* Before register_camera, important */
+ ucpia->present = 1;
+
+ cam = cpia_register_camera(&cpia_usb_ops, ucpia);
+ if (!cam) {
+ LOG("failed to cpia_register_camera\n");
+ goto fail_all;
+ }
+
+ ADD_TO_LIST(cam_list, cam);
+
+ return cam;
+
+fail_all:
+ vfree(ucpia->buffers[2]);
+ ucpia->buffers[2] = NULL;
+fail_alloc_2:
+ vfree(ucpia->buffers[1]);
+ ucpia->buffers[1] = NULL;
+fail_alloc_1:
+ vfree(ucpia->buffers[0]);
+ ucpia->buffers[0] = NULL;
+fail_alloc_0:
+
+ return NULL;
+}
+
+static void cpia_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver cpia_driver = {
+ "cpia",
+ cpia_probe,
+ cpia_disconnect,
+ { NULL, NULL }
+};
+
+/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
+/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */
+/* will do it for us as well as passing a udev structure - jerdfelt */
+static void cpia_disconnect(struct usb_device *udev, void *ptr)
+{
+ struct cam_data *cam = (struct cam_data *) ptr;
+ struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data;
+
+ REMOVE_FROM_LIST(cam);
+
+ /* Don't even try to reset the altsetting if we're disconnected */
+ cpia_usb_free_resources(ucpia, 0);
+
+ ucpia->present = 0;
+
+ cpia_unregister_camera(cam);
+
+ ucpia->curbuff->status = FRAME_ERROR;
+
+ if (waitqueue_active(&ucpia->wq_stream))
+ wake_up_interruptible(&ucpia->wq_stream);
+
+ usb_driver_release_interface(&cpia_driver,
+ &udev->actconfig->interface[0]);
+
+ ucpia->curbuff = ucpia->workbuff = NULL;
+
+ if (ucpia->buffers[2]) {
+ vfree(ucpia->buffers[2]);
+ ucpia->buffers[2] = NULL;
+ }
+
+ if (ucpia->buffers[1]) {
+ vfree(ucpia->buffers[1]);
+ ucpia->buffers[1] = NULL;
+ }
+
+ if (ucpia->buffers[0]) {
+ vfree(ucpia->buffers[0]);
+ ucpia->buffers[0] = NULL;
+ }
+
+ if (!ucpia->open)
+ kfree(ucpia);
+}
+
+int usb_cpia_init(void)
+{
+ cam_list = NULL;
+
+ return usb_register(&cpia_driver);
+}
+
+void usb_cpia_cleanup(void)
+{
+/*
+ struct cam_data *cam;
+
+ while ((cam = cam_list) != NULL)
+ cpia_disconnect(NULL, cam);
+*/
+
+ usb_deregister(&cpia_driver);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return usb_cpia_init();
+}
+
+void cleanup_module(void)
+{
+ usb_cpia_cleanup();
+}
+#endif /* !MODULE */
diff --git a/drivers/char/joystick/joy-spaceball.c b/drivers/char/joystick/joy-spaceball.c
index 421a3cf8f..874eb5268 100644
--- a/drivers/char/joystick/joy-spaceball.c
+++ b/drivers/char/joystick/joy-spaceball.c
@@ -207,6 +207,8 @@ static int js_sball_ldisc_open(struct tty_struct *tty)
struct js_sball_info iniinfo;
struct js_sball_info *info = &iniinfo;
+ MOD_INC_USE_COUNT;
+
info->tty = tty;
info->idx = 0;
info->used = 1;
@@ -221,8 +223,6 @@ static int js_sball_ldisc_open(struct tty_struct *tty)
js_sball_init_corr(js_sball_port->corr);
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -312,9 +312,7 @@ static int js_sball_ldisc_room(struct tty_struct *tty)
static struct tty_ldisc js_sball_ldisc = {
magic: TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
name: "spaceball",
-#endif
open: js_sball_ldisc_open,
close: js_sball_ldisc_close,
receive_buf: js_sball_ldisc_receive,
diff --git a/drivers/char/joystick/joy-spaceorb.c b/drivers/char/joystick/joy-spaceorb.c
index 464e59006..a154bcdd5 100644
--- a/drivers/char/joystick/joy-spaceorb.c
+++ b/drivers/char/joystick/joy-spaceorb.c
@@ -199,6 +199,8 @@ static int js_orb_ldisc_open(struct tty_struct *tty)
struct js_orb_info iniinfo;
struct js_orb_info *info = &iniinfo;
+ MOD_INC_USE_COUNT;
+
info->tty = tty;
info->idx = 0;
info->used = 1;
@@ -213,8 +215,6 @@ static int js_orb_ldisc_open(struct tty_struct *tty)
js_orb_init_corr(js_orb_port->corr);
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -270,9 +270,7 @@ static int js_orb_ldisc_room(struct tty_struct *tty)
static struct tty_ldisc js_orb_ldisc = {
magic: TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
name: "spaceorb",
-#endif
open: js_orb_ldisc_open,
close: js_orb_ldisc_close,
receive_buf: js_orb_ldisc_receive,
diff --git a/drivers/char/joystick/joy-warrior.c b/drivers/char/joystick/joy-warrior.c
index fd7be5787..8737d1cc9 100644
--- a/drivers/char/joystick/joy-warrior.c
+++ b/drivers/char/joystick/joy-warrior.c
@@ -90,28 +90,12 @@ static void js_war_process_packet(struct js_war_info* info)
if (!info->port->devs[0]) return;
buttons[0][0] = ((data[3] & 0xa) >> 1) | ((data[3] & 0x5) << 1);
return;
- case 2: /* Static status (Send !S to get one) */
-#if 0
- printk("joy-warrior: Static status:");
- for (i = 0; i < 12; i++)
- printk(" %02x", info->data[i]);
- printk("\n");
-#endif
- return;
case 3: /* XY-axis info->data */
if (!info->port->devs[0]) return;
axes[0][0] = ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5));
axes[0][1] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
return;
break;
- case 4: /* Dynamic status */
-#if 0
- printk("joy-warrior: Dynamic status:");
- for (i = 0; i < 4; i++)
- printk(" %02x", info->data[i]);
- printk("\n");
-#endif
- return;
case 5: /* Throttle, spinner, hat info->data */
if (!info->port->devs[0]) return;
axes[0][2] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
@@ -119,6 +103,9 @@ static void js_war_process_packet(struct js_war_info* info)
axes[0][4] = (data[3] & 8 ? 1 : 0) - (info->data[3] & 4 ? 1 : 0);
axes[0][5] = (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5);
return;
+ case 2: /* Static status (Send !S to get one) */
+ case 4: /* Dynamic status */
+ return;
default:
printk("joy-warrior: Unknown packet %d length %d:", (data[0] >> 4) & 7, info->idx);
for (i = 0; i < info->idx; i++)
@@ -199,6 +186,8 @@ static int js_war_ldisc_open(struct tty_struct *tty)
struct js_war_info iniinfo;
struct js_war_info *info = &iniinfo;
+ MOD_INC_USE_COUNT;
+
info->tty = tty;
info->idx = 0;
info->len = 0;
@@ -216,8 +205,6 @@ static int js_war_ldisc_open(struct tty_struct *tty)
js_war_init_corr(js_war_port->corr);
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -283,9 +270,7 @@ static int js_war_ldisc_room(struct tty_struct *tty)
static struct tty_ldisc js_war_ldisc = {
magic: TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
name: "warrior",
-#endif
open: js_war_ldisc_open,
close: js_war_ldisc_close,
receive_buf: js_war_ldisc_receive,
diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c
index cfd0f2e82..d0dc70f55 100644
--- a/drivers/char/joystick/joystick.c
+++ b/drivers/char/joystick/joystick.c
@@ -499,6 +499,7 @@ static int js_open(struct inode *inode, struct file *file)
if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
return -EINVAL;
+
spin_lock_irqsave(&js_lock, flags);
while (i > 0 && jd) {
@@ -510,32 +511,32 @@ static int js_open(struct inode *inode, struct file *file)
if (!jd) return -ENODEV;
- if ((result = jd->open(jd))) return result;
-
- if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {
+ if ((result = jd->open(jd)))
+ return result;
- MOD_INC_USE_COUNT;
+ MOD_INC_USE_COUNT;
- spin_lock_irqsave(&js_lock, flags);
+ if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
- curl = jd->list;
+ spin_lock_irqsave(&js_lock, flags);
- jd->list = new;
- jd->list->next = curl;
- jd->list->dev = jd;
- jd->list->startup = 0;
- jd->list->tail = GOB(jd->bhead);
- file->private_data = jd->list;
+ curl = jd->list;
- spin_unlock_irqrestore(&js_lock, flags);
+ jd->list = new;
+ jd->list->next = curl;
+ jd->list->dev = jd;
+ jd->list->startup = 0;
+ jd->list->tail = GOB(jd->bhead);
+ file->private_data = jd->list;
- if (!js_use_count++) js_do_timer(0);
+ spin_unlock_irqrestore(&js_lock, flags);
- } else {
- result = -ENOMEM;
- }
+ if (!js_use_count++) js_do_timer(0);
- return result;
+ return 0;
}
/*
@@ -573,10 +574,11 @@ static int js_release(struct inode *inode, struct file *file)
kfree(file->private_data);
if (!--js_use_count) del_timer(&js_timer);
- MOD_DEC_USE_COUNT;
jd->close(jd);
+ MOD_DEC_USE_COUNT;
+
return 0;
}
@@ -585,50 +587,6 @@ static int js_release(struct inode *inode, struct file *file)
* It's used for debugging only.
*/
-#if 0
-static void js_dump_mem(void)
-{
-
- struct js_port *curp = js_port;
- struct js_dev *curd = js_dev;
- int i;
-
- printk(",--- Dumping Devices:\n");
- printk("| js_dev = %x\n", (int) js_dev);
-
- while (curd) {
- printk("| %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n",
- curd->next ? "|":"`",
- (int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io);
- curd = curd->next;
- }
-
- printk(">--- Dumping ports:\n");
- printk("| js_port = %x\n", (int) js_port);
-
- while (curp) {
- printk("| %s-port %x, next %x, io %#x, devices %d\n",
- curp->next ? "|":"`",
- (int) curp, (int) curp->next, curp->io, curp->ndevs);
- for (i = 0; i < curp->ndevs; i++) {
- curd = curp->devs[i];
- if (curd)
- printk("| %s %s-device %x, next %x axes %d, buttons %d, port %x\n",
- curp->next ? "|":" ", (i < curp->ndevs-1) ? "|":"`",
- (int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port);
- else
- printk("| %s %s-device %x, not there\n",
- curp->next ? "|":" ", (i < curp->ndevs-1) ? "|":"`", (int) curd);
-
- }
- curp = curp->next;
- }
-
- printk("`--- Done\n");
-}
-#endif
-
-
struct js_port *js_register_port(struct js_port *port,
void *info, int devs, int infos, js_read_func read)
{
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e9a34fbf3..79b7201f9 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -34,9 +34,6 @@ void soundcore_init(void);
#ifdef CONFIG_SOUND_OSS
void soundcard_init(void);
#endif
-#ifdef CONFIG_DMASOUND
-void dmasound_init(void);
-#endif
#endif
#ifdef CONFIG_SPARCAUDIO
extern int sparcaudio_init(void);
@@ -637,9 +634,6 @@ int __init chr_dev_init(void)
#ifdef CONFIG_SOUND_OSS
soundcard_init();
#endif
-#ifdef CONFIG_DMASOUND
- dmasound_init();
-#endif
#endif
#ifdef CONFIG_SPARCAUDIO
sparcaudio_init();
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index a2097967e..f155cf091 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -12,7 +12,10 @@
* Author:
* L. Haag
*
- * $Log: r3964.c,v $
+ * $Log: n_r3964.c,v $
+ * Revision 1.8 2000/03/23 14:14:54 dwmw2
+ * Fix race in sleeping in r3964_read()
+ *
* Revision 1.7 1999/28/08 11:41:50 dwmw2
* Port to 2.3 kernel
*
@@ -38,7 +41,6 @@
*
*
*/
-#define R3964_VERSION "1.7"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -224,7 +226,7 @@ static int __init r3964_init(void)
{
int status;
- printk ("r3964: Philips r3964 Driver V%s\n", R3964_VERSION);
+ printk ("r3964: Philips r3964 Driver $Revision: 1.8 $\n");
/*
* Register the tty line discipline
@@ -1280,8 +1282,8 @@ static int r3964_read(struct tty_struct *tty, struct file *file,
/* block until there is a message: */
add_wait_queue(&pInfo->read_wait, &wait);
repeat:
- pMsg = remove_msg(pInfo, pClient);
current->state = TASK_INTERRUPTIBLE;
+ pMsg = remove_msg(pInfo, pClient);
if (!pMsg && !signal_pending(current))
{
schedule();
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index c5b0e54ba..2e2d391fa 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -39,6 +39,7 @@
* 990605 Made changes to code to support Firmware 1.22a, added
* fairly useless proc entry.
* 990610 removed said useless proc code for the merge <alan>
+ * 000403 Removed last traces of proc code. <davej>
*/
#include <linux/module.h>
@@ -541,38 +542,6 @@ static void debug_off(void)
mode_debug = 0;
}
-static int pcwd_proc_get_info(char *buffer, char **start, off_t offset,
- int length, int inout)
-{
- int len;
- off_t begin = 0;
-
- revision = get_revision();
- len = sprintf(buffer, "Version = " WD_VER "\n");
-
- if (revision == PCWD_REVISION_A)
- len += sprintf(buffer + len, "Revision = A\n");
- else
- len += sprintf(buffer + len, "Revision = C\n");
-
- if (supports_temp) {
- unsigned short c = inb(current_readport);
-
- len += sprintf(buffer + len, "Temp = Yes\n"
- "Current temp = %d (Celsius)\n",
- c);
- } else
- len += sprintf(buffer + len, "Temp = No\n");
-
- *start = buffer + (offset);
- len -= offset;
-
- if (len > length)
- len = length;
-
- return len;
-}
-
static struct file_operations pcwd_fops = {
read: pcwd_read,
write: pcwd_write,
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 4336009fc..b392ef70e 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -537,7 +537,7 @@ static int pp_release (struct inode * inode, struct file * file)
unsigned int minor = MINOR (inode->i_rdev);
struct pp_struct *pp = file->private_data;
- if (pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) {
+ if (pp->pdev && pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) {
if (!(pp->flags & PP_CLAIMED)) {
parport_claim_or_block (pp->pdev);
pp->flags |= PP_CLAIMED;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 9331852e1..4f1c9c703 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -29,10 +29,6 @@
#define BUILDING_PTY_C 1
#include <linux/devpts_fs.h>
-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);
-
struct pty_struct {
int magic;
wait_queue_head_t open_wait;
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 110df61af..91000f708 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -220,10 +220,6 @@ static char *serial_revdate = "2000-03-20";
#define _INLINE_
#endif
-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);
@@ -4361,6 +4357,9 @@ static struct pci_board pnp_devices[] __initdata = {
/* U.S. Robotics 56K FAX INT */
{ ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Viking 56K FAX INT */
+ { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* These ID's are taken from M$ documentation */
/* Compaq 14400 Modem */
diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
index 827be953a..bff89aff8 100644
--- a/drivers/char/sh-sci.c
+++ b/drivers/char/sh-sci.c
@@ -1,9 +1,10 @@
-/* $Id: sh-sci.c,v 1.32 2000-03-05 13:56:18+09 gniibe Exp $
+/* $Id: sh-sci.c,v 1.36 2000/03/22 13:32:10 gniibe Exp $
*
* linux/drivers/char/sh-sci.c
*
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
* Copyright (C) 1999, 2000 Niibe Yutaka
+ * Copyright (C) 2000 Sugioka Toshinobu
*
* TTY code is based on sx.c (Specialix SX driver) by:
*
@@ -38,7 +39,7 @@
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include "generic_serial.h"
+#include <linux/generic_serial.h>
#include "sh-sci.h"
#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
@@ -54,7 +55,7 @@ static void sci_disable_rx_interrupts(void *ptr);
static void sci_enable_rx_interrupts(void *ptr);
static int sci_get_CD(void *ptr);
static void sci_shutdown_port(void *ptr);
-static void sci_set_real_termios(void *ptr);
+static int sci_set_real_termios(void *ptr);
static void sci_hungup(void *ptr);
static void sci_close(void *ptr);
static int sci_chars_in_buffer(void *ptr);
@@ -142,7 +143,11 @@ static void sci_set_baud(struct sci_port *port)
}
if (t > 0) {
- sci_setsignals (port, 1, -1);
+ sci_setsignals (port, 1, -1);
+ if(t >= 256) {
+ ctrl_out((ctrl_in(SCSMR) & ~3) | 1, SCSMR);
+ t >>= 2;
+ }
ctrl_outb(t, SCBRR);
ctrl_outw(0xa400, RFCR); /* Refresh counter clear */
while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER)
@@ -155,7 +160,7 @@ static void sci_set_baud(struct sci_port *port)
static void sci_set_termios_cflag(struct sci_port *port)
{
unsigned short status;
- unsigned short smr_val=0;
+ unsigned short smr_val;
#if defined(CONFIG_SH_SCIF_SERIAL)
unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */
#endif
@@ -172,6 +177,7 @@ static void sci_set_termios_cflag(struct sci_port *port)
fcr_val = 0;
#endif
+ smr_val = ctrl_in(SCSMR) & 3;
if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7)
smr_val |= 0x40;
if (C_PARENB(port->gs.tty))
@@ -196,7 +202,7 @@ static void sci_set_termios_cflag(struct sci_port *port)
sci_enable_rx_interrupts(port);
}
-static void sci_set_real_termios(void *ptr)
+static int sci_set_real_termios(void *ptr)
{
struct sci_port *port = ptr;
@@ -218,6 +224,8 @@ static void sci_set_real_termios(void *ptr)
set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
else
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+
+ return 0;
}
/* ********************************************************************** *
@@ -352,10 +360,16 @@ static inline void sci_receive_chars(struct sci_port *port)
static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
struct sci_port *port = ptr;
+ unsigned long flags;
if (port->gs.flags & GS_ACTIVE)
- if (!(port->gs.flags & SCI_RX_THROTTLE))
+ if (!(port->gs.flags & SCI_RX_THROTTLE)) {
sci_receive_chars(port);
+ return;
+ }
+ save_and_cli(flags);
+ ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_RIE, SCSCR);
+ restore_flags(flags);
}
static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
@@ -363,9 +377,14 @@ static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
struct sci_port *port = ptr;
if (port->gs.flags & GS_ACTIVE)
- if (port->gs.xmit_cnt) {
- sci_transmit_chars(port);
- }
+ sci_transmit_chars(port);
+ else {
+ unsigned long flags;
+
+ save_and_cli(flags);
+ ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_TIE, SCSCR);
+ restore_flags(flags);
+ }
}
static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h
index 9239e41d7..2a736f4c9 100644
--- a/drivers/char/sh-sci.h
+++ b/drivers/char/sh-sci.h
@@ -1,4 +1,4 @@
-/* $Id: sh-sci.h,v 1.5 2000-03-05 13:54:32+09 gniibe Exp $
+/* $Id: sh-sci.h,v 1.8 2000/03/08 15:19:39 gniibe Exp $
*
* linux/drivers/char/sh-sci.h
*
@@ -18,13 +18,18 @@
#define SC_SR (volatile unsigned char *)0xfffffe88
#define SC_RDR 0xfffffe8a
#define SCSPTR 0xffffff7c
-
-#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-
#elif defined(__SH4__)
-Not yet.
+#define SCSMR (volatile unsigned char *)0xffe00000
+#define SCBRR 0xffe00004
+#define SCSCR (volatile unsigned char *)0xffe00008
+#define SC_TDR 0xffe0000c
+#define SC_SR (volatile unsigned char *)0xffe00010
+#define SC_RDR 0xffe00014
+#define SCSPTR 0xffe0001c
#endif
+#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+
#define SCI_TD_E 0x80
#define SCI_RD_F 0x40
#define SCI_ORER 0x20
@@ -45,8 +50,6 @@ Not yet.
#define SCI_CTRL_FLAGS_CKE1 0x02
#define SCI_CTRL_FLAGS_CKE0 0x01
-#define RFCR 0xffffff74
-
#define SCI_ERI_IRQ 23
#define SCI_RXI_IRQ 24
#define SCI_TXI_IRQ 25
@@ -69,8 +72,6 @@ Not yet.
#undef SCSPTR /* Is there any register for RTS?? */
#undef SCLSR
-#define RFCR 0xffffff74
-
#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
/* 0x33 when external clock is used */
#define SCI_IPR_OFFSET (64+4)
@@ -87,8 +88,6 @@ Not yet.
#define SCSPTR 0xFFE80020
#define SCLSR 0xFFE80024
-#define RFCR 0xFF800028
-
#define SCSCR_INIT 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
#define SCI_IPR_OFFSET (32+4)
@@ -131,6 +130,12 @@ Not yet.
#endif
#endif
+#if defined(__sh3__)
+#define RFCR 0xffffff74
+#elif defined(__SH4__)
+#define RFCR 0xFF800028
+#endif
+
#define SCI_PRIORITY 3
#define SCI_MINOR_START 64
@@ -183,14 +188,15 @@ struct sci_port {
*/
#if defined(__sh3__)
-#define BPS_2400 191
-#define BPS_4800 95
-#define BPS_9600 47
-#define BPS_19200 23
-#define BPS_38400 11
-#define BPS_115200 3
+#define PCLK 14745600
#elif defined(__SH4__)
-/* Values for SH-4 please! */
-
-#define BPS_115200 8
+#define PCLK 33333333
#endif
+
+#define SCBRR_VALUE(bps) (PCLK/(32*bps)-1)
+#define BPS_2400 SCBRR_VALUE(2400)
+#define BPS_4800 SCBRR_VALUE(4800)
+#define BPS_9600 SCBRR_VALUE(9600)
+#define BPS_19200 SCBRR_VALUE(19200)
+#define BPS_38400 SCBRR_VALUE(38400)
+#define BPS_115200 SCBRR_VALUE(115200)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 1e0c22ee6..2c4a8777d 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -99,9 +99,6 @@
#ifdef CONFIG_VT
extern void con_init_devfs (void);
#endif
-void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
- unsigned minor);
-void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
@@ -153,6 +150,12 @@ extern long serial167_console_init(void);
extern console_8xx_init(void);
extern int rs_8xx_init(void);
#endif /* CONFIG_8xx */
+#ifdef CONFIG_HWC
+extern void hwc_console_init(void);
+#endif
+#ifdef CONFIG_3215
+extern void con3215_init(void);
+#endif /* CONFIG_3215 */
#ifndef MIN
@@ -2192,6 +2195,12 @@ void __init console_init(void)
serial167_console_init();
#endif
#endif
+#ifdef CONFIG_3215
+ con3215_init();
+#endif
+#ifdef CONFIG_HWC
+ hwc_console_init();
+#endif
}
static struct tty_driver dev_tty_driver, dev_syscons_driver;
diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c
index dfea37d63..0ed55b715 100644
--- a/drivers/char/tuner.c
+++ b/drivers/char/tuner.c
@@ -97,7 +97,6 @@ static struct tunertype tuners[] = {
{ "Temic NTSC", TEMIC, NTSC,
16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
{ "Temic PAL_I", TEMIC, PAL_I,
- // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
{ "Temic 4036 FY5 NTSC", TEMIC, NTSC,
16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
@@ -111,6 +110,8 @@ static struct tunertype tuners[] = {
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
{ "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
+ { "Temic 4006FH5", TEMIC, PAL_I,
+ 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
};
#define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index 0a4e65c57..60990d1db 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -47,6 +47,9 @@ extern int i2c_tuner_init(struct video_init *);
#ifdef CONFIG_VIDEO_BWQCAM
extern int init_bw_qcams(struct video_init *);
#endif
+#ifdef CONFIG_VIDEO_CPIA
+extern int cpia_init(struct video_init *);
+#endif
#ifdef CONFIG_VIDEO_PLANB
extern int init_planbs(struct video_init *);
#endif
@@ -62,6 +65,9 @@ static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BWQCAM
{"bw-qcam", init_bw_qcams},
#endif
+#ifdef CONFIG_VIDEO_CPIA
+ {"cpia", cpia_init},
+#endif
#ifdef CONFIG_VIDEO_PLANB
{"planb", init_planbs},
#endif
@@ -133,9 +139,11 @@ static int video_open(struct inode *inode, struct file *file)
if(vfl==NULL) {
char modname[20];
+ MOD_INC_USE_COUNT;
sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor);
request_module(modname);
vfl=video_device[minor];
+ MOD_DEC_USE_COUNT;
if (vfl==NULL)
return -ENODEV;
}
diff --git a/drivers/char/wd501p.h b/drivers/char/wd501p.h
index 81971da6b..11fc72b04 100644
--- a/drivers/char/wd501p.h
+++ b/drivers/char/wd501p.h
@@ -25,11 +25,21 @@
#define WDT_COUNT1 (io+1)
#define WDT_COUNT2 (io+2)
#define WDT_CR (io+3)
-#define WDT_SR (io+4)
-#define WDT_RT (io+5)
-#define WDT_UNUSED (io+6)
+#define WDT_SR (io+4) /* Start buzzer on PCI write */
+#define WDT_RT (io+5) /* Stop buzzer on PCI write */
+#define WDT_BUZZER (io+6) /* PCI only: rd=disable, wr=enable */
#define WDT_DC (io+7)
+/* The following are only on the PCI card, they're outside of I/O space on
+ * the ISA card: */
+#define WDT_CLOCK (io+12) /* COUNT2: rd=16.67MHz, wr=2.0833MHz */
+/* inverted opto isolated reset output: */
+#define WDT_OPTONOTRST (io+13) /* wr=enable, rd=disable */
+/* opto isolated reset output: */
+#define WDT_OPTORST (io+14) /* wr=enable, rd=disable */
+/* programmable outputs: */
+#define WDT_PROGOUT (io+15) /* wr=enable, rd=disable */
+
#define WDC_SR_WCCR 1 /* Active low */
#define WDC_SR_TGOOD 2
#define WDC_SR_ISOI0 4
@@ -39,6 +49,8 @@
#define WDC_SR_PSUUNDR 64 /* Active low */
#define WDC_SR_IRQ 128 /* Active low */
+#ifndef WDT_IS_PCI
+
/*
* Feature Map 1 is the active high inputs not supported on your card.
* Feature Map 2 is the active low inputs not supported on your card.
@@ -67,6 +79,13 @@
#define WDT_OPTION_MASK (WDIOF_OVERHEAT)
#endif
+#else
+
+#define FEATUREMAP1 (WDC_SR_TGOOD|WDC_SR_FANGOOD)
+#define FEATUREMAP2 (WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
+#define WDT_OPTION_MASK (WDIOF_OVERHEAT)
+#endif
+
#ifndef FEATUREMAP1
#error "Config option not set"
#endif
diff --git a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
new file mode 100644
index 000000000..6e99a72ac
--- /dev/null
+++ b/drivers/char/wdt_pci.c
@@ -0,0 +1,558 @@
+/*
+ * Industrial Computer Source WDT500/501 driver for Linux 2.1.x
+ *
+ * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.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.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ * Release 0.08.
+ *
+ * Fixes
+ * Dave Gregorich : Modularisation and minor bugs
+ * Alan Cox : Added the watchdog ioctl() stuff
+ * Alan Cox : Fixed the reboot problem (as noted by
+ * Matt Crocker).
+ * Alan Cox : Added wdt= boot option
+ * Alan Cox : Cleaned up copy/user stuff
+ * Tim Hockin : Added insmod parameters, comment cleanup
+ * Parameterized timeout
+ * JP Nollmann : Added support for PCI wdt501p
+ * Alan Cox : Split ISA and PCI cards into two drivers
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#define WDT_IS_PCI
+#include "wd501p.h"
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+
+/*
+ * Until Access I/O gets their application for a PCI vendor ID approved,
+ * I don't think that it's appropriate to move these constants into the
+ * regular pci_ids.h file. -- JPN 2000/01/18
+ */
+
+#ifndef PCI_VENDOR_ID_ACCESSIO
+#define PCI_VENDOR_ID_ACCESSIO 0x494f
+#endif
+#ifndef PCI_DEVICE_ID_WDG_CSM
+#define PCI_DEVICE_ID_WDG_CSM 0x22c0
+#endif
+
+static int wdt_is_open=0;
+
+/*
+ * You must set these - there is no sane way to probe for this board.
+ * You can use wdt=x,y to set these now.
+ */
+
+static int io=0x240;
+static int irq=11;
+
+#define WD_TIMO (100*60) /* 1 minute */
+
+#ifndef MODULE
+
+/**
+ * wdtpci_setup:
+ * @str: command line string
+ *
+ * Setup options. The board isn't really probe-able so we have to
+ * get the user to tell us the configuration. Sane people build it
+ * modular but the others come here.
+ */
+
+static int __init wdtpci_setup(char *str)
+{
+ int ints[4];
+
+ str = get_options (str, ARRAY_SIZE(ints), ints);
+
+ if (ints[0] > 0)
+ {
+ io = ints[1];
+ if(ints[0] > 1)
+ irq = ints[2];
+ }
+
+ return 1;
+}
+
+__setup("wdt=", wdtpci_setup);
+
+#endif /* !MODULE */
+
+/*
+ * Programming support
+ */
+
+static void wdtpci_ctr_mode(int ctr, int mode)
+{
+ ctr<<=6;
+ ctr|=0x30;
+ ctr|=(mode<<1);
+ outb_p(ctr, WDT_CR);
+}
+
+static void wdtpci_ctr_load(int ctr, int val)
+{
+ outb_p(val&0xFF, WDT_COUNT0+ctr);
+ outb_p(val>>8, WDT_COUNT0+ctr);
+}
+
+/*
+ * Kernel methods.
+ */
+
+
+/**
+ * wdtpci_status:
+ *
+ * Extract the status information from a WDT watchdog device. There are
+ * several board variants so we have to know which bits are valid. Some
+ * bits default to one and some to zero in order to be maximally painful.
+ *
+ * we then map the bits onto the status ioctl flags.
+ */
+
+static int wdtpci_status(void)
+{
+ /*
+ * Status register to bit flags
+ */
+
+ int flag=0;
+ unsigned char status=inb_p(WDT_SR);
+ status|=FEATUREMAP1;
+ status&=~FEATUREMAP2;
+
+ if(!(status&WDC_SR_TGOOD))
+ flag|=WDIOF_OVERHEAT;
+ if(!(status&WDC_SR_PSUOVER))
+ flag|=WDIOF_POWEROVER;
+ if(!(status&WDC_SR_PSUUNDR))
+ flag|=WDIOF_POWERUNDER;
+ if(!(status&WDC_SR_FANGOOD))
+ flag|=WDIOF_FANFAULT;
+ if(status&WDC_SR_ISOI0)
+ flag|=WDIOF_EXTERN1;
+ if(status&WDC_SR_ISII1)
+ flag|=WDIOF_EXTERN2;
+ return flag;
+}
+
+/**
+ * wdtpci_interrupt:
+ * @irq: Interrupt number
+ * @dev_id: Unused as we don't allow multiple devices.
+ * @regs: Unused.
+ *
+ * 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.
+ */
+
+static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /*
+ * Read the status register see what is up and
+ * then printk it.
+ */
+
+ unsigned char status=inb_p(WDT_SR);
+
+ status|=FEATUREMAP1;
+ status&=~FEATUREMAP2;
+
+ printk(KERN_CRIT "WDT status %d\n", status);
+
+ if(!(status&WDC_SR_TGOOD))
+ printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
+ if(!(status&WDC_SR_PSUOVER))
+ printk(KERN_CRIT "PSU over voltage.\n");
+ if(!(status&WDC_SR_PSUUNDR))
+ printk(KERN_CRIT "PSU under voltage.\n");
+ if(!(status&WDC_SR_FANGOOD))
+ printk(KERN_CRIT "Possible fan fault.\n");
+ if(!(status&WDC_SR_WCCR))
+#ifdef SOFTWARE_REBOOT
+#ifdef ONLY_TESTING
+ printk(KERN_CRIT "Would Reboot.\n");
+#else
+ printk(KERN_CRIT "Initiating system reboot.\n");
+ machine_restart(NULL);
+#endif
+#else
+ printk(KERN_CRIT "Reset in 5ms.\n");
+#endif
+}
+
+
+static long long wdtpci_llseek(struct file *file, long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+/**
+ * wdtpci_ping:
+ *
+ * Reload counter one with the watchdog timeout. We don't bother reloading
+ * the cascade counter.
+ */
+
+static void wdtpci_ping(void)
+{
+ /* Write a watchdog value */
+ inb_p(WDT_DC);
+ wdtpci_ctr_mode(1,2);
+ wdtpci_ctr_load(1,WD_TIMO); /* Timeout */
+ outb_p(0, WDT_DC);
+}
+
+/**
+ * wdtpci_write:
+ * @file: file handle to the watchdog
+ * @buf: buffer to write (unused as data does not matter here
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if(count)
+ {
+ wdtpci_ping();
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * wdtpci_read:
+ * @file: file handle to the watchdog board
+ * @buf: buffer to write 1 byte into
+ * @count: length of buffer
+ * @ptr: offset (no seek allowed)
+ *
+ * Read reports the temperature in degrees Fahrenheit. The API is in
+ * farenheit. It was designed by an imperial measurement luddite.
+ */
+
+static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+ unsigned short c=inb_p(WDT_RT);
+ unsigned char cp;
+
+ /* Can't seek (pread) on this device */
+ if (ptr != &file->f_pos)
+ return -ESPIPE;
+
+ switch(MINOR(file->f_dentry->d_inode->i_rdev))
+ {
+ case TEMP_MINOR:
+ c*=11;
+ c/=15;
+ cp=c+7;
+ if(copy_to_user(buf,&cp,1))
+ return -EFAULT;
+ return 1;
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * wdtpci_ioctl:
+ * @inode: inode of the device
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features. We only actually usefully support
+ * querying capabilities and current status.
+ */
+
+static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ static struct watchdog_info ident=
+ {
+ WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
+ |WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT,
+ 1,
+ "WDT500/501PCI"
+ };
+
+ ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */
+ switch(cmd)
+ {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
+
+ case WDIOC_GETSTATUS:
+ return put_user(wdtpci_status(),(int *)arg);
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, (int *)arg);
+ case WDIOC_KEEPALIVE:
+ wdtpci_ping();
+ return 0;
+ }
+}
+
+/**
+ * wdtpci_open:
+ * @inode: inode of device
+ * @file: file handle to device
+ *
+ * One of our two misc devices has been opened. The watchdog device is
+ * single open and on opening we load the counters. Counter zero is a
+ * 100Hz cascade, into counter 1 which downcounts to reboot. When the
+ * counter triggers counter 2 downcounts the length of the reset pulse
+ * which set set to be as long as possible.
+ */
+
+static int wdtpci_open(struct inode *inode, struct file *file)
+{
+ switch(MINOR(inode->i_rdev))
+ {
+ case WATCHDOG_MINOR:
+ if(wdt_is_open)
+ return -EBUSY;
+ MOD_INC_USE_COUNT;
+ /*
+ * Activate
+ */
+
+ wdt_is_open=1;
+
+ inb_p(WDT_DC); /* Disable */
+
+ /*
+ * "pet" the watchdog, as Access says.
+ * This resets the clock outputs.
+ */
+
+ wdtpci_ctr_mode(2,0);
+ outb_p(0, WDT_DC);
+
+ inb_p(WDT_DC);
+
+ outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */
+ inb_p(WDT_BUZZER); /* disable */
+ inb_p(WDT_OPTONOTRST); /* disable */
+ inb_p(WDT_OPTORST); /* disable */
+ inb_p(WDT_PROGOUT); /* disable */
+ wdtpci_ctr_mode(0,3);
+ wdtpci_ctr_mode(1,2);
+ wdtpci_ctr_mode(2,1);
+ wdtpci_ctr_load(0,20833); /* count at 100Hz */
+ wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */
+ /* DO NOT LOAD CTR2 on PCI card! -- JPN */
+ outb_p(0, WDT_DC); /* Enable */
+ return 0;
+ case TEMP_MINOR:
+ MOD_INC_USE_COUNT;
+ return 0;
+ default:
+ return -ENODEV;
+ }
+}
+
+/**
+ * wdtpci_close:
+ * @inode: inode to board
+ * @file: file handle to board
+ *
+ * The watchdog has a configurable API. There is a religious dispute
+ * between people who want their watchdog to be able to shut down and
+ * those who want to be sure if the watchdog manager dies the machine
+ * reboots. In the former case we disable the counters, in the latter
+ * case you have to open it again very soon.
+ */
+
+static int wdtpci_release(struct inode *inode, struct file *file)
+{
+ if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+ {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ inb_p(WDT_DC); /* Disable counters */
+ wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
+#endif
+ wdt_is_open=0;
+ }
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/**
+ * notify_sys:
+ * @this: our notifier block
+ * @code: the event being reported
+ * @unused: unused
+ *
+ * Our notifier is called on system shutdowns. We want to turn the card
+ * off at reboot otherwise the machine will reboot again during memory
+ * test or worse yet during the following fsck. This would suck, in fact
+ * trust me - if it happens it does suck.
+ */
+
+static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if(code==SYS_DOWN || code==SYS_HALT)
+ {
+ /* Turn the card off */
+ inb_p(WDT_DC);
+ wdtpci_ctr_load(2,0);
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+
+static struct file_operations wdtpci_fops = {
+ llseek: wdtpci_llseek,
+ read: wdtpci_read,
+ write: wdtpci_write,
+ ioctl: wdtpci_ioctl,
+ open: wdtpci_open,
+ release: wdtpci_release,
+};
+
+static struct miscdevice wdtpci_miscdev=
+{
+ WATCHDOG_MINOR,
+ "watchdog",
+ &wdtpci_fops
+};
+
+#ifdef CONFIG_WDT_501
+static struct miscdevice temp_miscdev=
+{
+ TEMP_MINOR,
+ "temperature",
+ &wdtpci_fops
+};
+#endif
+
+/*
+ * The WDT card needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block wdtpci_notifier=
+{
+ wdtpci_notify_sys,
+ NULL,
+ 0
+};
+
+#ifdef MODULE
+
+#define wdtpci_init init_module
+
+/**
+ * cleanup_module:
+ *
+ * Unload the watchdog. You cannot do this with any file handles open.
+ * If your watchdog is set to continue ticking on close and you unload
+ * it, well it keeps ticking. We won't get the interrupt but the board
+ * will not touch PC memory so all is fine. You just have to load a new
+ * module in 60 seconds or reboot.
+ */
+
+void cleanup_module(void)
+{
+ misc_deregister(&wdtpci_miscdev);
+#ifdef CONFIG_WDT_501_PCI
+ misc_deregister(&temp_miscdev);
+#endif
+ unregister_reboot_notifier(&wdtpci_notifier);
+ release_region(io,16);
+ free_irq(irq, &wdtpci_miscdev);
+}
+
+#endif
+
+/**
+ * wdtpci_init:
+ *
+ * Set up the WDT watchdog board. All we have to do is grab the
+ * resources we require and bitch if anyone beat us to them.
+ * The open() function will actually kick the board off.
+ */
+
+int __init wdtpci_init(void)
+{
+ struct pci_dev *dev = NULL;
+
+ if (pci_present())
+ {
+ while ((dev = pci_find_device(PCI_VENDOR_ID_ACCESSIO,
+ PCI_DEVICE_ID_WDG_CSM, dev))) {
+ /* See if we can do this device */
+ irq = dev->irq;
+ io = dev->resource[2].start;
+ printk("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
+ "(Interrupt %d)\n", io, irq);
+ }
+ }
+ if(request_region(io, 16, "wdt-pci")==NULL)
+ {
+ printk(KERN_ERR "I/O %d is not free.\n", io);
+ return -EIO;
+ }
+ if(request_irq(irq, wdtpci_interrupt, SA_INTERRUPT|SA_SHIRQ, "wdt-pci", &wdtpci_miscdev))
+ {
+ printk(KERN_ERR "IRQ %d is not free.\n", irq);
+ release_region(io, 16);
+ return -EIO;
+ }
+ misc_register(&wdtpci_miscdev);
+#ifdef CONFIG_WDT_501
+ misc_register(&temp_miscdev);
+#endif
+ register_reboot_notifier(&wdtpci_notifier);
+ return 0;
+}
+
diff --git a/drivers/i2c/i2c-elektor.c b/drivers/i2c/i2c-elektor.c
index 6140f61cd..86e79f22c 100644
--- a/drivers/i2c/i2c-elektor.c
+++ b/drivers/i2c/i2c-elektor.c
@@ -231,7 +231,7 @@ static struct i2c_adapter pcf_isa_ops = {
pcf_isa_unreg,
};
-static int __init i2c_pcfisa_init(void)
+int __init i2c_pcfisa_init(void)
{
struct i2c_pcf_isa *pisa = &gpi;
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 33014bc06..e8cfa5c7a 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -813,14 +813,18 @@ static void idedisk_setup (ide_drive_t *drive)
(!drive->forced_geom) && drive->bios_sect && drive->bios_head)
drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-#if 0 /* done instead for entire identify block in arch/ide.h stuff */
- /* fix byte-ordering of buffer size field */
- id->buf_size = le16_to_cpu(id->buf_size);
-#endif
- printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
- drive->name, id->model,
- capacity/2048L, id->buf_size/2,
- drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
+
+ /* Give size in megabytes (MB), not mebibytes (MiB). */
+ /* We compute the exact rounded value, avoiding overflow. */
+ printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950);
+
+ /* Only print cache size when it was specified */
+ if (id->buf_size)
+ printk (" w/%dKiB Cache", id->buf_size/2);
+
+ printk(", CHS=%d/%d/%d",
+ drive->bios_cyl, drive->bios_head, drive->bios_sect);
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->using_dma)
(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index cdd10f6e1..35ba5cb5f 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -603,6 +603,8 @@ check_if_enabled:
IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
+ IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
+ IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 89921f7b9..fb24fb0a5 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1662,6 +1662,7 @@ void ide_init_drive_cmd (struct request *rq)
rq->cmd = IDE_DRIVE_CMD;
rq->sector = 0;
rq->nr_sectors = 0;
+ rq->nr_segments = 0;
rq->current_nr_sectors = 0;
rq->sem = NULL;
rq->bh = NULL;
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 9ce1cf4af..3097345c8 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);
-/**
- * DOC: SMP and the 8390 setup.
+/*
+ * 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
@@ -407,13 +407,16 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/**
- * ei_interrupt -
- * @irq:
- * @dev_id:
- * @regs:
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+ * @regs: unused
*
- * The typical workload of the driver:
- * Handle the ether interface interrupts.
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+ * stack. We also handle transmit completions and wake the transmit path if
+ * neccessary. We also update the counters and do other housekeeping as
+ * needed
*/
void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 057f2f704..6b72d0b0d 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -108,9 +108,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
tristate ' HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
- if [ "$CONFIG_OBSOLETE" = "y" ]; then
- tristate ' ICL EtherTeam 16i/32 support' CONFIG_ETH16I
- fi
+ tristate ' ICL EtherTeam 16i/32 support' CONFIG_ETH16I
tristate ' NE2000/NE1000 support' CONFIG_NE2000
if [ "$CONFIG_OBSOLETE" = "y" ]; then
tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
@@ -194,7 +192,7 @@ endmenu
bool 'FDDI driver support' CONFIG_FDDI
if [ "$CONFIG_FDDI" = "y" ]; then
- bool ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+ dep_tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_FDDI
tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP
fi
@@ -216,6 +214,7 @@ fi
tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
if [ ! "$CONFIG_PPP" = "n" ]; then
+ dep_bool ' PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index c2eeb81ba..fc59bfb08 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -324,7 +324,9 @@ OX_OBJS := $(filter $(export-objs), $(obj-y))
M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+ifneq ($(ARCH),s390)
O_OBJS += auto_irq.o
+endif
include $(TOPDIR)/Rules.make
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index bccd82b04..7e6910154 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -118,7 +118,7 @@ extern int de600_probe(struct net_device *);
extern int de620_probe(struct net_device *);
/* FDDI adapters */
-extern int dfx_probe(struct net_device *dev);
+extern int dfx_probe(void);
extern int apfddi_init(struct net_device *dev);
extern int skfp_probe(struct net_device *dev);
@@ -184,6 +184,9 @@ struct devprobe eisa_probes[] __initdata = {
#ifdef CONFIG_NE3210
{ne3210_probe, 0},
#endif
+#ifdef CONFIG_DEFXX
+ {dfx_probe, 0}.
+#endif
{NULL, 0},
};
@@ -465,9 +468,6 @@ static int __init fddiif_probe(struct net_device *dev)
return 1; /* ENXIO */
if (1
-#ifdef CONFIG_DEFXX
- && dfx_probe(dev)
-#endif
#ifdef CONFIG_APFDDI
&& apfddi_init(dev)
#endif
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 91aeaced9..00fb09341 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -194,11 +194,12 @@
* 12-Sep-96 LVS Reset current address to factory address during
* device open. Updated transmit path to post a
* single fragment which includes PRH->end of data.
+ * Mar 2000 AC Did various cleanups for 2.3.x
*/
/* Version information string - should be updated prior to each new release!!! */
-static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefani@lkg.dec.com)\n";
+static const char *version = "defxx.c:v1.05 2000/03/26 Lawrence V. Stefani (stefani@lkg.dec.com) and others\n";
/* Include files */
@@ -236,11 +237,11 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa
/* Define global routines */
-int dfx_probe(struct net_device *dev);
+int dfx_probe(void);
/* Define module-wide (static) routines */
-static struct net_device *dfx_alloc_device(struct net_device *dev, u16 iobase);
+static struct net_device *dfx_alloc_device(u16 iobase);
static void dfx_bus_init(struct net_device *dev);
static void dfx_bus_config_check(DFX_board_t *bp);
@@ -402,29 +403,9 @@ static inline void dfx_port_read_long(
* dev - pointer to device information
*
* Functional Description:
- * This routine is called by the OS for each FDDI device name (fddi0,
- * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. Since
- * the DEFXX.C driver currently does not support being loaded as a
- * module, dfx_probe() will initialize all devices the first time
- * it is called.
- *
- * Let's say that dfx_probe() is getting called to initialize fddi0.
- * Furthermore, let's say there are three supported controllers in the
- * system. Before dfx_probe() leaves, devices fddi0, fddi1, and fddi2
- * will be initialized and a global flag will be set to indicate that
- * dfx_probe() has already been called.
- *
- * However...the OS doesn't know that we've already initialized
- * devices fddi1 and fddi2 so dfx_probe() gets called again and again
- * until it reaches the end of the device list for FDDI (presently,
- * fddi7). It's important that the driver "pretend" to probe for
- * devices fddi1 and fddi2 and return success. Devices fddi3
- * through fddi7 will return failure since they weren't initialized.
- *
- * This algorithm seems to work for the time being. As other FDDI
- * drivers are written for Linux, a more generic approach (perhaps
- * similar to the Ethernet card approach) may need to be implemented.
- *
+ * This routine is called by the OS once at startup to scan for
+ * DEFXX cards.
+ *
* Return Codes:
* 0 - This device (fddi0, fddi1, etc) configured successfully
* -ENODEV - No devices present, or no Digital FDDI EISA or PCI device
@@ -446,7 +427,9 @@ static inline void dfx_port_read_long(
* the device structure.
*/
-int __init dfx_probe(struct net_device *dev)
+static struct net_device *bp_root;
+
+int __init dfx_probe(void)
{
int i; /* used in for loops */
int version_disp; /* was version info string already displayed? */
@@ -456,44 +439,26 @@ int __init dfx_probe(struct net_device *dev)
u16 command; /* PCI Configuration space Command register val */
u32 slot_id; /* EISA hardware (slot) ID read from adapter */
DFX_board_t *bp; /* board pointer */
+ struct net_device *dev;
DBG_printk("In dfx_probe...\n");
- /*
- * Verify whether we're going through dfx_probe() again
- *
- * If so, see if we're going through for a subsequent fddi device that
- * we've already initialized. If we are, return success (0). If not,
- * return failure (-ENODEV).
- */
-
version_disp = 0; /* default to version string not displayed */
- if (already_probed)
- {
- DBG_printk("Already entered dfx_probe\n");
- if (dev != NULL)
- if ((strncmp(dev->name, "fddi", 4) == 0) && (dev->base_addr != 0))
- {
- DBG_printk("In dfx_probe for fddi adapter (%s) we've already initialized it, so return success\n", dev->name);
- return(0);
- }
- return(-ENODEV);
- }
- already_probed = 1; /* set global flag */
+ already_probed = 1; /* set global flag */
/* Scan for FDDI EISA controllers */
for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */
- {
+ {
port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */
slot_id = inl(port); /* read EISA HW (slot) ID */
if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID)
- {
+ {
if (!version_disp) /* display version info if adapter is found */
- {
+ {
version_disp = 1; /* set display flag to TRUE so that */
printk(version); /* we only display this string ONCE */
- }
+ }
port = (i << 12); /* recalc base addr */
@@ -501,46 +466,47 @@ int __init dfx_probe(struct net_device *dev)
port_len = PI_ESIC_K_CSR_IO_LEN;
if (check_region(port, port_len) == 0)
- {
+ {
/* Allocate a new device structure for this adapter */
- dev = dfx_alloc_device(dev, port);
+ dev = dfx_alloc_device(port);
if (dev != NULL)
- {
+ {
/* Initialize board structure with bus-specific info */
-
bp = (DFX_board_t *) dev->priv;
+ bp->next = bp_root;
+ bp_root = dev;
bp->dev = dev;
bp->bus_type = DFX_BUS_TYPE_EISA;
if (dfx_driver_init(dev) == DFX_K_SUCCESS)
num_boards++; /* only increment global board count on success */
else
dev->base_addr = 0; /* clear port address field in device structure on failure */
- }
}
+ }
else
printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
- }
}
+ }
/* Scan for FDDI PCI controllers */
if (pci_present()) /* is PCI even present? */
while ((pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, pdev)))
- {
+ {
if (!version_disp) /* display version info if adapter is found */
- {
+ {
version_disp = 1; /* set display flag to TRUE so that */
printk(version); /* we only display this string ONCE */
- }
+ }
/* Verify that I/O enable bit is set (PCI slot is enabled) */
pci_read_config_word(pdev, PCI_COMMAND, &command);
if ((command & PCI_COMMAND_IO) == 0)
- printk("I/O enable bit not set! Verify that slot is enabled\n");
+ printk(KERN_ERR "defxx: I/O enable bit not set! Verify that slot is enabled\n");
else
- {
+ {
/* Turn off memory mapped space and enable mastering */
command |= PCI_COMMAND_MASTER;
@@ -556,28 +522,30 @@ int __init dfx_probe(struct net_device *dev)
port_len = PFI_K_CSR_IO_LEN;
if (check_region(port, port_len) == 0)
- {
+ {
/* Allocate a new device structure for this adapter */
- dev = dfx_alloc_device(dev, port);
+ dev = dfx_alloc_device(port);
if (dev != NULL)
- {
+ {
/* Initialize board structure with bus-specific info */
bp = (DFX_board_t *) dev->priv;
bp->dev = dev;
+ bp->next = bp_root;
+ bp_root = dev;
bp->bus_type = DFX_BUS_TYPE_PCI;
bp->pci_dev = pdev;
if (dfx_driver_init(dev) == DFX_K_SUCCESS)
num_boards++; /* only increment global board count on success */
else
dev->base_addr = 0; /* clear port address field in device structure on failure */
- }
}
- else
- printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
}
+ else
+ printk(KERN_ERR "defxx: I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
}
+ }
/*
* If we're at this point we're going through dfx_probe() for the first
@@ -589,7 +557,7 @@ int __init dfx_probe(struct net_device *dev)
return(0);
else
return(-ENODEV);
- }
+}
/*
@@ -639,32 +607,32 @@ int __init dfx_probe(struct net_device *dev)
* None
*/
-struct net_device __init *dfx_alloc_device( struct net_device *dev, u16 iobase)
+struct net_device __init *dfx_alloc_device(u16 iobase)
{
struct net_device *tmp_dev; /* pointer to a device structure */
+ int err;
DBG_printk("In dfx_alloc_device...\n");
/* Find next free fddi entry */
- for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next)
- if ((strncmp(tmp_dev->name, "fddi", 4) == 0) && (tmp_dev->base_addr == 0))
- break;
+ tmp_dev = dev_alloc("fddi%d", &err);
if (tmp_dev == NULL)
- {
- printk("Could not find free FDDI device structure for this adapter!\n");
+ {
+ printk(KERN_ERR "Could not find free FDDI device structure for this adapter!\n");
return(NULL);
- }
+ }
DBG_printk("Device entry free, device name = %s\n", tmp_dev->name);
/* Allocate space for private board structure */
tmp_dev->priv = (void *) kmalloc(sizeof(DFX_board_t), GFP_KERNEL);
if (tmp_dev->priv == NULL)
- {
- printk("Could not allocate memory for private board structure!\n");
+ {
+ printk(KERN_ERR "defxx: Could not allocate memory for private board structure!\n");
+ kfree(tmp_dev);
return(NULL);
- }
+ }
memset(tmp_dev->priv, 0, sizeof(DFX_board_t)); /* clear structure */
/* Initialize new device structure */
@@ -696,7 +664,7 @@ struct net_device __init *dfx_alloc_device( struct net_device *dev, u16 iobase)
fddi_setup(tmp_dev);
return(tmp_dev);
- }
+}
/*
@@ -1370,22 +1338,22 @@ int dfx_adap_init(
* if the open is successful.
*/
-int dfx_open(
- struct net_device *dev
- )
-
- {
+int dfx_open(struct net_device *dev)
+{
DFX_board_t *bp = (DFX_board_t *)dev->priv;
DBG_printk("In dfx_open...\n");
+
+ MOD_INC_USE_COUNT;
/* Register IRQ - support shared interrupts by passing device ptr */
if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev))
- {
- printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
- return(-EAGAIN);
- }
+ {
+ printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
+ MOD_DEC_USE_COUNT;
+ return -EAGAIN;
+ }
/*
* Set current address to factory MAC address
@@ -1416,16 +1384,17 @@ int dfx_open(
bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */
if (dfx_adap_init(bp) != DFX_K_SUCCESS)
- {
- printk("%s: Adapter open failed!\n", dev->name);
- return(-EAGAIN);
- }
+ {
+ printk(KERN_ERR "%s: Adapter open failed!\n", dev->name);
+ free_irq(dev->irq, dev);
+ MOD_DEC_USE_COUNT;
+ return -EAGAIN;
+ }
/* Set device structure info */
-
netif_start_queue(dev);
return(0);
- }
+}
/*
@@ -1460,11 +1429,8 @@ int dfx_open(
* routine.
*/
-int dfx_close(
- struct net_device *dev
- )
-
- {
+int dfx_close(struct net_device *dev)
+{
DFX_board_t *bp = (DFX_board_t *)dev->priv;
DBG_printk("In dfx_close...\n");
@@ -1514,8 +1480,10 @@ int dfx_close(
/* Deregister (free) IRQ */
free_irq(dev->irq, dev);
+
+ MOD_DEC_USE_COUNT;
return(0);
- }
+}
/*
@@ -3492,6 +3460,30 @@ void dfx_xmt_flush(
return;
}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ if(dfx_probe()<0)
+ return -ENODEV;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ while(bp_root!=NULL)
+ {
+ struct net_device *tmp=bp_root;
+ DFX_board_t *priv=tmp->priv;
+ bp_root=priv->next;
+ kfree(tmp->priv);
+ kfree(tmp);
+ }
+}
+
+#endif
+
/*
* Local variables:
diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
index d602b2589..223ad7d5d 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/defxx.h
@@ -1756,6 +1756,7 @@ typedef struct DFX_board_tag
/* Store device, bus-specific, and parameter information for this adapter */
struct net_device *dev; /* pointer to device structure */
+ struct net_device *next;
u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */
u16 base_addr; /* base I/O address (same as dev->base_addr) */
struct pci_dev * pci_dev;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 404d4a996..128128bcb 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1,9 +1,8 @@
+/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
/*
-
- drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux
-
+ NOTICE: For use with late 2.3 kernels only.
+ May not compile for kernels 2.3.43-47.
Written 1996-1999 by Donald Becker.
- Modified 2000 by Linux Kernel Team
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -11,8 +10,6 @@
This driver is for the Intel EtherExpress Pro100 (Speedo3) design.
It should work with all i82557/558/559 boards.
- To use as a module, use the compile-command at the end of the file.
-
The author may be reached as becker@CESDIS.usra.edu, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
@@ -23,14 +20,211 @@
There is a Majordomo mailing list based at
linux-eepro100@cesdis.gsfc.nasa.gov
+ The driver also contains updates by different kernel developers
+ (see incomplete list below).
+ This driver clone is maintained by Andrey V. Savochkin <saw@saw.sw.com.sg>.
+ Please use this email address and linux-kernel mailing list for bug reports.
-
- Version history:
- v1.09j+LK1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
+ Version history:
+ 1998 Apr - 2000 Feb Andrey V. Savochkin <saw@saw.sw.com.sg>
+ Serious fixes for multicast filter list setting, TX timeout routine;
+ RX ring refilling logic; other stuff
+ 2000 Feb Jeff Garzik <jgarzik@mandrakesoft.com>
Convert to new PCI driver interface
+ 2000 Mar 24 Dragan Stancevic <visitor@valinux.com>
+ Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
+ Dragan Stancevic <visitor@valinux.com> March 24th, 2000.
+*/
+
+static const char *version =
+"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
+"eepro100.c: $Revision: 1.29 $ 2000/03/30 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
+
+/* A few user-configurable values that apply to all boards.
+ First set is undocumented and spelled per Intel recommendations. */
+
+static int congenb = 0; /* Enable congestion control in the DP83840. */
+static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
+static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
+/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
+static int txdmacount = 128;
+static int rxdmacount = 0;
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
+ Lower values use more memory, but are faster. */
+static int rx_copybreak = 200;
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
+
+/* 'options' is used to pass a transceiver override or full-duplex flag
+ e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int debug = -1; /* The debug level */
+/* A few values that may be tweaked. */
+/* The ring sizes should be a power of two for efficiency. */
+#define TX_RING_SIZE 32
+#define RX_RING_SIZE 32
+/* How much slots multicast filter setup may take.
+ Do not descrease without changing set_rx_mode() implementaion. */
+#define TX_MULTICAST_SIZE 2
+#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2)
+/* Actual number of TX packets queued, must be
+ <= TX_RING_SIZE-TX_MULTICAST_RESERV. */
+#define TX_QUEUE_LIMIT (TX_RING_SIZE-TX_MULTICAST_RESERV)
+/* Hysteresis marking queue as no longer full. */
+#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4)
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (2*HZ)
+/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
+#define PKT_BUF_SZ 1536
+
+#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/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
+MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
+
+#define RUN_AT(x) (jiffies + (x))
+
+/* ACPI power states don't universally work (yet) */
+#ifndef CONFIG_EEPRO100_PM
+#undef pci_set_power_state
+#define pci_set_power_state null_set_power_state
+static inline int null_set_power_state(struct pci_dev *dev, int state)
+{
+ return 0;
+}
+#endif /* CONFIG_EEPRO100_PM */
+
+#ifndef pci_resource_start
+#define pci_resource_start(p, n) (p)->resource[n].start
+#define pci_resource_len(p, n) ((p)->resource[n].end - (p)->resource[n].start)
+#endif
+
+/* Because of changes in this area the driver may not compile for kernels
+ 2.3.43 - 2.3.47. --SAW */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+#define netif_wake_queue(dev) do { \
+ clear_bit(0, (void*)&dev->tbusy); \
+ mark_bh(NET_BH); \
+ } while(0)
+#define netif_start_queue(dev) clear_bit(0, (void*)&dev->tbusy)
+#define netif_stop_queue(dev) set_bit(0, (void*)&dev->tbusy)
+#define netif_running(dev) dev->start
+#define netdevice_start(dev) dev->start = 1
+#define netdevice_stop(dev) dev->start = 0
+#define netif_set_tx_timeout(dev, tf, tm)
+#define dev_kfree_skb_irq(x) dev_kfree_skb(x)
+#else
+#define netdevice_start(dev)
+#define netdevice_stop(dev)
+#define netif_set_tx_timeout(dev, tf, tm) \
+ do { \
+ (dev)->tx_timeout = (tf); \
+ (dev)->watchdog_timeo = (tm); \
+ } while(0)
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,47)
+#define netif_device_attach(dev) netif_start_queue(dev)
+#define netif_device_detach(dev) netif_stop_queue(dev)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+typedef u32 dma_addr_t;
+static void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t *dma_handle)
+{
+ void *ret;
+ ret = kmalloc(size, GFP_ATOMIC);
+ if (ret != NULL) {
+ *dma_handle = virt_to_bus(ret);
+ }
+ return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ kfree(vaddr);
+}
+
+#define PCI_DMA_FROMDEVICE 0
+#define PCI_DMA_TODEVICE 0
+
+extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+ size_t size, int direction)
+{
+ return virt_to_bus(ptr);
+}
+
+extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+ size_t size, int direction)
+{
+}
+
+extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+ dma_addr_t dma_handle,
+ size_t size, int direction)
+{
+}
+#endif
+
+/* The total I/O port extent of the board.
+ The registers beyond 0x18 only exist on the i82558. */
+#define SPEEDO3_TOTAL_SIZE 0x20
+
+int speedo_debug = 1;
+
+/*
Theory of Operation
I. Board Compatibility
@@ -136,24 +330,6 @@ allocate a new, minimally-sized skbuff. For large frames the copying cost
is non-trivial, and the larger copy might flush the cache of useful data, so
we pass up the skbuff the packet was received into.
-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 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 'sp->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 'sp->tx_full' flag is set, it clears both the
-tx_full and tbusy flags.
-
IV. Notes
Thanks to Steve Williams of Intel for arranging the non-disclosure agreement
@@ -162,120 +338,30 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
*/
+static int speedo_found1(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt, int acpi_idle_state);
-static const char *version =
-"eepro100.c:v1.09j+LK1.0 Feb 13, 2000 Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
-
-/* A few user-configurable values that apply to all boards.
- First set is undocumented and spelled per Intel recommendations. */
-
-static int congenb = 0; /* Enable congestion control in the DP83840. */
-static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
-static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
-/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
-static int txdmacount = 128;
-static int rxdmacount = 0;
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
- Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
-
-/* 'options' is used to pass a transceiver override or full-duplex flag
- e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int debug = -1; /* The debug level */
-
-/* A few values that may be tweaked. */
-/* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */
-#define RX_RING_SIZE 32
-/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
-#define TX_QUEUE_LIMIT 12
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
-/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-#define PKT_BUF_SZ 1536
-
-#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".
+#ifdef USE_IO
+#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
+#define SPEEDO_SIZE 32
+#else
+#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0
+#define SPEEDO_SIZE 0x1000
#endif
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(multicast_filter_limit, "i");
-
-#define EEPRO100_MODULE_NAME "eepro100"
-#define PFX EEPRO100_MODULE_NAME ": "
-
-#define RUN_AT(x) (jiffies + (x))
-
-/* ACPI power states don't universally work (yet) */
-#ifndef CONFIG_EEPRO100_PM
-#undef pci_set_power_state
-#define pci_set_power_state null_set_power_state
-static inline int null_set_power_state(struct pci_dev *dev, int state)
-{
- return 0;
-}
-#endif /* CONFIG_EEPRO100_PM */
-
-
-/* compile-time switch to en/disable slow PIO */
-#undef USE_IO
-
-
-int speedo_debug = 1;
-
-
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,
};
#ifndef USE_IO
+/* Currently alpha headers define in/out macros.
+ Undefine them. 2000/03/30 SAW */
+#undef inb
+#undef inw
+#undef inl
+#undef outb
+#undef outw
+#undef outl
#define inb readb
#define inw readw
#define inl readl
@@ -284,127 +370,106 @@ enum pci_flags_bit {
#define outl writel
#endif
-
/* How to wait for the command unit to accept a command.
Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done (long cmd_ioaddr)
+static inline void wait_for_cmd_done(long cmd_ioaddr)
{
- int wait = 100;
- do;
- while (inb (cmd_ioaddr) && --wait >= 0);
+ int wait = 1000;
+ do ;
+ while(inb(cmd_ioaddr) && --wait >= 0);
}
-
/* Offsets to the various registers.
All accesses need not be longword aligned. */
enum speedo_offsets {
SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */
- SCBPointer = 4, /* General purpose pointer. */
- SCBPort = 8, /* Misc. commands and operands. */
- SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
- SCBCtrlMDI = 16, /* MDI interface control. */
- SCBEarlyRx = 20, /* Early receive byte count. */
+ SCBPointer = 4, /* General purpose pointer. */
+ SCBPort = 8, /* Misc. commands and operands. */
+ SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
+ SCBCtrlMDI = 16, /* MDI interface control. */
+ SCBEarlyRx = 20, /* Early receive byte count. */
};
-
-
/* Commands that can be put in a command list entry. */
enum commands {
- CmdNOp = 0,
- CmdIASetup = 0x10000,
- CmdConfigure = 0x20000,
- CmdMulticastList = 0x30000,
- CmdTx = 0x40000,
- CmdTDR = 0x50000,
- CmdDump = 0x60000,
- CmdDiagnose = 0x70000,
+ CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000,
+ CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000,
+ CmdDump = 0x60000, CmdDiagnose = 0x70000,
CmdSuspend = 0x40000000, /* Suspend after completion. */
CmdIntr = 0x20000000, /* Interrupt after completion. */
CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */
};
-
-
-/* Do atomically if possible. */
-#if defined(__i386__) || defined(__alpha__) || defined(__ia64__)
-#define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status)
-#elif defined(__powerpc__)
-#define clear_suspend(cmd) clear_bit(6, &(cmd)->cmd_status)
+/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the
+ status bits. Previous driver versions used separate 16 bit fields for
+ commands and statuses. --SAW
+ FIXME: it may not work on non-IA32 architectures.
+ */
+#if defined(__LITTLE_ENDIAN)
+#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000
+#elif defined(__BIG_ENDIAN)
+#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040
#else
-#if 0
-# error You are probably in trouble: clear_suspend() MUST be atomic.
-#endif
-# define clear_suspend(cmd) (cmd)->cmd_status &= cpu_to_le32(~CmdSuspend)
+#error Unsupported byteorder
#endif
enum SCBCmdBits {
- SCBMaskCmdDone = 0x8000,
- SCBMaskRxDone = 0x4000,
- SCBMaskCmdIdle = 0x2000,
- SCBMaskRxSuspend = 0x1000,
- SCBMaskEarlyRx = 0x0800,
- SCBMaskFlowCtl = 0x0400,
- SCBTriggerIntr = 0x0200,
- SCBMaskAll = 0x0100,
- /* The rest are Rx and Tx commands. */
- CUStart = 0x0010,
- CUResume = 0x0020,
- CUStatsAddr = 0x0040,
- CUShowStats = 0x0050,
- CUCmdBase = 0x0060, /* CU Base address (set to zero) . */
- CUDumpStats = 0x0070, /* Dump then reset stats counters. */
- RxStart = 0x0001,
- RxResume = 0x0002,
- RxAbort = 0x0004,
- RxAddrLoad = 0x0006,
- RxResumeNoResources = 0x0007,
+ SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
+ SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
+ SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
+ /* The rest are Rx and Tx commands. */
+ CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
+ CUCmdBase=0x0060, /* CU Base address (set to zero) . */
+ CUDumpStats=0x0070, /* Dump then reset stats counters. */
+ RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
+ RxResumeNoResources=0x0007,
};
enum SCBPort_cmds {
- PortReset = 0,
- PortSelfTest = 1,
- PortPartialReset = 2,
- PortDump = 3,
+ PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
};
/* The Speedo3 Rx and Tx frame/buffer descriptors. */
-struct descriptor { /* A generic descriptor. */
- s32 cmd_status; /* All command and status fields. */
- u32 link; /* struct descriptor * */
+struct descriptor { /* A generic descriptor. */
+ s32 cmd_status; /* All command and status fields. */
+ u32 link; /* struct descriptor * */
unsigned char params[0];
};
/* The Speedo3 Rx and Tx buffer descriptors. */
-struct RxFD { /* Receive frame descriptor. */
+struct RxFD { /* Receive frame descriptor. */
s32 status;
- u32 link; /* struct RxFD * */
- u32 rx_buf_addr; /* void * */
+ u32 link; /* struct RxFD * */
+ u32 rx_buf_addr; /* void * */
u32 count;
};
/* Selected elements of the Tx/RxFD.status word. */
enum RxFD_bits {
- RxComplete = 0x8000,
- RxOK = 0x2000,
- RxErrCRC = 0x0800,
- RxErrAlign = 0x0400,
- RxErrTooBig = 0x0200,
- RxErrSymbol = 0x0010,
- RxEth2Type = 0x0020,
- RxNoMatch = 0x0004,
- RxNoIAMatch = 0x0002,
- TxUnderrun = 0x1000,
- StatusComplete = 0x8000,
+ RxComplete=0x8000, RxOK=0x2000,
+ RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
+ RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
+ TxUnderrun=0x1000, StatusComplete=0x8000,
};
-struct TxFD { /* Transmit frame descriptor set. */
+struct TxFD { /* Transmit frame descriptor set. */
s32 status;
- u32 link; /* void * */
- u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
- s32 count; /* # of TBD (=1), Tx start thresh., etc. */
+ u32 link; /* void * */
+ u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
+ s32 count; /* # of TBD (=1), Tx start thresh., etc. */
/* This constitutes two "TBD" entries -- we only use one. */
- u32 tx_buf_addr0; /* void *, frame to be transmitted. */
- s32 tx_buf_size0; /* Length of Tx frame. */
- u32 tx_buf_addr1; /* void *, frame to be transmitted. */
- s32 tx_buf_size1; /* Length of Tx frame. */
+#define TX_DESCR_BUF_OFFSET 16
+ u32 tx_buf_addr0; /* void *, frame to be transmitted. */
+ s32 tx_buf_size0; /* Length of Tx frame. */
+ u32 tx_buf_addr1; /* void *, frame to be transmitted. */
+ s32 tx_buf_size1; /* Length of Tx frame. */
+};
+
+/* Multicast filter setting block. --SAW */
+struct speedo_mc_block {
+ struct speedo_mc_block *next;
+ unsigned int tx;
+ dma_addr_t frame_dma;
+ unsigned int len;
+ struct descriptor frame __attribute__ ((__aligned__(16)));
};
/* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -428,46 +493,55 @@ struct speedo_stats {
u32 done_marker;
};
+enum Rx_ring_state_bits {
+ RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8,
+};
+
/* Do not change the position (alignment) of the first few elements!
- The later elements are grouped for cache locality. */
+ The later elements are grouped for cache locality.
+
+ Unfortunately, all the positions have been shifted since there.
+ A new re-alignment is required. 2000/03/06 SAW */
struct speedo_private {
- struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */
+ struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */
struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */
/* The addresses of a Tx/Rx-in-place packets/buffers. */
struct sk_buff *tx_skbuff[TX_RING_SIZE];
struct sk_buff *rx_skbuff[RX_RING_SIZE];
- dma_addr_t rx_ring_dma[RX_RING_SIZE];
+ /* Mapped addresses of the rings. */
dma_addr_t tx_ring_dma;
- struct descriptor *last_cmd; /* Last command sent. */
- unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */
- spinlock_t lock; /* Group with Tx control cache line. */
- u32 tx_threshold; /* The value for txdesc.count. */
- struct RxFD *last_rxf; /* Last command sent. */
- unsigned int cur_rx, dirty_rx; /* The next free ring entry */
- long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
+#define TX_RING_ELEM_DMA(sp, n) ((sp)->tx_ring_dma + (n)*sizeof(struct TxFD))
+ dma_addr_t rx_ring_dma[RX_RING_SIZE];
+ struct descriptor *last_cmd; /* Last command sent. */
+ unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */
+ spinlock_t lock; /* Group with Tx control cache line. */
+ u32 tx_threshold; /* The value for txdesc.count. */
+ struct RxFD *last_rxf; /* Last filled RX buffer. */
+ unsigned int cur_rx, dirty_rx; /* The next free ring entry */
+ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
const char *product_name;
struct enet_statistics stats;
struct speedo_stats *lstats;
+ dma_addr_t lstats_dma;
int chip_id;
- unsigned char acpi_pwr;
struct pci_dev *pdev;
- struct timer_list timer; /* Media selection timer. */
- int mc_setup_frm_len; /* The length of an allocated.. */
- struct descriptor *mc_setup_frm;/* ..multicast setup frame. */
- int mc_setup_busy; /* Avoid double-use of setup frame. */
- dma_addr_t mc_setup_dma;
- char rx_mode; /* Current PROMISC/ALLMULTI setting. */
- unsigned int tx_full:1; /* The Tx queue is full. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
- unsigned int rx_bug:1; /* Work around receiver hang errata. */
- unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */
- unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */
- unsigned char default_port:8; /* Last dev->if_port value. */
- unsigned short phy[2]; /* PHY media interfaces available. */
- unsigned short advertising; /* Current PHY advertised caps. */
- unsigned short partner; /* Link partner caps. */
+ struct timer_list timer; /* Media selection timer. */
+ struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
+ struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
+ int in_interrupt; /* Word-aligned dev->interrupt */
+ unsigned char acpi_pwr;
+ char rx_mode; /* Current PROMISC/ALLMULTI setting. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
+ unsigned int rx_bug:1; /* Work around receiver hang errata. */
+ unsigned char default_port:8; /* Last dev->if_port value. */
+ unsigned char rx_ring_state; /* RX ring status flags. */
+ unsigned short phy[2]; /* PHY media interfaces available. */
+ unsigned short advertising; /* Current PHY advertised caps. */
+ unsigned short partner; /* Link partner caps. */
};
+
/* The parameters for a CmdConfigure operation.
There are so many options that it would be difficult to document each bit.
We mostly use the default or recommended settings. */
@@ -479,7 +553,7 @@ const char i82557_config_cmd[22] = {
const char i82558_config_cmd[22] = {
22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
0, 0x2E, 0, 0x60, 0x08, 0x88,
- 0x68, 0, 0x40, 0xf2, 0xBD, /* 0xBD->0xFD=Force full-duplex */
+ 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */
0x31, 0x05, };
/* PHY media interface chips. */
@@ -493,6 +567,12 @@ enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
#define EE_READ_CMD (6)
+static int eepro100_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void eepro100_remove_one (struct pci_dev *pdev);
+static void eepro100_suspend (struct pci_dev *pdev);
+static void eepro100_resume (struct pci_dev *pdev);
+
static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
static int mdio_read(long ioaddr, int phy_id, int location);
static int mdio_write(long ioaddr, int phy_id, int location, int value);
@@ -502,12 +582,15 @@ static void speedo_timer(unsigned long data);
static void speedo_init_rx_ring(struct net_device *dev);
static void speedo_tx_timeout(struct net_device *dev);
static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void speedo_refill_rx_buffers(struct net_device *dev, int force);
static int speedo_rx(struct net_device *dev);
+static void speedo_tx_buffer_gc(struct net_device *dev);
static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int speedo_close(struct net_device *dev);
static struct enet_statistics *speedo_get_stats(struct net_device *dev);
static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
+static void speedo_show_state(struct net_device *dev);
@@ -518,75 +601,104 @@ static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100,
0x2000, 0x2100, 0x0400, 0x3100};
#endif
-
-
static int __devinit eepro100_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
- struct net_device *dev;
- struct speedo_private *sp;
- unsigned char *tx_ring;
- dma_addr_t tx_ring_dma;
- const char *product;
- int i, option;
- u16 eeprom[0x100];
- int acpi_idle_state = 0, pm, irq;
unsigned long ioaddr;
- static int card_idx = -1;
+ int irq;
+ int acpi_idle_state = 0, pm;
+ static int cards_found = 0;
static int did_version = 0; /* Already printed version info. */
-
if (speedo_debug > 0 && did_version++ == 0)
printk(version);
-#ifdef USE_IO
- ioaddr = pci_resource_start (pdev, 0);
-#else
- ioaddr = pci_resource_start (pdev, 1);
-#endif
- irq = pdev->irq;
-
- card_idx++;
-
- if (!request_region (pci_resource_start (pdev, 1),
- pci_resource_len (pdev, 1),
- EEPRO100_MODULE_NAME)) {
- printk (KERN_ERR PFX "cannot reserve I/O ports\n");
+ if (!request_region(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1), "eepro100")) {
+ printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
goto err_out_none;
}
- if (!request_mem_region (pci_resource_start (pdev, 0),
- pci_resource_len (pdev, 0),
- EEPRO100_MODULE_NAME)) {
- printk (KERN_ERR PFX "cannot reserve MMIO region\n");
+ if (!request_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0), "eepro100")) {
+ printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
goto err_out_free_pio_region;
}
-
-#ifndef USE_IO
- ioaddr = (unsigned long) ioremap (pci_resource_start (pdev, 0),
- pci_resource_len (pdev, 0));
+
+ irq = pdev->irq;
+#ifdef USE_IO
+ ioaddr = pci_resource_start(pdev, 1);
+ if (speedo_debug > 2)
+ printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
+ ioaddr, irq);
+#else
+ ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
if (!ioaddr) {
- printk (KERN_ERR PFX "cannot remap MMIO region %lx @ %lx\n",
- pci_resource_len (pdev, 0),
- pci_resource_start (pdev, 0));
+ printk (KERN_ERR "eepro100: cannot remap MMIO region %lx @ %lx\n",
+ pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
goto err_out_free_mmio_region;
}
+ if (speedo_debug > 2)
+ printk("Found Intel i82557 PCI Speedo, MMIO at %#lx, IRQ %d.\n",
+ pci_resource_start(pdev, 0), irq);
#endif
- tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
- + sizeof(struct speedo_stats), &tx_ring_dma);
- if (!tx_ring) {
- printk(KERN_ERR PFX "Could not allocate DMA memory.\n");
- goto err_out_iounmap;
+ /* save power state b4 pci_enable_device overwrites it */
+ pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm) {
+ u16 pwr_command;
+ pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
+ acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
}
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "eepro100: Could not enable PCI device\n");
+ goto err_out_free_mmio_region;
+ }
+
+ pci_set_master(pdev);
+
+ if (speedo_found1(pdev, ioaddr, irq, 0, cards_found, acpi_idle_state) == 0)
+ cards_found++;
+ else
+ goto err_out_iounmap;
+
+ return 0;
+
+err_out_iounmap: ;
+#ifndef USE_IO
+ iounmap ((void *)ioaddr);
+#endif
+err_out_free_mmio_region:
+ release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+err_out_free_pio_region:
+ release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+err_out_none:
+ return -ENODEV;
+}
+
+static int speedo_found1(struct pci_dev *pdev,
+ long ioaddr, int irq, int chip_idx, int card_idx, int acpi_idle_state)
+{
+ struct net_device *dev;
+ struct speedo_private *sp;
+ const char *product;
+ int i, option;
+ u16 eeprom[0x100];
+ int size;
+ void *tx_ring_space;
+ dma_addr_t tx_ring_dma;
+
+ size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats);
+ tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma);
+ if (tx_ring_space == NULL)
+ return -1;
+
dev = init_etherdev(NULL, sizeof(struct speedo_private));
if (dev == NULL) {
- printk(KERN_ERR PFX "Could not allocate ethernet device.\n");
- goto err_out_free_tx_ring;
- }
- if (dev->priv == NULL) {
- printk(KERN_ERR PFX "Could not allocate ethernet device private info.\n");
- goto err_out_free_netdev;
+ printk(KERN_ERR "eepro100: Could not allocate ethernet device.\n");
+ pci_free_consistent(pdev, size, tx_ring_space, tx_ring_dma);
+ return -1;
}
if (dev->mem_start > 0)
@@ -596,21 +708,6 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
else
option = 0;
- /* save power state b4 pci_enable_device overwrites it */
- pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pm) {
- u16 pwr_command;
- pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
- acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
- }
-
- if (pci_enable_device (pdev)) {
- printk(KERN_ERR PFX "Could not enable PCI device\n");
- goto err_out_free_netdev;
- }
-
- pci_set_master (pdev);
-
/* Read the station address EEPROM before doing the reset.
Nominally his should even be done before accepting the device, but
then we wouldn't have a device name with which to report the error.
@@ -655,22 +752,26 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
if (eeprom[3] & 0x0100)
product = "OEM i82557/i82558 10/100 Ethernet";
else
- product = "Intel PCI EtherExpress Pro100";
+ product = pdev->name;
- printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
+ printk(KERN_INFO "%s: %s, ", dev->name, product);
for (i = 0; i < 5; i++)
printk("%2.2X:", dev->dev_addr[i]);
- printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk("%2.2X, ", dev->dev_addr[i]);
+#ifdef USE_IO
+ printk("I/O at %#3lx, ", ioaddr);
+#endif
+ printk("IRQ %d.\n", irq);
-#if 1
+#if 1 || defined(kernel_bloat)
/* OK, this is pure kernel bloat. I don't like it when other drivers
waste non-pageable kernel space to emit similar messages, but I need
them for bug reports. */
{
const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"};
/* The self-test results must be paragraph aligned. */
- volatile s32 *self_test_results = (volatile s32 *)tx_ring;
+ volatile s32 *self_test_results;
int boguscnt = 16000; /* Timeout for set-test. */
if (eeprom[3] & 0x03)
printk(KERN_INFO " Receiver lock-up bug exists -- enabling"
@@ -704,7 +805,8 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
}
- /* Perform a system self-test. Use the tx_ring consistent DMA mapping for it. */
+ /* Perform a system self-test. */
+ self_test_results = (s32*) ((((long) tx_ring_space) + 15) & ~0xf);
self_test_results[0] = 0;
self_test_results[1] = -1;
outl(tx_ring_dma | PortSelfTest, ioaddr + SCBPort);
@@ -734,7 +836,7 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
outl(PortReset, ioaddr + SCBPort);
/* Return the chip to its original power state. */
- pci_set_power_state (pdev, acpi_idle_state);
+ pci_set_power_state(pdev, acpi_idle_state);
pdev->driver_data = dev;
@@ -742,20 +844,18 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
dev->irq = irq;
sp = dev->priv;
-
sp->pdev = pdev;
sp->acpi_pwr = acpi_idle_state;
- sp->tx_ring = (struct TxFD *)tx_ring;
+ sp->tx_ring = tx_ring_space;
sp->tx_ring_dma = tx_ring_dma;
sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
-
- sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
+ sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
+ sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
if (card_idx >= 0) {
if (full_duplex[card_idx] >= 0)
sp->full_duplex = full_duplex[card_idx];
}
-
sp->default_port = option >= 0 ? (option & 0x0f) : 0;
sp->phy[0] = eeprom[6];
@@ -768,37 +868,15 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
/* The Speedo-specific entries in the device structure. */
dev->open = &speedo_open;
dev->hard_start_xmit = &speedo_start_xmit;
- dev->tx_timeout = &speedo_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
+ netif_set_tx_timeout(dev, &speedo_tx_timeout, TX_TIMEOUT);
dev->stop = &speedo_close;
dev->get_stats = &speedo_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &speedo_ioctl;
return 0;
-
-err_out_free_netdev:
- unregister_netdevice (dev);
- kfree (dev);
-err_out_free_tx_ring:
- pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
- + sizeof(struct speedo_stats),
- tx_ring, tx_ring_dma);
-err_out_iounmap:
-#ifndef USE_IO
- iounmap ((void *)ioaddr);
-err_out_free_mmio_region:
-#endif
- release_mem_region (pci_resource_start (pdev, 0),
- pci_resource_len (pdev, 0));
-err_out_free_pio_region:
- release_region (pci_resource_start (pdev, 1),
- pci_resource_len (pdev, 1));
-err_out_none:
- return -ENODEV;
}
-
-
+
/* Serial EEPROM section.
A "bit" grungy, but we work our way through bit-by-bit :->. */
/* EEPROM_Ctrl bits. */
@@ -887,6 +965,7 @@ speedo_open(struct net_device *dev)
sp->last_cmd = 0;
sp->tx_full = 0;
spin_lock_init(&sp->lock);
+ sp->in_interrupt = 0;
/* .. we can safely take handler calls during init. */
if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
@@ -896,9 +975,8 @@ speedo_open(struct net_device *dev)
dev->if_port = sp->default_port;
-#if 0
- /* With some transceivers we must retrigger negotiation to reset
- power-up errors. */
+#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us
+ /* Retrigger negotiation to reset previous errors. */
if ((sp->phy[0] & 0x8000) == 0) {
int phy_addr = sp->phy[0] & 0x1f ;
/* Use 0x3300 for restarting NWay, other values to force xcvr:
@@ -918,16 +996,17 @@ speedo_open(struct net_device *dev)
speedo_init_rx_ring(dev);
/* Fire up the hardware. */
+ outw(SCBMaskAll, ioaddr + SCBCmd);
speedo_resume(dev);
+ netdevice_start(dev);
netif_start_queue(dev);
/* Setup the chip and configure the multicast list. */
- sp->mc_setup_frm = NULL;
- sp->mc_setup_frm_len = 0;
- sp->mc_setup_busy = 0;
- sp->rx_mode = -1; /* Invalid -> always reset the mode. */
+ sp->mc_setup_head = NULL;
+ sp->mc_setup_tail = NULL;
sp->flow_ctrl = sp->partner = 0;
+ sp->rx_mode = -1; /* Invalid -> always reset the mode. */
set_rx_mode(dev);
if ((sp->phy[0] & 0x8000) == 0)
sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
@@ -951,6 +1030,7 @@ speedo_open(struct net_device *dev)
/* No need to wait for the command unit to accept here. */
if ((sp->phy[0] & 0x8000) == 0)
mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
+
return 0;
}
@@ -960,8 +1040,6 @@ static void speedo_resume(struct net_device *dev)
struct speedo_private *sp = (struct speedo_private *)dev->priv;
long ioaddr = dev->base_addr;
- outw(SCBMaskAll, ioaddr + SCBCmd);
-
/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
sp->tx_threshold = 0x01208000;
@@ -974,42 +1052,45 @@ static void speedo_resume(struct net_device *dev)
wait_for_cmd_done(ioaddr + SCBCmd);
/* Load the statistics block and rx ring addresses. */
- outl(sp->tx_ring_dma + sizeof(struct TxFD) * TX_RING_SIZE, ioaddr + SCBPointer);
+ outl(sp->lstats_dma, ioaddr + SCBPointer);
outb(CUStatsAddr, ioaddr + SCBCmd);
sp->lstats->done_marker = 0;
wait_for_cmd_done(ioaddr + SCBCmd);
- outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
- ioaddr + SCBPointer);
- outb(RxStart, ioaddr + SCBCmd);
- wait_for_cmd_done(ioaddr + SCBCmd);
+ if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
+ dev->name);
+ } else {
+ outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
+ ioaddr + SCBPointer);
+ outb(RxStart, ioaddr + SCBCmd);
+ wait_for_cmd_done(ioaddr + SCBCmd);
+ }
outb(CUDumpStats, ioaddr + SCBCmd);
/* Fill the first command with our physical address. */
{
- int entry = sp->cur_tx++ % TX_RING_SIZE;
- struct descriptor *cur_cmd = (struct descriptor *)&sp->tx_ring[entry];
+ struct descriptor *ias_cmd;
+ ias_cmd =
+ (struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE];
/* Avoid a bug(?!) here by marking the command already completed. */
- cur_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
- cur_cmd->link =
- cpu_to_le32(sp->tx_ring_dma + (sp->cur_tx % TX_RING_SIZE)
- * sizeof(struct TxFD));
- memcpy(cur_cmd->params, dev->dev_addr, 6);
- if (sp->last_cmd)
- clear_suspend(sp->last_cmd);
- sp->last_cmd = cur_cmd;
+ ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
+ ias_cmd->link =
+ cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
+ memcpy(ias_cmd->params, dev->dev_addr, 6);
+ sp->last_cmd = ias_cmd;
}
/* Start the chip's Tx process and unmask interrupts. */
wait_for_cmd_done(ioaddr + SCBCmd);
- outl(sp->tx_ring_dma
- + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD),
+ outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE)),
ioaddr + SCBPointer);
- outw(CUStart, ioaddr + SCBCmd);
-
- netif_start_queue (dev);
+ /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
+ remain masked --Dragan */
+ outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
}
/* Media monitoring and control. */
@@ -1025,6 +1106,8 @@ static void speedo_timer(unsigned long data)
int partner = mdio_read(ioaddr, phy_num, 5);
if (partner != sp->partner) {
int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
sp->partner = partner;
if (flow_ctrl != sp->flow_ctrl) {
sp->flow_ctrl = flow_ctrl;
@@ -1034,12 +1117,11 @@ static void speedo_timer(unsigned long data)
mdio_read(ioaddr, phy_num, 1);
/* If link beat has returned... */
if (mdio_read(ioaddr, phy_num, 1) & 0x0004)
- dev->flags |= IFF_RUNNING;
+ dev->flags |= IFF_RUNNING;
else
dev->flags &= ~IFF_RUNNING;
}
}
-
if (speedo_debug > 3) {
printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
dev->name, inw(ioaddr + SCBStatus));
@@ -1049,6 +1131,9 @@ static void speedo_timer(unsigned long data)
/* We haven't received a packet in a Long Time. We might have been
bitten by the receiver hang bug. This can be cleared by sending
a set multicast list command. */
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG "%s: Sending a multicast list set command"
+ " from a timer routine.\n", dev->name);
set_rx_mode(dev);
}
/* We must continue to monitor the media. */
@@ -1066,25 +1151,31 @@ static void speedo_show_state(struct net_device *dev)
/* Print a few items for debugging. */
if (speedo_debug > 0) {
int i;
- printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %d / %d:\n", dev->name,
+ printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n", dev->name,
sp->cur_tx, sp->dirty_tx);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(KERN_DEBUG "%s: %c%c%d %8.8x.\n", dev->name,
+ printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name,
i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
i, sp->tx_ring[i].status);
}
- printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n",
- dev->name, sp->cur_rx);
+ printk(KERN_DEBUG "%s: Printing Rx ring"
+ " (next to receive into %u, dirty index %u).\n",
+ dev->name, sp->cur_rx, sp->dirty_rx);
for (i = 0; i < RX_RING_SIZE; i++)
- printk(KERN_DEBUG " Rx ring entry %d %8.8x.\n",
- i, (int)sp->rx_ringp[i]->status);
+ printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
+ sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
+ i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
+ i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
+ i, (sp->rx_ringp[i] != NULL) ?
+ (unsigned)sp->rx_ringp[i]->status : 0);
for (i = 0; i < 16; i++) {
+ /* FIXME: what does it mean? --SAW */
if (i == 6) i = 21;
- printk(KERN_DEBUG " PHY index %d register %d is %4.4x.\n",
- phy_num, i, mdio_read(ioaddr, phy_num, i));
+ printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n",
+ dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
}
}
@@ -1126,55 +1217,124 @@ speedo_init_rx_ring(struct net_device *dev)
sp->last_rxf = last_rxf;
}
+static void speedo_purge_tx(struct net_device *dev)
+{
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+ int entry;
+
+ while ((int)(sp->cur_tx - sp->dirty_tx) > 0) {
+ entry = sp->dirty_tx % TX_RING_SIZE;
+ if (sp->tx_skbuff[entry]) {
+ sp->stats.tx_errors++;
+ pci_unmap_single(sp->pdev,
+ le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
+ sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(sp->tx_skbuff[entry]);
+ sp->tx_skbuff[entry] = 0;
+ }
+ sp->dirty_tx++;
+ }
+ while (sp->mc_setup_head != NULL) {
+ struct speedo_mc_block *t;
+ if (speedo_debug > 1)
+ printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
+ pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
+ sp->mc_setup_head->len, PCI_DMA_TODEVICE);
+ t = sp->mc_setup_head->next;
+ kfree(sp->mc_setup_head);
+ sp->mc_setup_head = t;
+ }
+ sp->mc_setup_tail = NULL;
+ sp->tx_full = 0;
+ netif_wake_queue(dev);
+}
+
static void speedo_tx_timeout(struct net_device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
long ioaddr = dev->base_addr;
int status = inw(ioaddr + SCBStatus);
-
- /* Trigger a stats dump to give time before the reset. */
- speedo_get_stats(dev);
+ unsigned long flags;
printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
" %4.4x at %d/%d command %8.8x.\n",
dev->name, status, inw(ioaddr + SCBCmd),
sp->dirty_tx, sp->cur_tx,
sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
+
+ /* Trigger a stats dump to give time before the reset. */
+ speedo_get_stats(dev);
+
speedo_show_state(dev);
+#if 0
if ((status & 0x00C0) != 0x0080
&& (status & 0x003C) == 0x0010) {
/* Only the command unit has stopped. */
printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
dev->name);
- outl(sp->tx_ring_dma
- + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD),
+ outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE])),
ioaddr + SCBPointer);
outw(CUStart, ioaddr + SCBCmd);
} else {
+#else
+ {
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+ start_bh_atomic();
+ /* Ensure that timer routine doesn't run! */
+ del_timer(&sp->timer);
+ end_bh_atomic();
+#else /* LINUX_VERSION_CODE */
+#ifdef __SMP__
+ del_timer_sync(&sp->timer);
+#else /* SMP */
+ del_timer(&sp->timer);
+#endif /* SMP */
+#endif /* LINUX_VERSION_CODE */
/* Reset the Tx and Rx units. */
outl(PortReset, ioaddr + SCBPort);
- if (speedo_debug > 0)
- speedo_show_state(dev);
+ /* We may get spurious interrupts here. But I don't think that they
+ may do much harm. 1999/12/09 SAW */
udelay(10);
+ /* Disable interrupts. */
+ outw(SCBMaskAll, ioaddr + SCBCmd);
+ synchronize_irq();
+ speedo_tx_buffer_gc(dev);
+ /* Free as much as possible.
+ It helps to recover from a hang because of out-of-memory.
+ It also simplifies speedo_resume() in case TX ring is full or
+ close-to-be full. */
+ speedo_purge_tx(dev);
+ speedo_refill_rx_buffers(dev, 1);
+ spin_lock_irqsave(&sp->lock, flags);
speedo_resume(dev);
+ sp->rx_mode = -1;
+ dev->trans_start = jiffies;
+ spin_unlock_irqrestore(&sp->lock, flags);
+ set_rx_mode(dev); /* it takes the spinlock itself --SAW */
+ sp->timer.expires = RUN_AT(2*HZ);
+ add_timer(&sp->timer);
}
/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
if ((sp->phy[0] & 0x8000) == 0) {
int phy_addr = sp->phy[0] & 0x1f;
+ int advertising = mdio_read(ioaddr, phy_addr, 4);
+ int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
mdio_write(ioaddr, phy_addr, 0, 0x0400);
mdio_write(ioaddr, phy_addr, 1, 0x0000);
mdio_write(ioaddr, phy_addr, 4, 0x0000);
mdio_write(ioaddr, phy_addr, 0, 0x8000);
#ifdef honor_default_port
mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#else
+ mdio_read(ioaddr, phy_addr, 0);
+ mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
+ mdio_write(ioaddr, phy_addr, 4, advertising);
#endif
}
- sp->stats.tx_errors++;
- dev->trans_start = jiffies;
- netif_start_queue (dev);
+ return;
}
-
static int
speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -1182,58 +1342,141 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
long ioaddr = dev->base_addr;
int entry;
- /* Caution: the write order is important here, set the base address
- with the "ownership" bits last. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
+ if (test_bit(0, (void*)&dev->tbusy) != 0) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < TX_TIMEOUT - 2)
+ return 1;
+ if (tickssofar < TX_TIMEOUT) {
+ /* Reap sent packets from the full Tx queue. */
+ unsigned long flags;
+ spin_lock_irqsave(&sp->lock, flags);
+ wait_for_cmd_done(ioaddr + SCBCmd);
+ outw(SCBTriggerIntr, ioaddr + SCBCmd);
+ spin_unlock_irqrestore(&sp->lock, flags);
+ return 1;
+ }
+ speedo_tx_timeout(dev);
+ return 1;
+ }
+#endif
{ /* Prevent interrupts from changing the Tx ring from underneath us. */
unsigned long flags;
spin_lock_irqsave(&sp->lock, flags);
+
+ /* Check if there are enough space. */
+ if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+ printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name);
+ netif_stop_queue(dev);
+ sp->tx_full = 1;
+ spin_unlock_irqrestore(&sp->lock, flags);
+ return 1;
+ }
+
/* Calculate the Tx descriptor entry. */
entry = sp->cur_tx++ % TX_RING_SIZE;
sp->tx_skbuff[entry] = skb;
- /* Todo: be a little more clever about setting the interrupt bit. */
sp->tx_ring[entry].status =
cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex);
+ if (!(entry & ((TX_RING_SIZE>>2)-1)))
+ sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr);
sp->tx_ring[entry].link =
- cpu_to_le32(sp->tx_ring_dma
- + (sp->cur_tx % TX_RING_SIZE)
- * sizeof(struct TxFD));
+ cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
sp->tx_ring[entry].tx_desc_addr =
- cpu_to_le32(sp->tx_ring_dma
- + ((long)&sp->tx_ring[entry].tx_buf_addr0
- - (long)sp->tx_ring));
+ cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE) +
+ TX_DESCR_BUF_OFFSET);
/* The data region is always in one buffer descriptor. */
sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
sp->tx_ring[entry].tx_buf_addr0 =
cpu_to_le32(pci_map_single(sp->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE));
sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
- /* Todo: perhaps leave the interrupt bit set if the Tx queue is more
- than half full. Argument against: we should be receiving packets
- and scavenging the queue. Argument for: if so, it shouldn't
- matter. */
/* Trigger the command unit resume. */
- {
- struct descriptor *last_cmd = sp->last_cmd;
- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
- last_cmd->cmd_status &= cpu_to_le32(~(CmdSuspend | CmdIntr));
- }
- if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) {
+ wait_for_cmd_done(ioaddr + SCBCmd);
+ clear_suspend(sp->last_cmd);
+ /* We want the time window between clearing suspend flag on the previous
+ command and resuming CU to be as small as possible.
+ Interrupts in between are very undesired. --SAW */
+ outb(CUResume, ioaddr + SCBCmd);
+ sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+
+ /* Leave room for set_rx_mode(). If there is no more space than reserved
+ for multicast filter mark the ring as full. */
+ if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+ netif_stop_queue(dev);
sp->tx_full = 1;
- netif_stop_queue (dev);
}
+
spin_unlock_irqrestore(&sp->lock, flags);
}
- wait_for_cmd_done(ioaddr + SCBCmd);
- outw(CUResume, ioaddr + SCBCmd);
dev->trans_start = jiffies;
-
+
return 0;
}
+static void speedo_tx_buffer_gc(struct net_device *dev)
+{
+ unsigned int dirty_tx;
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+
+ dirty_tx = sp->dirty_tx;
+ while ((int)(sp->cur_tx - dirty_tx) > 0) {
+ int entry = dirty_tx % TX_RING_SIZE;
+ int status = le32_to_cpu(sp->tx_ring[entry].status);
+
+ if (speedo_debug > 5)
+ printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
+ entry, status);
+ if ((status & StatusComplete) == 0)
+ break; /* It still hasn't been processed. */
+ if (status & TxUnderrun)
+ if (sp->tx_threshold < 0x01e08000) {
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n",
+ dev->name);
+ sp->tx_threshold += 0x00040000;
+ }
+ /* Free the original skb. */
+ if (sp->tx_skbuff[entry]) {
+ sp->stats.tx_packets++; /* Count only user packets. */
+ sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
+ pci_unmap_single(sp->pdev,
+ le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
+ sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(sp->tx_skbuff[entry]);
+ sp->tx_skbuff[entry] = 0;
+ }
+ dirty_tx++;
+ }
+
+ if (speedo_debug && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
+ printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
+ " full=%d.\n",
+ dirty_tx, sp->cur_tx, sp->tx_full);
+ dirty_tx += TX_RING_SIZE;
+ }
+
+ while (sp->mc_setup_head != NULL
+ && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) {
+ struct speedo_mc_block *t;
+ if (speedo_debug > 1)
+ printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
+ pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
+ sp->mc_setup_head->len, PCI_DMA_TODEVICE);
+ t = sp->mc_setup_head->next;
+ kfree(sp->mc_setup_head);
+ sp->mc_setup_head = t;
+ }
+ if (sp->mc_setup_head == NULL)
+ sp->mc_setup_tail = NULL;
+
+ sp->dirty_tx = dirty_tx;
+}
+
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -1253,11 +1496,21 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
ioaddr = dev->base_addr;
sp = (struct speedo_private *)dev->priv;
- spin_lock (&sp->lock);
+#ifndef final_version
+ /* A lock to prevent simultaneous entry on SMP machines. */
+ if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+ dev->name);
+ sp->in_interrupt = 0; /* Avoid halting machine. */
+ return;
+ }
+#endif
do {
status = inw(ioaddr + SCBStatus);
/* Acknowledge all of the current interrupt sources ASAP. */
+ /* Will change from 0xfc00 to 0xff00 when we start handling
+ FCP and ER interrupts --Dragan */
outw(status & 0xfc00, ioaddr + SCBStatus);
if (speedo_debug > 4)
@@ -1267,90 +1520,194 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
if ((status & 0xfc00) == 0)
break;
- if (status & 0x4000) /* Packet received. */
+ /* Always check if all rx buffers are allocated. --SAW */
+ speedo_refill_rx_buffers(dev, 0);
+
+ if ((status & 0x5000) || /* Packet received, or Rx error. */
+ (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed)
+ /* Need to gather the postponed packet. */
speedo_rx(dev);
if (status & 0x1000) {
- if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
- outw(RxResumeNoResources, ioaddr + SCBCmd);
- else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
- /* No idea of what went wrong. Restart the receiver. */
- outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
- ioaddr + SCBPointer);
- outw(RxStart, ioaddr + SCBCmd);
+ spin_lock(&sp->lock);
+ if ((status & 0x003c) == 0x0028) { /* No more Rx buffers. */
+ struct RxFD *rxf;
+ printk(KERN_WARNING "%s: card reports no RX buffers.\n",
+ dev->name);
+ rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
+ if (rxf == NULL) {
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG
+ "%s: NULL cur_rx in speedo_interrupt().\n",
+ dev->name);
+ sp->rx_ring_state |= RrNoMem|RrNoResources;
+ } else if (rxf == sp->last_rxf) {
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG
+ "%s: cur_rx is last in speedo_interrupt().\n",
+ dev->name);
+ sp->rx_ring_state |= RrNoMem|RrNoResources;
+ } else
+ outb(RxResumeNoResources, ioaddr + SCBCmd);
+ } else if ((status & 0x003c) == 0x0008) { /* No resources. */
+ struct RxFD *rxf;
+ printk(KERN_WARNING "%s: card reports no resources.\n",
+ dev->name);
+ rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
+ if (rxf == NULL) {
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG
+ "%s: NULL cur_rx in speedo_interrupt().\n",
+ dev->name);
+ sp->rx_ring_state |= RrNoMem|RrNoResources;
+ } else if (rxf == sp->last_rxf) {
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG
+ "%s: cur_rx is last in speedo_interrupt().\n",
+ dev->name);
+ sp->rx_ring_state |= RrNoMem|RrNoResources;
+ } else {
+ /* Restart the receiver. */
+ outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
+ ioaddr + SCBPointer);
+ outb(RxStart, ioaddr + SCBCmd);
+ }
}
sp->stats.rx_errors++;
+ spin_unlock(&sp->lock);
+ }
+
+ if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) {
+ printk(KERN_WARNING
+ "%s: restart the receiver after a possible hang.\n",
+ dev->name);
+ spin_lock(&sp->lock);
+ /* Restart the receiver.
+ I'm not sure if it's always right to restart the receiver
+ here but I don't know another way to prevent receiver hangs.
+ 1999/12/25 SAW */
+ outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
+ ioaddr + SCBPointer);
+ outb(RxStart, ioaddr + SCBCmd);
+ sp->rx_ring_state &= ~RrNoResources;
+ spin_unlock(&sp->lock);
}
/* User interrupt, Command/Tx unit interrupt or CU not active. */
if (status & 0xA400) {
- unsigned int dirty_tx;
-
- dirty_tx = sp->dirty_tx;
- while (sp->cur_tx - dirty_tx > 0) {
- int entry = dirty_tx % TX_RING_SIZE;
- int status = le32_to_cpu(sp->tx_ring[entry].status);
-
- if (speedo_debug > 5)
- printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
- entry, status);
- if ((status & StatusComplete) == 0)
- break; /* It still hasn't been processed. */
- if (status & TxUnderrun)
- if (sp->tx_threshold < 0x01e08000)
- sp->tx_threshold += 0x00040000;
- /* Free the original skb. */
- if (sp->tx_skbuff[entry]) {
- sp->stats.tx_packets++; /* Count only user packets. */
- sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
- pci_unmap_single(sp->pdev,
- le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
- sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(sp->tx_skbuff[entry]);
- sp->tx_skbuff[entry] = 0;
- } else if ((status & 0x70000) == CmdNOp) {
- if (sp->mc_setup_busy)
- pci_unmap_single(sp->pdev,
- sp->mc_setup_dma,
- sp->mc_setup_frm_len,
- PCI_DMA_TODEVICE);
- sp->mc_setup_busy = 0;
- }
- dirty_tx++;
- }
-
-#ifndef final_version
- if (sp->cur_tx - dirty_tx > TX_RING_SIZE) {
- printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
- " full=%d.\n",
- dirty_tx, sp->cur_tx, sp->tx_full);
- dirty_tx += TX_RING_SIZE;
- }
-#endif
-
- sp->dirty_tx = dirty_tx;
+ spin_lock(&sp->lock);
+ speedo_tx_buffer_gc(dev);
if (sp->tx_full
- && sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) {
- /* The ring is no longer full, clear tbusy. */
+ && (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) {
+ /* The ring is no longer full. */
sp->tx_full = 0;
- netif_wake_queue (dev);
+ netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */
}
+ spin_unlock(&sp->lock);
}
- } while (--boguscnt > 0);
-
- if (boguscnt <= 0) {
- printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
- dev->name, status);
- /* Clear all interrupt sources. */
- outl(0xfc00, ioaddr + SCBStatus);
- }
+ if (--boguscnt < 0) {
+ printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
+ dev->name, status);
+ /* Clear all interrupt sources. */
+ /* Will change from 0xfc00 to 0xff00 when we start handling
+ FCP and ER interrupts --Dragan */
+ outl(0xfc00, ioaddr + SCBStatus);
+ break;
+ }
+ } while (1);
if (speedo_debug > 3)
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, inw(ioaddr + SCBStatus));
- spin_unlock (&sp->lock);
+ clear_bit(0, (void*)&sp->in_interrupt);
+ return;
+}
+
+static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
+{
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+ struct RxFD *rxf;
+ struct sk_buff *skb;
+ /* Get a fresh skbuff to replace the consumed one. */
+ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+ sp->rx_skbuff[entry] = skb;
+ if (skb == NULL) {
+ sp->rx_ringp[entry] = NULL;
+ return NULL;
+ }
+ rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
+ sp->rx_ring_dma[entry] =
+ pci_map_single(sp->pdev, rxf,
+ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+ skb->dev = dev;
+ skb_reserve(skb, sizeof(struct RxFD));
+ rxf->rx_buf_addr = 0xffffffff;
+ return rxf;
+}
+
+static inline void speedo_rx_link(struct net_device *dev, int entry,
+ struct RxFD *rxf, dma_addr_t rxf_dma)
+{
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+ rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */
+ rxf->link = 0; /* None yet. */
+ rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
+ sp->last_rxf->link = cpu_to_le32(rxf_dma);
+ sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
+ sp->last_rxf = rxf;
+}
+
+static int speedo_refill_rx_buf(struct net_device *dev, int force)
+{
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+ int entry;
+ struct RxFD *rxf;
+
+ entry = sp->dirty_rx % RX_RING_SIZE;
+ if (sp->rx_skbuff[entry] == NULL) {
+ rxf = speedo_rx_alloc(dev, entry);
+ if (rxf == NULL) {
+ unsigned int forw;
+ int forw_entry;
+ if (speedo_debug > 2 || !(sp->rx_ring_state & RrOOMReported)) {
+ printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n",
+ dev->name, force);
+ speedo_show_state(dev);
+ sp->rx_ring_state |= RrOOMReported;
+ }
+ if (!force)
+ return -1; /* Better luck next time! */
+ /* Borrow an skb from one of next entries. */
+ for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++)
+ if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL)
+ break;
+ if (forw == sp->cur_rx)
+ return -1;
+ forw_entry = forw % RX_RING_SIZE;
+ sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry];
+ sp->rx_skbuff[forw_entry] = NULL;
+ rxf = sp->rx_ringp[forw_entry];
+ sp->rx_ringp[forw_entry] = NULL;
+ sp->rx_ringp[entry] = rxf;
+ }
+ } else {
+ rxf = sp->rx_ringp[entry];
+ }
+ speedo_rx_link(dev, entry, rxf, sp->rx_ring_dma[entry]);
+ sp->dirty_rx++;
+ sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */
+ return 0;
+}
+
+static void speedo_refill_rx_buffers(struct net_device *dev, int force)
+{
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+
+ /* Refill the RX ring. */
+ while ((int)(sp->cur_rx - sp->dirty_rx) > 0 &&
+ speedo_refill_rx_buf(dev, force) != -1);
}
static int
@@ -1360,6 +1717,7 @@ speedo_rx(struct net_device *dev)
int entry = sp->cur_rx % RX_RING_SIZE;
int status;
int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
+ int alloc_ok = 1;
if (speedo_debug > 4)
printk(KERN_DEBUG " In speedo_rx().\n");
@@ -1370,6 +1728,19 @@ speedo_rx(struct net_device *dev)
if (--rx_work_limit < 0)
break;
+
+ /* Check for a rare out-of-memory case: the current buffer is
+ the last buffer allocated in the RX ring. --SAW */
+ if (sp->last_rxf == sp->rx_ringp[entry]) {
+ /* Postpone the packet. It'll be reaped at an interrupt when this
+ packet is no longer the last packet in the ring. */
+ if (speedo_debug > 2)
+ printk(KERN_DEBUG "%s: RX packet postponed!\n",
+ dev->name);
+ sp->rx_ring_state |= RrPostponed;
+ break;
+ }
+
if (speedo_debug > 4)
printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status,
pkt_len);
@@ -1377,11 +1748,12 @@ speedo_rx(struct net_device *dev)
if (status & RxErrTooBig)
printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
"status %8.8x!\n", dev->name, status);
- else if ( ! (status & RxOK)) {
+ else if (! (status & RxOK)) {
/* There was a fatal error. This *should* be impossible. */
sp->stats.rx_errors++;
printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
- "status %8.8x.\n", dev->name, status);
+ "status %8.8x.\n",
+ dev->name, status);
}
} else {
struct sk_buff *skb;
@@ -1394,7 +1766,7 @@ speedo_rx(struct net_device *dev)
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
- PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
#if 1 || USE_IP_CSUM
/* Packet is in one chunk -- we can copy + cksum. */
eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
@@ -1416,7 +1788,7 @@ speedo_rx(struct net_device *dev)
temp = skb_put(skb, pkt_len);
sp->rx_ringp[entry] = NULL;
pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
- PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
@@ -1424,40 +1796,18 @@ speedo_rx(struct net_device *dev)
sp->stats.rx_bytes += pkt_len;
}
entry = (++sp->cur_rx) % RX_RING_SIZE;
+ sp->rx_ring_state &= ~RrPostponed;
+ /* Refill the recently taken buffers.
+ Do it one-by-one to handle traffic bursts better. */
+ if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1)
+ alloc_ok = 0;
}
- /* Refill the Rx ring buffers. */
- for (; sp->cur_rx - sp->dirty_rx > 0; sp->dirty_rx++) {
- struct RxFD *rxf;
- entry = sp->dirty_rx % RX_RING_SIZE;
- if (sp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb;
- /* Get a fresh skbuff to replace the consumed one. */
- skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
- sp->rx_skbuff[entry] = skb;
- if (skb == NULL) {
- sp->rx_ringp[entry] = NULL;
- break; /* Better luck next time! */
- }
- rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
- sp->rx_ring_dma[entry] =
- pci_map_single(sp->pdev, rxf, PKT_BUF_SZ
- + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
- skb->dev = dev;
- skb_reserve(skb, sizeof(struct RxFD));
- rxf->rx_buf_addr = 0xffffffff;
- } else {
- rxf = sp->rx_ringp[entry];
- }
- rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */
- rxf->link = 0; /* None yet. */
- rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
- sp->last_rxf->link = cpu_to_le32(sp->rx_ring_dma[entry]);
- sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
- sp->last_rxf = rxf;
- }
+ /* Try hard to refill the recently taken buffers. */
+ speedo_refill_rx_buffers(dev, 1);
sp->last_rx_time = jiffies;
+
return 0;
}
@@ -1468,6 +1818,7 @@ speedo_close(struct net_device *dev)
struct speedo_private *sp = (struct speedo_private *)dev->priv;
int i;
+ netdevice_stop(dev);
netif_stop_queue(dev);
if (speedo_debug > 1)
@@ -1477,13 +1828,16 @@ speedo_close(struct net_device *dev)
/* Shut off the media monitoring timer. */
del_timer(&sp->timer);
- /* Disable interrupts, and stop the chip's Rx process. */
- outw(SCBMaskAll, ioaddr + SCBCmd);
- outw(SCBMaskAll | RxAbort, ioaddr + SCBCmd);
+ /* Shutting down the chip nicely fails to disable flow control. So.. */
+ outl(PortPartialReset, ioaddr + SCBPort);
free_irq(dev->irq, dev);
- /* Free all the skbuffs in the Rx and Tx queues. */
+ /* Print a few items for debugging. */
+ if (speedo_debug > 3)
+ speedo_show_state(dev);
+
+ /* Free all the skbuffs in the Rx and Tx queues. */
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb = sp->rx_skbuff[i];
sp->rx_skbuff[i] = 0;
@@ -1499,7 +1853,6 @@ speedo_close(struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
struct sk_buff *skb = sp->tx_skbuff[i];
sp->tx_skbuff[i] = 0;
-
/* Clear the Tx descriptors. */
if (skb) {
pci_unmap_single(sp->pdev,
@@ -1508,17 +1861,19 @@ speedo_close(struct net_device *dev)
dev_kfree_skb(skb);
}
}
- if (sp->mc_setup_frm) {
- kfree(sp->mc_setup_frm);
- sp->mc_setup_frm_len = 0;
- }
- /* Print a few items for debugging. */
- if (speedo_debug > 3)
- speedo_show_state(dev);
+ /* Free multicast setting blocks. */
+ for (i = 0; sp->mc_setup_head != NULL; i++) {
+ struct speedo_mc_block *t;
+ t = sp->mc_setup_head->next;
+ kfree(sp->mc_setup_head);
+ sp->mc_setup_head = t;
+ }
+ sp->mc_setup_tail = NULL;
+ if (speedo_debug > 0)
+ printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
- /* Alt: acpi_set_pwr_state(pci_bus, pci_devfn, sp->acpi_pwr); */
- pci_set_power_state (sp->pdev, 2);
+ pci_set_power_state(sp->pdev, 2);
MOD_DEC_USE_COUNT;
@@ -1558,8 +1913,13 @@ speedo_get_stats(struct net_device *dev)
sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs);
sp->lstats->done_marker = 0x0000;
if (netif_running(dev)) {
+ unsigned long flags;
+ /* Take a spinlock to make wait_for_cmd_done and sending the
+ * command atomic. --SAW */
+ spin_lock_irqsave(&sp->lock, flags);
wait_for_cmd_done(ioaddr + SCBCmd);
- outw(CUDumpStats, ioaddr + SCBCmd);
+ outb(CUDumpStats, ioaddr + SCBCmd);
+ spin_unlock_irqrestore(&sp->lock, flags);
}
}
return &sp->stats;
@@ -1577,9 +1937,11 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
data[0] = phy;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- saved_acpi = pci_set_power_state (sp->pdev, 0);
- data[3] = mdio_read (ioaddr, data[0], data[1]);
- pci_set_power_state (sp->pdev, saved_acpi);
+ /* FIXME: these operations probably need to be serialized with MDIO
+ access from the timer routine and timeout handler. 2000/03/08 SAW */
+ saved_acpi = pci_set_power_state(sp->pdev, 0);
+ data[3] = mdio_read(ioaddr, data[0], data[1]);
+ pci_set_power_state(sp->pdev, saved_acpi);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
if (!capable(CAP_NET_ADMIN))
@@ -1619,9 +1981,13 @@ static void set_rx_mode(struct net_device *dev)
} else
new_rx_mode = 0;
- if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) {
- /* The Tx ring is full -- don't add anything! Presumably the new mode
- is in config_cmd_data and will be added anyway. */
+ if (speedo_debug > 3)
+ printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name,
+ sp->rx_mode, new_rx_mode);
+
+ if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) {
+ /* The Tx ring is full -- don't add anything! Hope the mode will be
+ * set again later. */
sp->rx_mode = -1;
return;
}
@@ -1637,8 +2003,7 @@ static void set_rx_mode(struct net_device *dev)
sp->tx_skbuff[entry] = 0; /* Redundant. */
sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure);
sp->tx_ring[entry].link =
- cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE)
- * sizeof(struct TxFD));
+ cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
/* Construct a full CmdConfig frame. */
memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
@@ -1646,7 +2011,10 @@ static void set_rx_mode(struct net_device *dev)
config_cmd_data[4] = rxdmacount;
config_cmd_data[5] = txdmacount + 0x80;
config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
- config_cmd_data[19] = sp->flow_ctrl ? 0xBD : 0x80;
+ /* 0x80 doesn't disable FC 0x84 does.
+ Disable Flow control since we are not ACK-ing any FC interrupts
+ for now. --Dragan */
+ config_cmd_data[19] = 0x84;
config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */
@@ -1656,7 +2024,11 @@ static void set_rx_mode(struct net_device *dev)
/* Trigger the command unit resume. */
wait_for_cmd_done(ioaddr + SCBCmd);
clear_suspend(last_cmd);
- outw(CUResume, ioaddr + SCBCmd);
+ outb(CUResume, ioaddr + SCBCmd);
+ if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+ netif_stop_queue(dev);
+ sp->tx_full = 1;
+ }
spin_unlock_irqrestore(&sp->lock, flags);
}
@@ -1674,8 +2046,7 @@ static void set_rx_mode(struct net_device *dev)
sp->tx_skbuff[entry] = 0;
sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList);
sp->tx_ring[entry].link =
- cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE)
- * sizeof(struct TxFD));
+ cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
*setup_params++ = cpu_to_le16(dev->mc_count*6);
@@ -1691,40 +2062,39 @@ static void set_rx_mode(struct net_device *dev)
wait_for_cmd_done(ioaddr + SCBCmd);
clear_suspend(last_cmd);
/* Immediately trigger the command unit resume. */
- outw(CUResume, ioaddr + SCBCmd);
+ outb(CUResume, ioaddr + SCBCmd);
+
+ if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+ netif_stop_queue(dev);
+ sp->tx_full = 1;
+ }
spin_unlock_irqrestore(&sp->lock, flags);
} else if (new_rx_mode == 0) {
struct dev_mc_list *mclist;
u16 *setup_params, *eaddrs;
- struct descriptor *mc_setup_frm = sp->mc_setup_frm;
+ struct speedo_mc_block *mc_blk;
+ struct descriptor *mc_setup_frm;
int i;
- /* If we are busy, someone might be quickly adding to the MC list.
- Try again later when the list updates stop. */
- if (sp->mc_setup_busy) {
- sp->rx_mode = -1;
+ mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6,
+ GFP_ATOMIC);
+ if (mc_blk == NULL) {
+ printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
+ dev->name);
+ sp->rx_mode = -1; /* We failed, try again. */
return;
}
- if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
- || sp->mc_setup_frm == NULL) {
- /* Allocate a full setup frame, 10bytes + <max addrs>. */
- if (sp->mc_setup_frm)
- kfree(sp->mc_setup_frm);
- sp->mc_setup_frm_len = 10 + multicast_filter_limit*6;
- sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
- if (sp->mc_setup_frm == NULL) {
- printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
- dev->name);
- sp->rx_mode = -1; /* We failed, try again. */
- return;
- }
- }
- mc_setup_frm = sp->mc_setup_frm;
+ mc_blk->next = NULL;
+ mc_blk->len = 2 + multicast_filter_limit*6;
+ mc_blk->frame_dma =
+ pci_map_single(sp->pdev, &mc_blk->frame, mc_blk->len,
+ PCI_DMA_TODEVICE);
+ mc_setup_frm = &mc_blk->frame;
+
/* Fill the setup frame. */
if (speedo_debug > 1)
- printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
- "%d bytes.\n",
- dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
+ printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n",
+ dev->name, mc_setup_frm);
mc_setup_frm->cmd_status =
cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList);
/* Link set below. */
@@ -1741,27 +2111,38 @@ static void set_rx_mode(struct net_device *dev)
/* Disable interrupts while playing with the Tx Cmd list. */
spin_lock_irqsave(&sp->lock, flags);
+
+ if (sp->mc_setup_tail)
+ sp->mc_setup_tail->next = mc_blk;
+ else
+ sp->mc_setup_head = mc_blk;
+ sp->mc_setup_tail = mc_blk;
+ mc_blk->tx = sp->cur_tx;
+
entry = sp->cur_tx++ % TX_RING_SIZE;
last_cmd = sp->last_cmd;
sp->last_cmd = mc_setup_frm;
- sp->mc_setup_busy = 1;
/* Change the command to a NoOp, pointing to the CmdMulti command. */
sp->tx_skbuff[entry] = 0;
sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
- sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len, PCI_DMA_TODEVICE);
- sp->tx_ring[entry].link = cpu_to_le32(sp->mc_setup_dma);
+ sp->tx_ring[entry].link = cpu_to_le32(mc_blk->frame_dma);
/* Set the link in the setup frame. */
mc_setup_frm->link =
- cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE)
- * sizeof(struct TxFD));
+ cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
wait_for_cmd_done(ioaddr + SCBCmd);
clear_suspend(last_cmd);
/* Immediately trigger the command unit resume. */
- outw(CUResume, ioaddr + SCBCmd);
+ outb(CUResume, ioaddr + SCBCmd);
+
+ if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
+ netif_stop_queue(dev);
+ sp->tx_full = 1;
+ }
spin_unlock_irqrestore(&sp->lock, flags);
+
if (speedo_debug > 5)
printk(" CmdMCSetup frame length %d in entry %d.\n",
dev->mc_count, entry);
@@ -1769,9 +2150,8 @@ static void set_rx_mode(struct net_device *dev)
sp->rx_mode = new_rx_mode;
}
-
-
-static void eepro100_suspend (struct pci_dev *pdev)
+
+static void eepro100_suspend(struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
long ioaddr = dev->base_addr;
@@ -1782,54 +2162,58 @@ static void eepro100_suspend (struct pci_dev *pdev)
/* XXX call pci_set_power_state ()? */
}
-
-static void eepro100_resume (struct pci_dev *pdev)
+static void eepro100_resume(struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
- struct speedo_private *np = (struct speedo_private *)dev->priv;
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+ long ioaddr = dev->base_addr;
- netif_device_attach(dev);
+ /* I'm absolutely uncertain if this part of code may work.
+ The problems are:
+ - correct hardware reinitialization;
+ - correct driver behavior between different steps of the
+ reinitialization;
+ - serialization with other driver calls.
+ 2000/03/08 SAW */
+ outw(SCBMaskAll, ioaddr + SCBCmd);
speedo_resume(dev);
- np->rx_mode = -1;
- np->flow_ctrl = np->partner = 0;
+ netif_device_attach(dev);
+ sp->rx_mode = -1;
+ sp->flow_ctrl = sp->partner = 0;
set_rx_mode(dev);
}
-
static void __devexit eepro100_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- unregister_netdev (dev);
+ unregister_netdev(dev);
- release_region (pci_resource_start (pdev, 1),
- pci_resource_len (pdev, 1));
- release_mem_region (pci_resource_start (pdev, 0),
- pci_resource_len (pdev, 0));
+ release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+ release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
#ifndef USE_IO
- iounmap ((char *) dev->base_addr);
+ iounmap((char *)dev->base_addr);
#endif
pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
- + sizeof(struct speedo_stats),
- sp->tx_ring, sp->tx_ring_dma);
-
- kfree (dev);
+ + sizeof(struct speedo_stats),
+ sp->tx_ring, sp->tx_ring_dma);
+ kfree(dev);
}
-
-
+
static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0,},
};
-MODULE_DEVICE_TABLE (pci, eepro100_pci_tbl);
-
+MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
static struct pci_driver eepro100_driver = {
- name: EEPRO100_MODULE_NAME,
+ name: "eepro100",
id_table: eepro100_pci_tbl,
probe: eepro100_init_one,
remove: eepro100_remove_one,
@@ -1837,30 +2221,44 @@ static struct pci_driver eepro100_driver = {
resume: eepro100_resume,
};
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)
+static int pci_module_init(struct pci_driver *pdev)
+{
+ int rc;
+
+ rc = pci_register_driver(pdev);
+ if (rc <= 0) {
+ printk(KERN_INFO "%s: No cards found, driver not installed.\n",
+ pdev->name);
+ pci_unregister_driver(pdev);
+ return -ENODEV;
+ }
+ return 0;
+}
+#endif
static int __init eepro100_init_module(void)
{
+ if (debug >= 0 && speedo_debug != debug)
+ printk(KERN_INFO "eepro100.c: Debug level is %d.\n", debug);
if (debug >= 0)
speedo_debug = debug;
- return pci_module_init (&eepro100_driver);
+ return pci_module_init(&eepro100_driver);
}
-
static void __exit eepro100_cleanup_module(void)
{
- pci_unregister_driver (&eepro100_driver);
+ pci_unregister_driver(&eepro100_driver);
}
-
module_init(eepro100_init_module);
module_exit(eepro100_cleanup_module);
-
+
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` `[ -f ./pci-netif.h ] && echo -DHAS_PCI_NETIF`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c eepro100.c"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 1281fff82..ed0df9a3b 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -52,7 +52,7 @@
#include <linux/if_ether.h> /* For the statistics structure. */
#include <linux/if_arp.h> /* For ARPHRD_ETHER */
-#define LOOPBACK_MTU (PAGE_SIZE - 172)
+#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
/*
* The higher levels take care of making this non-reentrant (it's
@@ -63,13 +63,6 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
/*
- * Take this out if the debug says its ok
- */
-
- if (skb == NULL || dev == NULL)
- printk(KERN_DEBUG "loopback fed NULL data - splat\n");
-
- /*
* Optimise so buffers with skb->free=1 are not copied but
* instead are lobbed from tx queue to rx queue
*/
@@ -110,7 +103,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
/* Initialize the rest of the LOOPBACK device. */
int __init loopback_init(struct net_device *dev)
{
- dev->mtu = LOOPBACK_MTU;
+ dev->mtu = PAGE_SIZE - LOOPBACK_OVERHEAD;
dev->hard_start_xmit = loopback_xmit;
dev->hard_header = eth_header;
dev->hard_header_cache = eth_header_cache;
@@ -127,6 +120,9 @@ int __init loopback_init(struct net_device *dev)
memset(dev->priv, 0, sizeof(struct net_device_stats));
dev->get_stats = get_stats;
+ if (num_physpages >= ((128*1024*1024)>>PAGE_SHIFT))
+ dev->mtu = 4096*4 - LOOPBACK_OVERHEAD;
+
/*
* Fill in the generic fields of the device structure.
*/
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 936abfed8..9530440e3 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -15,6 +15,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
+ dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
if [ "$CONFIG_CARDBUS" = "y" ]; then
dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile
index 65938d96d..ddefee51d 100644
--- a/drivers/net/pcmcia/Makefile
+++ b/drivers/net/pcmcia/Makefile
@@ -39,9 +39,18 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o
obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o
obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o
+obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o
+
O_OBJS := $(filter-out $(export-objs), $(obj-y))
OX_OBJS := $(filter $(export-objs), $(obj-y))
M_OBJS := $(filter-out $(export-objs), $(obj-m))
MX_OBJS := $(filter $(export-objs), $(obj-m))
include $(TOPDIR)/Rules.make
+
+.ibmtr.o: ../tokenring/ibmtr.c
+ $(CC) $(CFLAGS) -D__NO_VERSION__ -DPCMCIA -c -o $@ ../tokenring/ibmtr.c
+
+ibmtr_cs.o: .ibmtr.o ibmtr_cs.c
+ $(CC) $(CFLAGS) -DPCMCIA -c -o .$@ ibmtr_cs.c
+ $(LD) -r -o $@ .$@ .ibmtr.o
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
new file mode 100644
index 000000000..74f4bb612
--- /dev/null
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -0,0 +1,635 @@
+/*======================================================================
+
+ A PCMCIA token-ring driver for IBM-based cards
+
+ This driver supports the IBM PCMCIA Token-Ring Card.
+ Written by Steve Kipisz, kipisz@vnet.ibm.com or
+ bungy@ibm.net
+
+ Written 1995,1996.
+
+ This code is based on pcnet_cs.c from David Hinds.
+
+ V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com
+
+ Linux V2.2.x presented significant changes to the underlying
+ ibmtr.c code. Mainly the code became a lot more organized and
+ modular.
+
+ This caused the old PCMCIA Token Ring driver to give up and go
+ home early. Instead of just patching the old code to make it
+ work, the PCMCIA code has been streamlined, updated and possibly
+ improved.
+
+ This code now only contains code required for the Card Services.
+ All we do here is set the card up enough so that the real ibmtr.c
+ driver can find it and work with it properly.
+
+ i.e. We set up the io port, irq, mmio memory and shared ram memory.
+ This enables ibmtr_probe in ibmtr.c to find the card and configure it
+ as though it was a normal ISA and/or PnP card.
+
+ There is some confusion with the difference between available shared
+ ram and the amount actually reserved from memory. ibmtr.c sets up
+ several offsets depending upon the actual on-board memory, not the
+ reserved memory. We need to get around this to allow the cards to
+ work with other cards in restricted memory space. Therefore the
+ pcmcia_reality_check function.
+
+ TODO
+ - Write the suspend / resume functions.
+ - Fix Kernel Oops when removing card before ifconfig down
+
+ CHANGES
+
+ v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com)
+ Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c
+
+ v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com)
+ Updated to version 2.2.7 to match the first version of the kernel
+ that the modification to ibmtr.c were incorporated into.
+
+
+======================================================================*/
+
+#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/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include <linux/ibmtr.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#define PCMCIA_DEBUG 10
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n"
+" 2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n" ;
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* MMIO base address */
+static u_long mmiobase = 0;
+
+/* SRAM base address */
+static u_long srambase = 0;
+
+/* SRAM size 8,16,32,64 */
+static u_long sramsize = 16;
+
+/* Ringspeed 4,16 */
+static int ringspeed = 16;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(mmiobase, "i");
+MODULE_PARM(srambase, "i");
+MODULE_PARM(sramsize, "i");
+MODULE_PARM(ringspeed, "i");
+
+/*====================================================================*/
+
+static void ibmtr_config(dev_link_t *link);
+static void ibmtr_hw_setup(struct net_device *dev);
+static void ibmtr_release(u_long arg);
+static int ibmtr_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_info_t dev_info = "ibmtr_cs";
+
+static dev_link_t *ibmtr_attach(void);
+static void ibmtr_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+extern int ibmtr_probe(struct net_device *dev);
+unsigned char pcmcia_reality_check(unsigned char gss);
+
+extern int trdev_init(struct net_device *dev);
+extern void tok_interrupt(int irq, struct pt_regs *regs);
+extern int tok_init_card(struct net_device *dev);
+extern unsigned char get_sram_size(struct tok_info *ti);
+
+/*====================================================================*/
+
+typedef struct ibmtr_dev_t {
+ dev_link_t link;
+ struct net_device *dev; /* Changed for 2.2.0 */
+ dev_node_t node;
+ window_handle_t sram_win_handle;
+ struct tok_info ti;
+} ibmtr_dev_t;
+
+/*======================================================================
+
+ This bit of code is used to avoid unregistering network devices
+ at inappropriate times. 2.2 and later kernels are fairly picky
+ about when this can happen.
+
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+ dev_link_t *link, *next;
+ for (link = dev_list; link; link = next) {
+ next = link->next;
+ if (link->state & DEV_STALE_LINK)
+ ibmtr_detach(link);
+ }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+ ibmtr_attach() creates an "instance" of the driver, allocating
+ local data structures for one device. The device is registered
+ with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ibmtr_attach(void)
+{
+ ibmtr_dev_t *info;
+ dev_link_t *link;
+ struct net_device *dev;
+ client_reg_t client_reg;
+ int i, ret;
+
+ DEBUG(0, "ibmtr_attach()\n");
+ flush_stale_links();
+
+ /* Create new token-ring device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+
+ link->release.function = &ibmtr_release;
+ link->release.data = (u_long)link;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.NumPorts1 = 4;
+ link->io.IOAddrLines = 16;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->irq.Handler = &tok_interrupt;
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ dev = init_trdev(NULL,0);
+ dev->priv = &info->ti;
+ link->irq.Instance = info->dev = dev;
+
+ if (dev == NULL) {
+ ibmtr_detach(link);
+ return NULL;
+ }
+
+ dev->init = &ibmtr_probe;
+
+#if 0
+ dev->tbusy = 1;
+#endif
+
+ /* 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 = &ibmtr_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);
+ ibmtr_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* ibmtr_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 ibmtr_detach(dev_link_t *link)
+{
+ struct ibmtr_dev_t *info = link->priv;
+ dev_link_t **linkp;
+ struct net_device *dev;
+ long flags;
+
+
+ DEBUG(0, "ibmtr_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ dev = info->dev;
+
+ save_flags(flags);
+ cli();
+ {
+ struct tok_info *ti = (struct tok_info *)dev->priv;
+ if (ti->tr_timer.next) del_timer(&(ti->tr_timer));
+ }
+ if (link->state & DEV_RELEASE_PENDING) {
+ del_timer(&link->release);
+ link->state &= ~DEV_RELEASE_PENDING;
+ }
+ restore_flags(flags);
+
+ if (link->state & DEV_CONFIG) {
+ ibmtr_release((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ if (link->dev)
+ unregister_trdev(info->dev);
+ kfree(info);
+
+} /* ibmtr_detach */
+
+/*======================================================================
+
+ ibmtr_config() is scheduled to run after a CARD_INSERTION event
+ is received, to configure the PCMCIA socket, and to make the
+ token-ring device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void ibmtr_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ ibmtr_dev_t *info = link->priv;
+ struct net_device *dev = info->dev;
+ struct tok_info *ti = dev->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ win_req_t req;
+ memreq_t mem;
+ int i, last_ret, last_fn;
+ u_char buf[64];
+ unsigned char Shared_Ram_Base;
+
+ DEBUG(0, "ibmtr_config(0x%p)\n", link);
+
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ CS_CHECK(GetTupleData, handle, &tuple);
+ CS_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigBase = parse.config.base;
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ link->conf.ConfigIndex = 0x61;
+
+ /* Determine if this is PRIMARY or ALTERNATE. */
+
+ /* Try PRIMARY card at 0xA20-0xA23 */
+ link->io.BasePort1 = 0xA20;
+ i = CardServices(RequestIO, link->handle, &link->io);
+ if (i == CS_SUCCESS) {
+ memcpy(info->node.dev_name, "tr0\0", 4);
+ } else {
+ /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
+ link->io.BasePort1 = 0xA24;
+ CS_CHECK(RequestIO, link->handle, &link->io);
+ memcpy(info->node.dev_name, "tr1\0", 4);
+ }
+ dev->base_addr = link->io.BasePort1;
+
+ CS_CHECK(RequestIRQ, link->handle, &link->irq);
+ dev->irq = link->irq.AssignedIRQ;
+ ti->irq = link->irq.AssignedIRQ;
+ ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
+
+ /* Allocate the MMIO memory window */
+ req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+ req.Attributes |= WIN_USE_WAIT|WIN_STRICT_ALIGN;
+ req.Base = mmiobase;
+ req.Size = 0x2000;
+ req.AccessSpeed = 250;
+ link->win = (window_handle_t) link->handle;
+ CS_CHECK(RequestWindow, &link->win, &req);
+ mem.CardOffset = req.Base;
+ mem.Page = 0;
+ CS_CHECK(MapMemPage, link->win, &mem);
+ ti->mmio = (u_long)ioremap(req.Base, req.Size);
+
+ /* Allocate the SRAM memory window */
+ req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+ req.Attributes |= WIN_USE_WAIT|WIN_MAP_BELOW_1MB;
+ req.Base = srambase;
+ req.Size = sramsize * 1024;
+ req.AccessSpeed = 250;
+ info->sram_win_handle = (window_handle_t)link->handle;
+ CS_CHECK(RequestWindow, &info->sram_win_handle, &req);
+
+ mem.CardOffset = req.Base;
+ mem.Page = 0;
+ CS_CHECK(MapMemPage, info->sram_win_handle, &mem);
+ Shared_Ram_Base = req.Base >> 12;
+
+ ti->sram = 0;
+ ti->sram_base = Shared_Ram_Base;
+
+ CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+ /* Set up the Token-Ring Controller Configuration Register and
+ turn on the card. Check the "Local Area Network Credit Card
+ Adapters Technical Reference" SC30-3585 for this info. */
+ ibmtr_hw_setup(dev);
+
+#if 0
+ dev->tbusy = 0;
+#endif
+
+ i = register_trdev(dev);
+
+ if (i != 0) {
+ printk(KERN_NOTICE "ibmtr_cs: register_trdev() failed\n");
+ goto failed;
+ }
+
+ link->dev = &info->node;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ printk(KERN_INFO "%s: port %#3lx, irq %d,",
+ dev->name, dev->base_addr, dev->irq);
+ printk (" mmio %#5lx,", (u_long)ti->mmio);
+ printk (" sram %#5lx,", (u_long)ti->sram_base << 12);
+ printk ("\n" KERN_INFO " hwaddr=");
+ for (i = 0; i < TR_ALEN; i++)
+ printk("%02X", dev->dev_addr[i]);
+ printk("\n");
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+failed:
+ ibmtr_release((u_long)link);
+} /* ibmtr_config */
+
+/*======================================================================
+
+ After a card is removed, ibmtr_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 ibmtr_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+ ibmtr_dev_t *info = link->priv;
+ struct net_device *dev = info->dev;
+ struct tok_info *ti=(struct tok_info *) dev->priv;
+
+ DEBUG(0, "ibmtr_release(0x%p)\n", link);
+
+ if (link->open) {
+ DEBUG(1, "ibmtr_cs: release postponed, '%s' "
+ "still open\n", info->node.dev_name);
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ ti->open_status=CLOSED;
+
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+ if (link->win) {
+ struct tok_info *ti = dev->priv;
+ iounmap((void *)ti->mmio);
+ CardServices(ReleaseWindow, link->win);
+ CardServices(ReleaseWindow, info->sram_win_handle);
+ }
+
+ link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+
+} /* ibmtr_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.
+
+======================================================================*/
+
+static int ibmtr_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+ ibmtr_dev_t *info = link->priv;
+ struct net_device *dev = info->dev;
+
+ DEBUG(1, "ibmtr_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+#if 0
+ dev->tbusy = 1; dev->start = 0;
+#endif
+ link->release.expires = jiffies + HZ/20;
+ link->state |= DEV_RELEASE_PENDING;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT;
+ ibmtr_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG) {
+#if 0
+ if (link->open) {
+ dev->tbusy = 1; dev->start = 0;
+ }
+#endif
+ 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);
+ if (link->open) {
+ (dev->init)(dev);
+#if 0
+ dev->tbusy = 0; dev->start = 1;
+#endif
+ }
+ }
+ break;
+ }
+ return 0;
+} /* ibmtr_event */
+
+/*====================================================================*/
+
+static void ibmtr_hw_setup(struct net_device *dev)
+{
+ struct tok_info *ti = dev->priv;
+ int i;
+
+ /* Bizarre IBM behavior, there are 16 bits of information we
+ need to set, but the card only allows us to send 4 bits at a
+ time. For each byte sent to base_addr, bits 7-4 tell the
+ card which part of the 16 bits we are setting, bits 3-0 contain
+ the actual information */
+
+ /* First nibble provides 4 bits of mmio */
+ i = ((int)ti->mmio >> 16) & 0x0F;
+ outb(i, dev->base_addr);
+
+ /* Second nibble provides 3 bits of mmio */
+ i = 0x10 | (((int)ti->mmio >> 12) & 0x0E);
+ outb(i, dev->base_addr);
+
+ /* Third nibble, hard-coded values */
+ i = 0x26;
+ outb(i, dev->base_addr);
+
+ /* Fourth nibble sets shared ram page size */
+
+ /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
+
+ i = (sramsize >> 4) & 0x07;
+ i = ((i == 4) ? 3 : i) << 2;
+ i |= 0x30;
+
+ if (ringspeed == 16)
+ i |= 2;
+ if (dev->base_addr == 0xA24)
+ i |= 1;
+ outb(i, dev->base_addr);
+
+ /* X40 will release the card for use */
+
+ outb(0x40, dev->base_addr);
+
+ return;
+}
+
+/*======================================================================
+
+ A sweet little function that circumvents the problem with
+ ibmtr.c trying to use more memory than we can allocate for
+ the PCMCIA card. ibmtr.c just assumes that if a card has
+ 64K of shared ram, the entire 64K must be mapped into memory,
+ whereas resources are sometimes a little tight in card services
+ so we fool ibmtr.c into thinking the card has less memory on
+ it than it has.
+
+======================================================================*/
+
+unsigned char pcmcia_reality_check(unsigned char gss)
+{
+ return (gss < sramsize) ? sramsize : gss;
+}
+
+/*====================================================================*/
+
+static int __init init_ibmtr_cs(void)
+{
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "ibmtr_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &ibmtr_attach, &ibmtr_detach);
+ return 0;
+}
+
+static void __exit exit_ibmtr_cs(void)
+{
+ DEBUG(0, "ibmtr_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ ibmtr_detach(dev_list);
+}
+
+module_init(init_ibmtr_cs);
+module_exit(exit_ibmtr_cs);
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index e87de253d..c3eb74c37 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -119,9 +119,11 @@ ppp_asynctty_open(struct tty_struct *tty)
struct asyncppp *ap;
int err;
+ MOD_INC_USE_COUNT;
+ err = -ENOMEM;
ap = kmalloc(sizeof(*ap), GFP_KERNEL);
if (ap == 0)
- return -ENOMEM;
+ goto out;
/* initialize the asyncppp structure */
memset(ap, 0, sizeof(*ap));
@@ -140,15 +142,18 @@ ppp_asynctty_open(struct tty_struct *tty)
ap->chan.ops = &async_ops;
ap->chan.mtu = PPP_MRU;
err = ppp_register_channel(&ap->chan);
- if (err) {
- kfree(ap);
- return err;
- }
+ if (err)
+ goto out_free;
tty->disc_data = ap;
- MOD_INC_USE_COUNT;
return 0;
+
+ out_free:
+ kfree(ap);
+ out:
+ MOD_DEC_USE_COUNT;
+ return err;
}
/*
@@ -215,6 +220,16 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
err = -EFAULT;
switch (cmd) {
+ case PPPIOCGCHAN:
+ err = -ENXIO;
+ if (ap == 0)
+ break;
+ err = -EFAULT;
+ if (put_user(ppp_channel_index(&ap->chan), (int *) arg))
+ break;
+ err = 0;
+ break;
+
case PPPIOCGUNIT:
err = -ENXIO;
if (ap == 0)
@@ -257,10 +272,14 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
case PPPIOCSXASYNCMAP:
case PPPIOCGMRU:
case PPPIOCSMRU:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ break;
err = ppp_async_ioctl(&ap->chan, cmd, arg);
break;
case PPPIOCATTACH:
+ case PPPIOCDETACH:
err = ppp_channel_ioctl(&ap->chan, cmd, arg);
break;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 01b2cc4ea..a70c1a8db 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -19,7 +19,7 @@
* PPP driver, written by Michael Callahan and Al Longyear, and
* subsequently hacked by Paul Mackerras.
*
- * ==FILEVERSION 20000313==
+ * ==FILEVERSION 20000406==
*/
#include <linux/config.h>
@@ -55,8 +55,8 @@
#define NP_AT 3 /* Appletalk protocol */
#define NUM_NP 4 /* Number of NPs. */
-#define MPHDRLEN 4 /* multilink protocol header length */
-#define MPHDRLEN_SSN 2 /* ditto with short sequence numbers */
+#define MPHDRLEN 6 /* multilink protocol header length */
+#define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */
#define MIN_FRAG_SIZE 64
/*
@@ -125,12 +125,13 @@ struct ppp {
/*
* Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
- * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ.
+ * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
* Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
* Bits in xstate: SC_COMP_RUN
*/
#define SC_FLAG_BITS (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
- |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ)
+ |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
+ |SC_COMP_TCP|SC_REJ_COMP_TCP)
/*
* Private data structure for each channel.
@@ -182,6 +183,14 @@ static int last_channel_index;
/* We limit the length of ppp->file.rq to this (arbitrary) value */
#define PPP_MAX_RQLEN 32
+/*
+ * Maximum number of multilink fragments queued up.
+ * This has to be large enough to cope with the maximum latency of
+ * the slowest channel relative to the others. Strictly it should
+ * depend on the number of channels and their characteristics.
+ */
+#define PPP_MP_MAX_QLEN 128
+
/* Multilink header bits. */
#define B 0x80 /* this fragment begins a packet */
#define E 0x40 /* this fragment ends a packet */
@@ -351,10 +360,13 @@ static ssize_t ppp_file_read(struct ppp_file *pf, struct file *file,
add_wait_queue(&pf->rwait, &wait);
current->state = TASK_INTERRUPTIBLE;
for (;;) {
- ret = -EAGAIN;
skb = skb_dequeue(&pf->rq);
if (skb)
break;
+ ret = 0;
+ if (pf->kind == CHANNEL && PF_TO_CHANNEL(pf)->chan == 0)
+ break;
+ ret = -EAGAIN;
if (file->f_flags & O_NONBLOCK)
break;
ret = -ERESTARTSYS;
@@ -487,7 +499,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
spin_lock_bh(&pch->downl);
chan = pch->chan;
err = -ENOTTY;
- if (chan->ops->ioctl)
+ if (chan && chan->ops->ioctl)
err = chan->ops->ioctl(chan, cmd, arg);
spin_unlock_bh(&pch->downl);
}
@@ -767,6 +779,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
outf:
kfree_skb(skb);
+ ++ppp->stats.tx_dropped;
return 0;
}
@@ -1003,8 +1016,15 @@ ppp_push(struct ppp *ppp)
pch = list_entry(list, struct channel, clist);
spin_lock_bh(&pch->downl);
- if (skb_queue_len(&pch->file.xq) == 0
- && pch->chan->ops->start_xmit(pch->chan, skb))
+ if (pch->chan) {
+ if (pch->chan->ops->start_xmit(pch->chan, skb))
+ skb = 0;
+ } else {
+ /* channel got unregistered */
+ kfree_skb(skb);
+ skb = 0;
+ }
+ if (skb_queue_len(&pch->file.xq) == 0 && skb == 0)
ppp->xmit_pending = 0;
spin_unlock_bh(&pch->downl);
return;
@@ -1029,7 +1049,8 @@ ppp_push(struct ppp *ppp)
static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
{
int nch, len, fragsize;
- int i, bits, hdrlen;
+ int i, bits, hdrlen, mtu;
+ int flen, fnb;
unsigned char *p, *q;
struct list_head *list;
struct channel *pch;
@@ -1037,6 +1058,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
struct ppp_channel *chan;
nch = 0;
+ hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
list = &ppp->channels;
while ((list = list->next) != &ppp->channels) {
pch = list_entry(list, struct channel, clist);
@@ -1087,8 +1109,6 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
/* create a fragment for each channel */
bits = B;
- hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
- /* XXX gotta do A/C and prot compression here */
do {
list = list->next;
if (list == &ppp->channels) {
@@ -1099,47 +1119,73 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
++i;
if (!pch->avail)
continue;
- if (fragsize >= len) {
- fragsize = len;
- bits |= E;
+
+ /* check the channel's mtu and whether it is still attached. */
+ spin_lock_bh(&pch->downl);
+ if (pch->chan == 0 || (mtu = pch->chan->mtu) < hdrlen) {
+ /* can't use this channel */
+ spin_unlock_bh(&pch->downl);
+ pch->avail = 0;
+ if (--nch == 0)
+ break;
+ continue;
}
- frag = alloc_skb(fragsize + hdrlen, GFP_ATOMIC);
- if (frag != 0) {
- q = skb_put(frag, fragsize + hdrlen);
+
+ /*
+ * We have to create multiple fragments for this channel
+ * if fragsize is greater than the channel's mtu.
+ */
+ if (fragsize > len)
+ fragsize = len;
+ for (flen = fragsize; flen > 0; flen -= fnb) {
+ fnb = flen;
+ if (fnb > mtu + 2 - hdrlen)
+ fnb = mtu + 2 - hdrlen;
+ if (fnb >= len)
+ bits |= E;
+ frag = alloc_skb(fnb + hdrlen, GFP_ATOMIC);
+ if (frag == 0)
+ goto noskb;
+ q = skb_put(frag, fnb + hdrlen);
/* make the MP header */
+ q[0] = PPP_MP >> 8;
+ q[1] = PPP_MP;
if (ppp->flags & SC_MP_XSHORTSEQ) {
- q[0] = bits + ((ppp->nxseq >> 8) & 0xf);
- q[1] = ppp->nxseq;
- } else {
- q[0] = bits;
- q[1] = ppp->nxseq >> 16;
- q[2] = ppp->nxseq >> 8;
+ q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
q[3] = ppp->nxseq;
+ } else {
+ q[2] = bits;
+ q[3] = ppp->nxseq >> 16;
+ q[4] = ppp->nxseq >> 8;
+ q[5] = ppp->nxseq;
}
/* copy the data in */
- memcpy(q + hdrlen, p, fragsize);
+ memcpy(q + hdrlen, p, fnb);
/* try to send it down the channel */
- spin_lock_bh(&pch->downl);
chan = pch->chan;
- if (chan != 0) {
- if (!chan->ops->start_xmit(chan, frag))
- skb_queue_tail(&pch->file.xq, frag);
- } else {
- /* channel got unregistered, too bad */
- kfree_skb(skb);
- }
- spin_unlock_bh(&pch->downl);
+ if (!chan->ops->start_xmit(chan, frag))
+ skb_queue_tail(&pch->file.xq, frag);
+ pch->had_frag = 1;
+ p += fnb;
+ len -= fnb;
+ ++ppp->nxseq;
+ bits = 0;
}
- p += fragsize;
- len -= fragsize;
- ++ppp->nxseq;
- bits = 0;
+ spin_unlock_bh(&pch->downl);
} while (len > 0);
ppp->nxchan = i;
return 1;
+
+ noskb:
+ spin_unlock_bh(&pch->downl);
+ if (ppp->debug & 1)
+ printk(KERN_ERR "PPP: no memory (fragment)\n");
+ ++ppp->stats.tx_errors;
+ ++ppp->nxseq;
+ return 1; /* abandon the frame */
}
#endif /* CONFIG_PPP_MULTILINK */
@@ -1201,7 +1247,7 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
proto = PPP_PROTO(skb);
read_lock_bh(&pch->upl);
- if (pch->ppp == 0 || proto == PPP_LCP || proto == 0x80fb) {
+ if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) {
/* put it on the channel queue */
skb_queue_tail(&pch->file.rq, skb);
/* drop old frames if queue too long */
@@ -1306,12 +1352,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
}
len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2);
if (len <= 0) {
- int i;
printk(KERN_DEBUG "PPP: VJ decompression error\n");
- printk(KERN_DEBUG "PPP: len = %d data =", skb->len);
- for (i = 0; i < 16 && i < skb->len; ++i)
- printk(" %.2x", skb->data[i]);
- printk("\n");
goto err;
}
len += 2;
@@ -1426,11 +1467,11 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
static void
ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{
- u32 mask, seq, minseq;
+ u32 mask, seq;
struct list_head *l;
- int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? 2: 4;
+ int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
- if (skb->len < mphdrlen + 3)
+ if (skb->len < mphdrlen + 1 || ppp->mrru == 0)
goto err; /* no good, throw it away */
/* Decode sequence number and begin/end bits */
@@ -1442,22 +1483,38 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
mask = 0xffffff;
}
skb->BEbits = skb->data[2];
- skb_pull(skb, mphdrlen + 2); /* pull off PPP and MP headers*/
-
- /* Expand sequence number to 32 bits */
- seq |= pch->lastseq & ~mask;
- if (seq_before(seq, pch->lastseq)) {
- if (seq_after(seq, pch->lastseq - 100)) {
- printk(KERN_DEBUG "PPP: MP fragments out of order"
- " (%u, %u)\n", pch->lastseq, seq);
- goto err;
- }
+ skb_pull(skb, mphdrlen); /* pull off PPP and MP headers */
+
+ /*
+ * Do protocol ID decompression on the first fragment of each packet.
+ */
+ if ((skb->BEbits & B) && (skb->data[0] & 1))
+ *skb_push(skb, 1) = 0;
+
+ /*
+ * Expand sequence number to 32 bits, making it as close
+ * as possible to ppp->minseq.
+ */
+ seq |= ppp->minseq & ~mask;
+ if ((int)(ppp->minseq - seq) > (int)(mask >> 1))
seq += mask + 1;
- }
+ else if ((int)(seq - ppp->minseq) > (int)(mask >> 1))
+ seq -= mask + 1; /* should never happen */
skb->sequence = seq;
pch->lastseq = seq;
/*
+ * If this packet comes before the next one we were expecting,
+ * drop it.
+ */
+ if (seq_before(seq, ppp->nextseq)) {
+ kfree_skb(skb);
+ ++ppp->stats.rx_dropped;
+ ppp_receive_error(ppp);
+ return;
+ }
+
+ /*
* Reevaluate minseq, the minimum over all channels of the
* last sequence number received on each channel. Because of
* the increasing sequence number rule, we know that any fragment
@@ -1465,17 +1522,23 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
* The list of channels can't change because we have the receive
* side of the ppp unit locked.
*/
- minseq = seq;
for (l = ppp->channels.next; l != &ppp->channels; l = l->next) {
struct channel *ch = list_entry(l, struct channel, clist);
if (seq_before(ch->lastseq, seq))
seq = ch->lastseq;
}
- ppp->minseq = minseq;
+ if (seq_before(ppp->minseq, seq))
+ ppp->minseq = seq;
/* Put the fragment on the reconstruction queue */
ppp_mp_insert(ppp, skb);
+ /* If the queue is getting long, don't wait any longer for packets
+ before the start of the queue. */
+ if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN
+ && seq_before(ppp->minseq, ppp->mrq.next->sequence))
+ ppp->minseq = ppp->mrq.next->sequence;
+
/* Pull completed packets off the queue and receive them. */
while ((skb = ppp_mp_reconstruct(ppp)) != 0)
ppp_receive_nonmp_frame(ppp, skb);
@@ -1523,16 +1586,17 @@ ppp_mp_reconstruct(struct ppp *ppp)
struct sk_buff *skb = NULL;
int lost = 0, len = 0;
+ if (ppp->mrru == 0) /* do nothing until mrru is set */
+ return NULL;
head = list->next;
tail = NULL;
for (p = head; p != (struct sk_buff *) list; p = next) {
next = p->next;
if (seq_before(p->sequence, seq)) {
- /* this can't happen, anyway toss the skb */
- printk(KERN_ERR "ppp_mp_reconstruct bad seq %x < %x\n",
+ /* this can't happen, anyway ignore the skb */
+ printk(KERN_ERR "ppp_mp_reconstruct bad seq %u < %u\n",
p->sequence, seq);
- __skb_unlink(p, list);
- kfree_skb(p);
+ head = next;
continue;
}
if (p->sequence != seq) {
@@ -1542,8 +1606,8 @@ ppp_mp_reconstruct(struct ppp *ppp)
break;
/* Fragment `seq' is lost, keep going. */
lost = 1;
- seq = seq_before(p->sequence, minseq)?
- p->sequence: minseq;
+ seq = seq_before(minseq, p->sequence)?
+ minseq + 1: p->sequence;
next = p;
continue;
}
@@ -1560,22 +1624,31 @@ ppp_mp_reconstruct(struct ppp *ppp)
if (p->BEbits & B) {
head = p;
lost = 0;
- /* reset len, allow for protocol ID compression */
- len = p->data[0] & 1;
+ len = 0;
}
len += p->len;
/* Got a complete packet yet? */
if (lost == 0 && (p->BEbits & E) && (head->BEbits & B)) {
- if (len > ppp->mrru) {
+ if (len > ppp->mrru + 2) {
++ppp->stats.rx_length_errors;
+ printk(KERN_DEBUG "PPP: reconstructed packet"
+ " is too long (%d)\n", len);
+ } else if (p == head) {
+ /* fragment is complete packet - reuse skb */
+ tail = p;
+ skb = skb_get(p);
+ break;
} else if ((skb = dev_alloc_skb(len)) == NULL) {
++ppp->stats.rx_missed_errors;
+ printk(KERN_DEBUG "PPP: no memory for "
+ "reconstructed packet");
} else {
tail = p;
break;
}
+ ppp->nextseq = seq + 1;
}
/*
@@ -1593,19 +1666,18 @@ ppp_mp_reconstruct(struct ppp *ppp)
if (tail != NULL) {
/* If we have discarded any fragments,
signal a receive error. */
- if (head->sequence != ppp->nextseq)
+ if (head->sequence != ppp->nextseq) {
+ if (ppp->debug & 1)
+ printk(KERN_DEBUG " missed pkts %u..%u\n",
+ ppp->nextseq, head->sequence-1);
+ ++ppp->stats.rx_dropped;
ppp_receive_error(ppp);
-
- /* uncompress protocol ID */
- if (head->data[0] & 1)
- *skb_put(skb, 1) = 0;
- p = head;
- for (;;) {
- memcpy(skb_put(skb, p->len), p->data, p->len);
- if (p == tail)
- break;
- p = p->next;
}
+
+ if (head != tail)
+ /* copy to a single skb */
+ for (p = head; p != tail->next; p = p->next)
+ memcpy(skb_put(skb, p->len), p->data, p->len);
ppp->nextseq = tail->sequence + 1;
head = tail->next;
}
@@ -1642,6 +1714,9 @@ ppp_register_channel(struct ppp_channel *chan)
chan->ppp = pch;
init_ppp_file(&pch->file, CHANNEL);
pch->file.hdrlen = chan->hdrlen;
+#ifdef CONFIG_PPP_MULTILINK
+ pch->lastseq = -1;
+#endif /* CONFIG_PPP_MULTILINK */
spin_lock_init(&pch->downl);
pch->upl = RW_LOCK_UNLOCKED;
spin_lock_bh(&all_channels_lock);
@@ -1653,13 +1728,30 @@ ppp_register_channel(struct ppp_channel *chan)
}
/*
- * Return the unit number associated with a channel.
+ * Return the index of a channel.
+ */
+int ppp_channel_index(struct ppp_channel *chan)
+{
+ struct channel *pch = chan->ppp;
+
+ return pch->file.index;
+}
+
+/*
+ * Return the PPP unit number to which a channel is connected.
*/
int ppp_unit_number(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
+ int unit = -1;
- return pch->ppp->file.index;
+ if (pch != 0) {
+ read_lock_bh(&pch->upl);
+ if (pch->ppp != 0)
+ unit = pch->ppp->file.index;
+ read_unlock_bh(&pch->upl);
+ }
+ return unit;
}
/*
@@ -1760,6 +1852,8 @@ int ppp_channel_ioctl(struct ppp_channel *chan, unsigned int cmd,
int err = -ENOTTY;
int unit;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
if (pch == 0)
return -EINVAL;
switch (cmd) {
@@ -2104,6 +2198,10 @@ ppp_create_interface(int unit, int *retp)
INIT_LIST_HEAD(&ppp->channels);
spin_lock_init(&ppp->rlock);
spin_lock_init(&ppp->wlock);
+#ifdef CONFIG_PPP_MULTILINK
+ ppp->minseq = -1;
+ skb_queue_head_init(&ppp->mrq);
+#endif /* CONFIG_PPP_MULTILINK */
ppp->dev = dev;
dev->init = ppp_net_init;
@@ -2163,6 +2261,9 @@ static void ppp_destroy_interface(struct ppp *ppp)
}
skb_queue_purge(&ppp->file.xq);
skb_queue_purge(&ppp->file.rq);
+#ifdef CONFIG_PPP_MULTILINK
+ skb_queue_purge(&ppp->mrq);
+#endif /* CONFIG_PPP_MULTILINK */
dev = ppp->dev;
ppp->dev = 0;
ppp_unlock(ppp);
@@ -2247,10 +2348,12 @@ ppp_connect_channel(struct channel *pch, int unit)
if (pch->chan == 0) /* need to check this?? */
goto outr;
- hdrlen = pch->chan->hdrlen + PPP_HDRLEN;
+ if (pch->file.hdrlen > ppp->file.hdrlen)
+ ppp->file.hdrlen = pch->file.hdrlen;
+ hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */
if (ppp->dev && hdrlen > ppp->dev->hard_header_len)
ppp->dev->hard_header_len = hdrlen;
- list_add(&pch->clist, &ppp->channels);
+ list_add_tail(&pch->clist, &ppp->channels);
++ppp->n_channels;
pch->ppp = ppp;
ret = 0;
@@ -2319,6 +2422,7 @@ module_exit(ppp_cleanup);
EXPORT_SYMBOL(ppp_register_channel);
EXPORT_SYMBOL(ppp_unregister_channel);
+EXPORT_SYMBOL(ppp_channel_index);
EXPORT_SYMBOL(ppp_unit_number);
EXPORT_SYMBOL(ppp_input);
EXPORT_SYMBOL(ppp_input_error);
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 8bae76e1c..e049ab4bd 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -29,11 +29,9 @@
* PPP driver, written by Michael Callahan and Al Longyear, and
* subsequently hacked by Paul Mackerras.
*
- * ==FILEVERSION 991018==
+ * ==FILEVERSION 20000322==
*/
-/* $Id: ppp_synctty.c,v 1.3 1999/09/02 05:30:10 paulus Exp $ */
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -43,9 +41,17 @@
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
#include <linux/ppp_channel.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
-#define PPP_VERSION "2.4.0"
+#ifndef spin_trylock_bh
+#define spin_trylock_bh(lock) ({ int __r; local_bh_disable(); \
+ __r = spin_trylock(lock); \
+ if (!__r) local_bh_enable(); \
+ __r; })
+#endif
+
+#define PPP_VERSION "2.4.1"
/* Structure for storing local state. */
struct syncppp {
@@ -53,29 +59,25 @@ struct syncppp {
unsigned int flags;
unsigned int rbits;
int mru;
- unsigned long busy;
+ spinlock_t xmit_lock;
+ spinlock_t recv_lock;
+ unsigned long xmit_flags;
u32 xaccm[8];
u32 raccm;
unsigned int bytes_sent;
unsigned int bytes_rcvd;
struct sk_buff *tpkt;
- struct sk_buff_head xq;
unsigned long last_xmit;
struct sk_buff *rpkt;
- struct sk_buff_head rq;
- wait_queue_head_t rwait;
struct ppp_channel chan; /* interface to generic ppp layer */
- int connected;
};
-/* Bit numbers in busy */
-#define XMIT_BUSY 0
-#define RECV_BUSY 1
-#define XMIT_WAKEUP 2
-#define XMIT_FULL 3
+/* Bit numbers in xmit_flags */
+#define XMIT_WAKEUP 0
+#define XMIT_FULL 1
/* Bits in rbits */
#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
@@ -85,15 +87,18 @@ struct syncppp {
/*
* Prototypes.
*/
-static struct sk_buff* ppp_sync_txdequeue(struct syncppp *ap);
+static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *);
static int ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb);
+static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd,
+ unsigned long arg);
static int ppp_sync_push(struct syncppp *ap);
static void ppp_sync_flush_output(struct syncppp *ap);
static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
- char *flags, int count);
+ char *flags, int count);
struct ppp_channel_ops sync_ops = {
- ppp_sync_send
+ ppp_sync_send,
+ ppp_sync_ioctl
};
/*
@@ -157,50 +162,6 @@ ppp_print_buffer (const char *name, const __u8 *buf, int count)
}
}
-/*
- * Routines for locking and unlocking the transmit and receive paths.
- */
-static inline void
-lock_path(struct syncppp *ap, int bit)
-{
- do {
- while (test_bit(bit, &ap->busy))
- mb();
- } while (test_and_set_bit(bit, &ap->busy));
- mb();
-}
-
-static inline int
-trylock_path(struct syncppp *ap, int bit)
-{
- if (test_and_set_bit(bit, &ap->busy))
- return 0;
- mb();
- return 1;
-}
-
-static inline void
-unlock_path(struct syncppp *ap, int bit)
-{
- mb();
- clear_bit(bit, &ap->busy);
-}
-
-#define lock_xmit_path(ap) lock_path(ap, XMIT_BUSY)
-#define trylock_xmit_path(ap) trylock_path(ap, XMIT_BUSY)
-#define unlock_xmit_path(ap) unlock_path(ap, XMIT_BUSY)
-#define lock_recv_path(ap) lock_path(ap, RECV_BUSY)
-#define trylock_recv_path(ap) trylock_path(ap, RECV_BUSY)
-#define unlock_recv_path(ap) unlock_path(ap, RECV_BUSY)
-
-static inline void
-flush_skb_queue(struct sk_buff_head *q)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(q)) != 0)
- kfree_skb(skb);
-}
/*
* Routines implementing the synchronous PPP line discipline.
@@ -213,27 +174,41 @@ static int
ppp_sync_open(struct tty_struct *tty)
{
struct syncppp *ap;
+ int err;
+ MOD_INC_USE_COUNT;
ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+ err = -ENOMEM;
if (ap == 0)
- return -ENOMEM;
-
- MOD_INC_USE_COUNT;
+ goto out;
/* initialize the syncppp structure */
memset(ap, 0, sizeof(*ap));
ap->tty = tty;
ap->mru = PPP_MRU;
+ spin_lock_init(&ap->xmit_lock);
+ spin_lock_init(&ap->recv_lock);
ap->xaccm[0] = ~0U;
ap->xaccm[3] = 0x60000000U;
ap->raccm = ~0U;
- skb_queue_head_init(&ap->xq);
- skb_queue_head_init(&ap->rq);
- init_waitqueue_head(&ap->rwait);
+
+ ap->chan.private = ap;
+ ap->chan.ops = &sync_ops;
+ ap->chan.mtu = PPP_MRU;
+ ap->chan.hdrlen = 2; /* for A/C bytes */
+ err = ppp_register_channel(&ap->chan);
+ if (err)
+ goto out_free;
tty->disc_data = ap;
return 0;
+
+ out_free:
+ kfree(ap);
+ out:
+ MOD_DEC_USE_COUNT;
+ return err;
}
/*
@@ -248,208 +223,59 @@ ppp_sync_close(struct tty_struct *tty)
if (ap == 0)
return;
tty->disc_data = 0;
- lock_xmit_path(ap);
- lock_recv_path(ap);
+ ppp_unregister_channel(&ap->chan);
if (ap->rpkt != 0)
kfree_skb(ap->rpkt);
- flush_skb_queue(&ap->rq);
if (ap->tpkt != 0)
kfree_skb(ap->tpkt);
- flush_skb_queue(&ap->xq);
- if (ap->connected)
- ppp_unregister_channel(&ap->chan);
kfree(ap);
MOD_DEC_USE_COUNT;
}
/*
- * Read a PPP frame. pppd can use this to negotiate over the
- * channel before it joins it to a bundle.
+ * Read a PPP frame, for compatibility until pppd is updated.
*/
static ssize_t
ppp_sync_read(struct tty_struct *tty, struct file *file,
unsigned char *buf, size_t count)
{
struct syncppp *ap = tty->disc_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- struct sk_buff *skb = 0;
- ret = -ENXIO;
if (ap == 0)
- goto out; /* should never happen */
-
- add_wait_queue(&ap->rwait, &wait);
- current->state = TASK_INTERRUPTIBLE;
- for (;;) {
- ret = -EAGAIN;
- skb = skb_dequeue(&ap->rq);
- if (skb)
- break;
- if (file->f_flags & O_NONBLOCK)
- break;
- ret = -ERESTARTSYS;
- if (signal_pending(current))
- break;
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&ap->rwait, &wait);
-
- if (skb == 0)
- goto out;
-
- ret = -EOVERFLOW;
- if (skb->len > count)
- goto outf;
- ret = -EFAULT;
- if (copy_to_user(buf, skb->data, skb->len))
- goto outf;
- ret = skb->len;
-
- outf:
- kfree_skb(skb);
- out:
- return ret;
+ return -ENXIO;
+ return ppp_channel_read(&ap->chan, file, buf, count);
}
/*
- * Write a ppp frame. pppd can use this to send frames over
- * this particular channel.
+ * Write a ppp frame, for compatibility until pppd is updated.
*/
static ssize_t
ppp_sync_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t count)
{
struct syncppp *ap = tty->disc_data;
- struct sk_buff *skb;
- ssize_t ret;
- ret = -ENXIO;
if (ap == 0)
- goto out; /* should never happen */
-
- ret = -ENOMEM;
- skb = alloc_skb(count + 2, GFP_KERNEL);
- if (skb == 0)
- goto out;
- skb_reserve(skb, 2);
- ret = -EFAULT;
- if (copy_from_user(skb_put(skb, count), buf, count)) {
- kfree_skb(skb);
- goto out;
- }
-
- skb_queue_tail(&ap->xq, skb);
- ppp_sync_push(ap);
-
- ret = count;
-
- out:
- return ret;
+ return -ENXIO;
+ return ppp_channel_write(&ap->chan, buf, count);
}
static int
-ppp_sync_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
+ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct syncppp *ap = tty->disc_data;
int err, val;
- u32 accm[8];
- struct sk_buff *skb;
-
- err = -ENXIO;
- if (ap == 0)
- goto out; /* should never happen */
- err = -EPERM;
- if (!capable(CAP_NET_ADMIN))
- goto out;
err = -EFAULT;
switch (cmd) {
- case PPPIOCGFLAGS:
- val = ap->flags | ap->rbits;
- if (put_user(val, (int *) arg))
- break;
- err = 0;
- break;
- case PPPIOCSFLAGS:
- if (get_user(val, (int *) arg))
- break;
- ap->flags = val & ~SC_RCV_BITS;
- ap->rbits = val & SC_RCV_BITS;
- err = 0;
- break;
-
- case PPPIOCGASYNCMAP:
- if (put_user(ap->xaccm[0], (u32 *) arg))
- break;
- err = 0;
- break;
- case PPPIOCSASYNCMAP:
- if (get_user(ap->xaccm[0], (u32 *) arg))
- break;
- err = 0;
- break;
-
- case PPPIOCGRASYNCMAP:
- if (put_user(ap->raccm, (u32 *) arg))
- break;
- err = 0;
- break;
- case PPPIOCSRASYNCMAP:
- if (get_user(ap->raccm, (u32 *) arg))
- break;
- err = 0;
- break;
-
- case PPPIOCGXASYNCMAP:
- if (copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm)))
- break;
- err = 0;
- break;
- case PPPIOCSXASYNCMAP:
- if (copy_from_user(accm, (void *) arg, sizeof(accm)))
- break;
- accm[2] &= ~0x40000000U; /* can't escape 0x5e */
- accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */
- memcpy(ap->xaccm, accm, sizeof(ap->xaccm));
- err = 0;
- break;
-
- case PPPIOCGMRU:
- if (put_user(ap->mru, (int *) arg))
- break;
- err = 0;
- break;
- case PPPIOCSMRU:
- if (get_user(val, (int *) arg))
- break;
- if (val < PPP_MRU)
- val = PPP_MRU;
- ap->mru = val;
- err = 0;
- break;
-
- case PPPIOCATTACH:
- if (get_user(val, (int *) arg))
- break;
- err = -EALREADY;
- if (ap->connected)
- break;
- ap->chan.private = ap;
- ap->chan.ops = &sync_ops;
- err = ppp_register_channel(&ap->chan);
- if (err != 0)
- break;
- ap->connected = 1;
- break;
- case PPPIOCDETACH:
+ case PPPIOCGUNIT:
err = -ENXIO;
- if (!ap->connected)
+ if (ap == 0)
+ break;
+ err = -EFAULT;
+ if (put_user(ppp_channel_index(&ap->chan), (int *) arg))
break;
- ppp_unregister_channel(&ap->chan);
- ap->connected = 0;
err = 0;
break;
@@ -460,8 +286,6 @@ ppp_sync_ioctl(struct tty_struct *tty, struct file *file,
case TCFLSH:
/* flush our buffers and the serial port's buffer */
- if (arg == TCIFLUSH || arg == TCIOFLUSH)
- flush_skb_queue(&ap->rq);
if (arg == TCIOFLUSH || arg == TCOFLUSH)
ppp_sync_flush_output(ap);
err = n_tty_ioctl(tty, file, cmd, arg);
@@ -469,17 +293,39 @@ ppp_sync_ioctl(struct tty_struct *tty, struct file *file,
case FIONREAD:
val = 0;
- if ((skb = skb_peek(&ap->rq)) != 0)
- val = skb->len;
if (put_user(val, (int *) arg))
break;
err = 0;
break;
+ /*
+ * Compatibility calls until pppd is updated.
+ */
+ case PPPIOCGFLAGS:
+ case PPPIOCSFLAGS:
+ case PPPIOCGASYNCMAP:
+ case PPPIOCSASYNCMAP:
+ case PPPIOCGRASYNCMAP:
+ case PPPIOCSRASYNCMAP:
+ case PPPIOCGXASYNCMAP:
+ case PPPIOCSXASYNCMAP:
+ case PPPIOCGMRU:
+ case PPPIOCSMRU:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ break;
+ err = ppp_sync_ioctl(&ap->chan, cmd, arg);
+ break;
+
+ case PPPIOCATTACH:
+ case PPPIOCDETACH:
+ err = ppp_channel_ioctl(&ap->chan, cmd, arg);
+ break;
+
default:
err = -ENOIOCTLCMD;
}
- out:
+
return err;
}
@@ -489,12 +335,10 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
struct syncppp *ap = tty->disc_data;
unsigned int mask;
- if (ap == 0)
- return 0; /* should never happen */
- poll_wait(file, &ap->rwait, wait);
mask = POLLOUT | POLLWRNORM;
- if (skb_peek(&ap->rq))
- mask |= POLLIN | POLLRDNORM;
+ /* compatibility for old pppd */
+ if (ap != 0)
+ mask |= ppp_channel_poll(&ap->chan, file, wait);
if (test_bit(TTY_OTHER_CLOSED, &tty->flags) || tty_hung_up_p(file))
mask |= POLLHUP;
return mask;
@@ -514,9 +358,9 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
if (ap == 0)
return;
- trylock_recv_path(ap);
+ spin_lock_bh(&ap->recv_lock);
ppp_sync_input(ap, buf, flags, count);
- unlock_recv_path(ap);
+ spin_unlock_bh(&ap->recv_lock);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
&& tty->driver.unthrottle)
tty->driver.unthrottle(tty);
@@ -530,7 +374,7 @@ ppp_sync_wakeup(struct tty_struct *tty)
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (ap == 0)
return;
- if (ppp_sync_push(ap) && ap->connected)
+ if (ppp_sync_push(ap))
ppp_output_wakeup(&ap->chan);
}
@@ -542,7 +386,7 @@ static struct tty_ldisc ppp_sync_ldisc = {
close: ppp_sync_close,
read: ppp_sync_read,
write: ppp_sync_write,
- ioctl: ppp_sync_ioctl,
+ ioctl: ppp_synctty_ioctl,
poll: ppp_sync_poll,
receive_room: ppp_sync_room,
receive_buf: ppp_sync_receive,
@@ -562,54 +406,133 @@ ppp_sync_init(void)
}
/*
+ * The following routines provide the PPP channel interface.
+ */
+static int
+ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
+{
+ struct syncppp *ap = chan->private;
+ int err, val;
+ u32 accm[8];
+
+ err = -EFAULT;
+ switch (cmd) {
+ case PPPIOCGFLAGS:
+ val = ap->flags | ap->rbits;
+ if (put_user(val, (int *) arg))
+ break;
+ err = 0;
+ break;
+ case PPPIOCSFLAGS:
+ if (get_user(val, (int *) arg))
+ break;
+ ap->flags = val & ~SC_RCV_BITS;
+ spin_lock_bh(&ap->recv_lock);
+ ap->rbits = val & SC_RCV_BITS;
+ spin_unlock_bh(&ap->recv_lock);
+ err = 0;
+ break;
+
+ case PPPIOCGASYNCMAP:
+ if (put_user(ap->xaccm[0], (u32 *) arg))
+ break;
+ err = 0;
+ break;
+ case PPPIOCSASYNCMAP:
+ if (get_user(ap->xaccm[0], (u32 *) arg))
+ break;
+ err = 0;
+ break;
+
+ case PPPIOCGRASYNCMAP:
+ if (put_user(ap->raccm, (u32 *) arg))
+ break;
+ err = 0;
+ break;
+ case PPPIOCSRASYNCMAP:
+ if (get_user(ap->raccm, (u32 *) arg))
+ break;
+ err = 0;
+ break;
+
+ case PPPIOCGXASYNCMAP:
+ if (copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm)))
+ break;
+ err = 0;
+ break;
+ case PPPIOCSXASYNCMAP:
+ if (copy_from_user(accm, (void *) arg, sizeof(accm)))
+ break;
+ accm[2] &= ~0x40000000U; /* can't escape 0x5e */
+ accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */
+ memcpy(ap->xaccm, accm, sizeof(ap->xaccm));
+ err = 0;
+ break;
+
+ case PPPIOCGMRU:
+ if (put_user(ap->mru, (int *) arg))
+ break;
+ err = 0;
+ break;
+ case PPPIOCSMRU:
+ if (get_user(val, (int *) arg))
+ break;
+ if (val < PPP_MRU)
+ val = PPP_MRU;
+ ap->mru = val;
+ err = 0;
+ break;
+
+ default:
+ err = -ENOTTY;
+ }
+ return err;
+}
+
+/*
* Procedures for encapsulation and framing.
*/
struct sk_buff*
-ppp_sync_txdequeue(struct syncppp *ap)
+ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
{
int proto;
unsigned char *data;
int islcp;
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&ap->xq)) != NULL) {
-
- data = skb->data;
- proto = (data[0] << 8) + data[1];
-
- /* LCP packets with codes between 1 (configure-request)
- * and 7 (code-reject) must be sent as though no options
- * have been negotiated.
- */
- islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;
-
- /* compress protocol field if option enabled */
- if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp)
- skb_pull(skb,1);
-
- /* prepend address/control fields if necessary */
- if ((ap->flags & SC_COMP_AC) == 0 || islcp) {
- if (skb_headroom(skb) < 2) {
- struct sk_buff *npkt = dev_alloc_skb(skb->len + 2);
- if (npkt == NULL) {
- kfree_skb(skb);
- continue;
- }
- skb_reserve(npkt,2);
- memcpy(skb_put(npkt,skb->len), skb->data, skb->len);
+ data = skb->data;
+ proto = (data[0] << 8) + data[1];
+
+ /* LCP packets with codes between 1 (configure-request)
+ * and 7 (code-reject) must be sent as though no options
+ * have been negotiated.
+ */
+ islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;
+
+ /* compress protocol field if option enabled */
+ if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp)
+ skb_pull(skb,1);
+
+ /* prepend address/control fields if necessary */
+ if ((ap->flags & SC_COMP_AC) == 0 || islcp) {
+ if (skb_headroom(skb) < 2) {
+ struct sk_buff *npkt = dev_alloc_skb(skb->len + 2);
+ if (npkt == NULL) {
kfree_skb(skb);
- skb = npkt;
+ return NULL;
}
- skb_push(skb,2);
- skb->data[0] = PPP_ALLSTATIONS;
- skb->data[1] = PPP_UI;
+ skb_reserve(npkt,2);
+ memcpy(skb_put(npkt,skb->len), skb->data, skb->len);
+ kfree_skb(skb);
+ skb = npkt;
}
-
- ap->last_xmit = jiffies;
- break;
+ skb_push(skb,2);
+ skb->data[0] = PPP_ALLSTATIONS;
+ skb->data[1] = PPP_UI;
}
+ ap->last_xmit = jiffies;
+
if (skb && ap->flags & SC_LOG_OUTPKT)
ppp_print_buffer ("send buffer", skb->data, skb->len);
@@ -633,9 +556,13 @@ ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb)
ppp_sync_push(ap);
- if (test_and_set_bit(XMIT_FULL, &ap->busy))
+ if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags))
return 0; /* already full */
- skb_queue_head(&ap->xq,skb);
+ skb = ppp_sync_txmunge(ap, skb);
+ if (skb != NULL)
+ ap->tpkt = skb;
+ else
+ clear_bit(XMIT_FULL, &ap->xmit_flags);
ppp_sync_push(ap);
return 1;
@@ -651,20 +578,13 @@ ppp_sync_push(struct syncppp *ap)
struct tty_struct *tty = ap->tty;
int tty_stuffed = 0;
- if (!trylock_xmit_path(ap)) {
- set_bit(XMIT_WAKEUP, &ap->busy);
+ set_bit(XMIT_WAKEUP, &ap->xmit_flags);
+ if (!spin_trylock_bh(&ap->xmit_lock))
return 0;
- }
for (;;) {
- if (test_and_clear_bit(XMIT_WAKEUP, &ap->busy))
+ if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))
tty_stuffed = 0;
- if (ap->tpkt == 0) {
- if ((ap->tpkt = ppp_sync_txdequeue(ap)) == 0) {
- clear_bit(XMIT_FULL, &ap->busy);
- done = 1;
- }
- }
- if (!tty_stuffed && ap->tpkt != NULL) {
+ if (!tty_stuffed && ap->tpkt != 0) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->driver.write(tty, 0, ap->tpkt->data, ap->tpkt->len);
if (sent < 0)
@@ -674,15 +594,17 @@ ppp_sync_push(struct syncppp *ap)
} else {
kfree_skb(ap->tpkt);
ap->tpkt = 0;
+ clear_bit(XMIT_FULL, &ap->xmit_flags);
+ done = 1;
}
continue;
}
/* haven't made any progress */
- unlock_xmit_path(ap);
- if (!(test_bit(XMIT_WAKEUP, &ap->busy)
+ spin_unlock_bh(&ap->xmit_lock);
+ if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags)
|| (!tty_stuffed && ap->tpkt != 0)))
break;
- if (!trylock_xmit_path(ap))
+ if (!spin_trylock_bh(&ap->xmit_lock))
break;
}
return done;
@@ -691,10 +613,10 @@ flush:
if (ap->tpkt != 0) {
kfree_skb(ap->tpkt);
ap->tpkt = 0;
- clear_bit(XMIT_FULL, &ap->busy);
+ clear_bit(XMIT_FULL, &ap->xmit_flags);
done = 1;
}
- unlock_xmit_path(ap);
+ spin_unlock_bh(&ap->xmit_lock);
return done;
}
@@ -707,16 +629,15 @@ ppp_sync_flush_output(struct syncppp *ap)
{
int done = 0;
- flush_skb_queue(&ap->xq);
- lock_xmit_path(ap);
+ spin_lock_bh(&ap->xmit_lock);
if (ap->tpkt != NULL) {
kfree_skb(ap->tpkt);
ap->tpkt = 0;
- clear_bit(XMIT_FULL, &ap->busy);
+ clear_bit(XMIT_FULL, &ap->xmit_flags);
done = 1;
}
- unlock_xmit_path(ap);
- if (done && ap->connected)
+ spin_unlock_bh(&ap->xmit_lock);
+ if (done)
ppp_output_wakeup(&ap->chan);
}
@@ -750,30 +671,13 @@ process_input_packet(struct syncppp *ap)
} else if (skb->len < 2)
goto err;
- /* pass to generic layer or queue it */
- if (ap->connected) {
- ppp_input(&ap->chan, skb);
- } else {
- skb_queue_tail(&ap->rq, skb);
- /* drop old frames if queue too long */
- while (ap->rq.qlen > PPPSYNC_MAX_RQLEN
- && (skb = skb_dequeue(&ap->rq)) != 0)
- kfree(skb);
- wake_up_interruptible(&ap->rwait);
- }
+ /* pass to generic layer */
+ ppp_input(&ap->chan, skb);
return;
err:
kfree_skb(skb);
- if (ap->connected)
- ppp_input_error(&ap->chan, code);
-}
-
-static inline void
-input_error(struct syncppp *ap, int code)
-{
- if (ap->connected)
- ppp_input_error(&ap->chan, code);
+ ppp_input_error(&ap->chan, code);
}
/* called when the tty driver has data for us.
@@ -794,7 +698,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
/* if flag set, then error, ignore frame */
if (flags != 0 && *flags) {
- input_error(ap, *flags);
+ ppp_input_error(&ap->chan, *flags);
return;
}
@@ -805,7 +709,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
if ((skb = ap->rpkt) == 0) {
if ((skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2)) == 0) {
printk(KERN_ERR "PPPsync: no memory (input pkt)\n");
- input_error(ap, 0);
+ ppp_input_error(&ap->chan, 0);
return;
}
/* Try to get the payload 4-byte aligned */
@@ -815,7 +719,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
}
if (count > skb_tailroom(skb)) {
/* packet overflowed MRU */
- input_error(ap, 1);
+ ppp_input_error(&ap->chan, 1);
} else {
sp = skb_put(skb, count);
memcpy(sp, buf, count);
@@ -823,17 +727,12 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
}
}
-#ifdef MODULE
-int
-init_module(void)
-{
- return ppp_sync_init();
-}
-
-void
-cleanup_module(void)
+void __exit
+ppp_sync_cleanup(void)
{
if (tty_register_ldisc(N_SYNC_PPP, NULL) != 0)
printk(KERN_ERR "failed to unregister Sync PPP line discipline\n");
}
-#endif /* MODULE */
+
+module_init(ppp_sync_init);
+module_exit(ppp_sync_cleanup);
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index f6710a0b5..2fb6a6970 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -412,21 +412,6 @@ static int __init skge_probe (void)
pci_set_master(pdev);
-#ifdef __sparc__
- /* Set the proper cache line size value, plus enable
- * write-invalidate and fast back-to-back on Sparc.
- */
- {
- SK_U16 pci_command;
-
- SkPciWriteCfgByte(pAC, PCI_CACHE_LINE_SIZE, 0x10);
-
- SkPciReadCfgWord(pAC, PCI_COMMAND, &pci_command);
- pci_command |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK);
- SkPciWriteCfgWord(pAC, PCI_COMMAND, pci_command);
- }
-#endif
-
base_address = pdev->resource[0].start;
#ifdef SK_BIG_ENDIAN
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index d4f6e5b19..70884ec53 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.94 2000/03/15 06:47:04 davem Exp $
+/* $Id: sunhme.c,v 1.95 2000/03/25 05:18:15 davem Exp $
* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -2688,7 +2688,6 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
struct pcidev_cookie *pcp;
struct happy_meal *hp;
unsigned long hpreg_base;
- unsigned short pci_command;
int i, node, qfe_slot = -1;
char prom_name[64];
@@ -2845,20 +2844,6 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
ether_setup(dev);
- /* If we don't do this, nothing works. */
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- pci_command |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
- /* Set the latency timer and cache line size as well,
- * PROM leaves it at zero.
- */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
- /* NOTE: Cache line size is in 32-bit word units. */
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
#ifdef MODULE
/* We are home free at this point, link us in to the happy
* module device list.
diff --git a/drivers/net/tokenring/Config.in b/drivers/net/tokenring/Config.in
index 316b638c2..44c53682c 100644
--- a/drivers/net/tokenring/Config.in
+++ b/drivers/net/tokenring/Config.in
@@ -14,7 +14,9 @@ if [ "$CONFIG_TR" != "n" ]; then
if [ "$CONFIG_TMS380TR" != "n" ]; then
dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR
dep_tristate ' Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR
- dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR
+ if [ "$CONFIG_MCA" = "y" ]; then
+ dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR
+ fi
fi
dep_tristate ' SMC ISA/MCA adapter support' CONFIG_SMCTR $CONFIG_TR
fi
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 0dfffbc8e..f206a44f9 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -88,6 +88,9 @@
* to support windowing into on adapter shared ram.
* i.e. Use LANAID to setup a PnP configuration with 16K RAM. Paging
* will shift this 16K window over the entire available shared RAM.
+ *
+ * Changes by Peter De Schrijver (p2@mind.be) :
+ * + fixed a problem with PCMCIA card removal
*/
/* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value
@@ -95,16 +98,8 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */
#define IBMTR_DEBUG_MESSAGES 0
-#ifdef PCMCIA
-#define MODULE
-#endif
-
#include <linux/module.h>
-#ifdef PCMCIA
-#undef MODULE
-#endif
-
#define NO_AUTODETECT 1
#undef NO_AUTODETECT
/* #undef ENABLE_PAGING */
@@ -161,13 +156,13 @@ static char mcchannelid[] = {
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/ibmtr.h>
#include <net/checksum.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/bitops.h>
-#include "ibmtr.h"
#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
@@ -814,6 +809,9 @@ static void tok_set_multicast_list(struct net_device *dev)
int i;
+ if(ti->open_status==CLOSED)
+ return;
+
address[0] = address[1] = address[2] = address[3] = 0;
mclist = dev->mc_list;
@@ -870,26 +868,28 @@ static int tok_close(struct net_device *dev)
struct tok_info *ti=(struct tok_info *) dev->priv;
- netif_stop_queue(dev);
- SET_PAGE(ti->srb_page);
- isa_writeb(DIR_CLOSE_ADAPTER,
- ti->srb + offsetof(struct srb_close_adapter, command));
- isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+ if(ti->open_status!=CLOSED) {
+ netif_stop_queue(dev);
+ SET_PAGE(ti->srb_page);
+ isa_writeb(DIR_CLOSE_ADAPTER,
+ ti->srb + offsetof(struct srb_close_adapter, command));
+ isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
- ti->open_status=CLOSED;
+ ti->open_status=CLOSED;
- sleep_on(&ti->wait_for_tok_int);
+ sleep_on(&ti->wait_for_tok_int);
- SET_PAGE(ti->srb_page);
- if (isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
- DPRINTK("close adapter failed: %02X\n",
- (int)isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
+ SET_PAGE(ti->srb_page);
+ if (isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
+ DPRINTK("close adapter failed: %02X\n",
+ (int)isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
#ifdef PCMCIA
- ti->sram = 0 ;
+ ti->sram = 0 ;
#endif
- DPRINTK("Adapter closed.\n");
- MOD_DEC_USE_COUNT;
+ DPRINTK("Adapter closed.\n");
+ MOD_DEC_USE_COUNT;
+ }
return 0;
}
@@ -937,6 +937,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
if (status == 0xFF)
{
DPRINTK("PCMCIA card removed.\n");
+ ti->open_status=CLOSED;
goto return_point ;
}
@@ -944,6 +945,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
if ( isa_readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
{
DPRINTK("PCMCIA card removed.\n");
+ ti->open_status=CLOSED;
goto return_point ;
}
#endif
@@ -1851,6 +1853,7 @@ int ibmtr_change_mtu(struct net_device *dev, int mtu) {
return 0;
}
+#ifndef PCMCIA
#ifdef MODULE
/* 3COM 3C619C supports 8 interrupts, 32 I/O ports */
@@ -1908,3 +1911,4 @@ void cleanup_module(void)
}
}
#endif /* MODULE */
+#endif
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index 491b04057..a588bb6ec 100644
--- a/drivers/net/wan/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
@@ -48,14 +48,8 @@
* Aug 8, 1998 acme Initial version.
*/
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
+#include <linux/init.h> /* __init */
#include <linux/module.h>
-#else
-#define EXPORT_SYMBOL(function)
-#endif
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
@@ -66,12 +60,10 @@
#include <asm/io.h> /* read[wl], write[wl], ioremap, iounmap */
#define MOD_VERSION 0
-#define MOD_RELEASE 5
+#define MOD_RELEASE 6
-#ifdef MODULE
MODULE_AUTHOR("Arnaldo Carvalho de Melo");
MODULE_DESCRIPTION("Cyclom 2x Sync Card Driver");
-#endif
/* Function Prototypes */
/* Module entry points. These are called by the OS and must be public. */
@@ -129,20 +121,21 @@ static u32 cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 };
* Return: 0 Ok
* < 0 error.
* Context: process */
-#ifdef MODULE
-int init_module(void)
+
+int __init cycx_drv_init(void)
{
printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE,
copyright);
return 0;
}
+
/* Module 'remove' entry point.
* o release all remaining system resources */
-void cleanup_module(void)
+void cycx_drv_cleanup(void)
{
}
-#endif
+
/* Kernel APIs */
/* Set up adapter.
* o detect adapter type
@@ -599,4 +592,8 @@ static u16 checksum(u8 *buf, u32 len)
return crc;
}
+
+module_init(cycx_drv_init);
+module_exit(cycx_drv_cleanup);
+
/* End */
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 188b06c97..ae501781b 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -13,6 +13,8 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* 2000/04/02 acme dprintk and cycx_debug
+* module_init/module_exit
* 2000/01/21 acme rename cyclomx_open to cyclomx_mod_inc_use_count
* and cyclomx_close to cyclomx_mod_dec_use_count
* 2000/01/08 acme cleanup
@@ -43,15 +45,21 @@
#include <asm/uaccess.h> /* kernel <-> user copy */
#include <linux/init.h> /* __init (when not using as a module) */
+/* Debug */
+
+unsigned int cycx_debug = 0;
+
#ifdef MODULE
MODULE_AUTHOR("Arnaldo Carvalho de Melo");
MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "cyclomx debug level");
#endif
/* Defines & Macros */
#define DRV_VERSION 0 /* version number */
-#define DRV_RELEASE 6 /* release (minor version) number */
+#define DRV_RELEASE 7 /* release (minor version) number */
#define MAX_CARDS 1 /* max number of adapters */
#ifndef CONFIG_CYCLOMX_CARDS /* configurable option */
@@ -60,10 +68,6 @@ MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
/* Function Prototypes */
-/* Module entry points */
-int init_module (void);
-void cleanup_module (void);
-
/* WAN link driver entry points */
static int setup (wan_device_t *wandev, wandev_conf_t *conf);
static int shutdown (wan_device_t *wandev);
@@ -98,11 +102,7 @@ static cycx_t *card_array = NULL; /* adapter data space */
* < 0 error.
* Context: process
*/
-#ifdef MODULE
-int init_module (void)
-#else
int __init cyclomx_init (void)
-#endif
{
int cnt, err = 0;
@@ -156,8 +156,7 @@ int __init cyclomx_init (void)
* o unregister all adapters from the WAN router
* o release all remaining system resources
*/
-#ifdef MODULE
-void cleanup_module (void)
+void cyclomx_cleanup (void)
{
int i = 0;
@@ -168,7 +167,7 @@ void cleanup_module (void)
kfree(card_array);
}
-#endif
+
/* WAN Device Driver Entry Points */
/*
* Setup/configure WAN link driver.
@@ -385,4 +384,7 @@ void cyclomx_set_state (cycx_t *card, int state)
spin_unlock_irqrestore(&card->lock, host_cpu_flags);
}
+module_init(cyclomx_init);
+module_exit(cyclomx_cleanup);
+
/* End */
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index e56125734..f3669aaf9 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -12,6 +12,10 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* 2000/04/02 acme dprintk, cycx_debug
+* fixed the bug introduced in get_dev_by_lcn and
+* get_dev_by_dte_addr by the anonymous hacker
+* that converted this driver to softnet
* 2000/01/08 acme cleanup
* 1999/10/27 acme use ARPHRD_HWX25 so that the X.25 stack know
* that we have a X.25 stack implemented in
@@ -110,7 +114,7 @@ typedef struct x25_channel {
u32 idle_tmout; /* sec, before disconnecting */
struct sk_buff *rx_skb; /* receive socket buffer */
cycx_t *card; /* -> owner */
- struct enet_statistics ifstats; /* interface statistics */
+ struct net_device_stats ifstats;/* interface statistics */
} x25_channel_t;
/* Function Prototypes */
@@ -178,13 +182,11 @@ static void hex_dump(char *msg, unsigned char *p, int len);
static void x25_dump_config(TX25Config *conf);
static void x25_dump_stats(TX25Stats *stats);
static void x25_dump_devs(wan_device_t *wandev);
-#define dprintk(format, a...) printk(format, ##a)
#else
#define hex_dump(msg, p, len)
#define x25_dump_config(conf)
#define x25_dump_stats(stats)
#define x25_dump_devs(wandev)
-#define dprintk(format, a...)
#endif
/* Public Functions */
@@ -846,7 +848,7 @@ static void connect_intr (cycx_t *card, TX25Cmd *cmd)
if (sizerem)
nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
- dprintk(KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n",
+ dprintk(1, KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n",
lcn, loc, rem);
if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) {
@@ -872,7 +874,7 @@ static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
- dprintk(KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n",
+ dprintk(1, KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n",
card->devname, lcn, key);
if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) {
@@ -897,7 +899,7 @@ static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
u8 lcn;
cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
- dprintk(KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",
+ dprintk(1, KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",
card->devname, lcn);
if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
/* Invalid channel, discard packet */
@@ -917,7 +919,7 @@ static void disconnect_intr (cycx_t *card, TX25Cmd *cmd)
u8 lcn;
cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
- dprintk(KERN_INFO "disconnect_intr:lcn=%d\n", lcn);
+ dprintk(1, KERN_INFO "disconnect_intr:lcn=%d\n", lcn);
if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
x25_channel_t *chan = dev->priv;
@@ -1172,7 +1174,7 @@ static int x25_place_call (cycx_t *card, x25_channel_t *chan)
key = ffz(card->u.x.connection_keys);
set_bit(key, (void*)&card->u.x.connection_keys);
++key;
- dprintk(KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
+ dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
memset(d, 0, sizeof(d));
d[1] = key; /* user key */
d[2] = 0x10;
@@ -1259,6 +1261,8 @@ static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
x25_channel_t *chan;
while (dev) {
+ chan = (x25_channel_t*)dev->priv;
+
if (chan->lcn == lcn)
break;
dev = chan->slave;
@@ -1273,6 +1277,8 @@ static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
x25_channel_t *chan;
while (dev) {
+ chan = (x25_channel_t*)dev->priv;
+
if (!strcmp(chan->addr, dte))
break;
dev = chan->slave;
@@ -1296,7 +1302,7 @@ static int chan_connect (struct net_device *dev)
if (!chan->addr[0])
return -EINVAL; /* no destination address */
- dprintk(KERN_INFO "%s: placing X.25 call to %s...\n",
+ dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",
card->devname, chan->addr);
if (x25_place_call(card, chan))
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index f1c618a90..7b369c004 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -1316,7 +1316,7 @@ EXPORT_SYMBOL(z8530_shutdown);
* @rtable: Table of register, value pairs
* FIXME: ioctl to allow user uploaded tables
*
- * Load a Z8530 channel up from the system data> We use +16 to
+ * Load a Z8530 channel up from the system data. We use +16 to
* indicate the 'prime' registers. The value 255 terminates the
* table
*/
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index e8bd316e6..b2f122af0 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -1,3 +1,8 @@
+2000-03-27 Tim Waugh <twaugh@redhat.com>
+
+ * parport_pc.c (parport_pc_ecp_read_block_pio): Correct operation
+ when peripheral is trying to send data when we stop listening.
+
2000-03-22 Tim Waugh <twaugh@redhat.com>
* init.c (parport_setup): Fix return value.
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 16b5ea3fe..5b912d3ef 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -178,9 +178,6 @@ static int get_fifo_residue (struct parport *p)
int cnfga;
const struct parport_pc_private *priv = p->physport->private_data;
- /* Prevent further data transfer. */
- frob_econtrol (p, 0xe0, ECR_TST << 5);
-
/* Adjust for the contents of the FIFO. */
for (residue = priv->fifo_depth; ; residue--) {
if (inb (ECONTROL (p)) & 0x2)
@@ -862,7 +859,8 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
length, flags);
/* Switch to reverse mode if necessary. */
- if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
+ if ((port->ieee1284.phase != IEEE1284_PH_REV_IDLE) &&
+ (port->ieee1284.phase != IEEE1284_PH_REV_DATA)) {
/* Event 38: Set nAutoFd low */
parport_frob_control (port,
PARPORT_CONTROL_AUTOFD,
@@ -879,7 +877,7 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
}
- /* Set up ECP parallel port mode.*/
+ /* Set up ECP FIFO mode.*/
parport_pc_data_reverse (port); /* Must be in PS2 mode */
parport_pc_frob_control (port,
PARPORT_CONTROL_STROBE |
@@ -951,15 +949,24 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
left--;
}
+ port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+
+ /* Go to forward idle mode to shut the peripheral up. */
+ parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
/* Finish up. */
- if (change_mode (port, ECR_PS2) == -EBUSY) {
+ {
int lost = get_fifo_residue (port);
- printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
- lost);
+ if (lost)
+ /* Shouldn't happen with compliant peripherals. */
+ printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
+ port->name, lost);
}
- port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-
return length - left;
}
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index c1cdd3d9a..6cafbc11a 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -1,4 +1,4 @@
-/* $Id: parport_sunbpp.c,v 1.9 1999/10/14 05:59:43 ecd Exp $
+/* $Id: parport_sunbpp.c,v 1.10 2000/03/27 01:47:56 anton Exp $
* Parallel-port routines for Sun architecture
*
* Author: Derrick J. Brashear <shadow@dementia.org>
@@ -335,6 +335,8 @@ static int __init init_one_port(struct sbus_dev *sdev)
return 0;
}
+ p->size = size;
+
dprintk(("init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index fe5ea143b..27cd907e1 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -103,6 +103,19 @@ static void get_lowlevel_driver (void)
request_module ("parport_lowlevel");
}
+/**
+ * parport_register_driver - register a parallel port device driver
+ * @drv: structure describing the driver
+ *
+ * This can be called by a parallel port device driver in order to
+ * receive notifications about ports being found in the system, as
+ * well as ports no longer available.
+ *
+ * The @drv structure is allocated by the caller and must not be
+ * deallocated until after calling parport_unregister_driver().
+ *
+ * Returns 0 on success. Currently it always succeeds.
+ **/
int parport_register_driver (struct parport_driver *drv)
{
struct parport *port;
@@ -121,6 +134,23 @@ int parport_register_driver (struct parport_driver *drv)
return 0;
}
+/**
+ * parport_unregister_driver - deregister a parallel port device driver
+ * @arg: structure describing the driver that was given to
+ * parport_register_driver()
+ *
+ * This should be called by a parallel port device driver that has
+ * registered itself using parport_register_driver() when it is about
+ * to be unloaded.
+ *
+ * When it returns, the driver's attach() routine will no longer be
+ * called, and for each port that attach() was called for, the
+ * detach() routine will hae been called.
+ *
+ * If the caller's attach() function can block, it is their
+ * responsibility to make sure to wait for it to exit before
+ * unloading.
+ **/
void parport_unregister_driver (struct parport_driver *arg)
{
struct parport_driver *drv = driver_chain, *olddrv = NULL;
@@ -149,8 +179,17 @@ void parport_unregister_driver (struct parport_driver *arg)
}
}
-/* Return a list of all the ports we know about. This function shouldn't
- * really be used -- use parport_register_driver instead. */
+/**
+ * parport_enumerate - return a list of the system's parallel ports
+ *
+ * This returns the head of the list of parallel ports in the system.
+ * The structure that is returned describes the first port in the
+ * list, and its 'next' member points to the next port, or %NULL if
+ * it's the last port.
+ *
+ * If there are no parallel ports in the system, parport_enumerate()
+ * will return %NULL.
+ **/
struct parport *parport_enumerate(void)
{
if (!portlist)
@@ -159,6 +198,33 @@ struct parport *parport_enumerate(void)
return portlist;
}
+/**
+ * parport_register_port - register a parallel port
+ * @base: base I/O address
+ * @irq: IRQ line
+ * @dma: DMA channel
+ * @ops: pointer to the port driver's port operations structure
+ *
+ * When a parallel port (lowlevel) driver finds a port that should be
+ * made available to parallel port device drivers, it should call
+ * parport_register_port(). The @base, @irq, and @dma parameters are
+ * for the convenience of port drivers, and for ports where they
+ * aren't meaningful needn't be set to anything special. They can be
+ * altered afterwards by adjusting the relevant members of the parport
+ * structure that is returned and represents the port. They should
+ * not be tampered with after calling parport_announce_port, however.
+ *
+ * If there are parallel port device drivers in the system that have
+ * registered themselves using parport_register_driver(), they are not
+ * told about the port at this time; that is done by
+ * parport_announce_port().
+ *
+ * The @ops structure is allocated by the caller, and must not be
+ * deallocated before calling parport_unregister_port().
+ *
+ * If there is no memory to allocate a new parport structure, this
+ * function will return %NULL.
+ **/
struct parport *parport_register_port(unsigned long base, int irq, int dma,
struct parport_operations *ops)
{
@@ -243,6 +309,17 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
return tmp;
}
+/**
+ * parport_announce_port - tell device drivers about a parallel port
+ * @port: parallel port to announce
+ *
+ * After a port driver has registered a parallel port with
+ * parport_register_port, and performed any necessary initialisation
+ * or adjustments, it should call parport_announce_port() in order to
+ * notify all device drivers that have called
+ * parport_register_driver(). Their attach() functions will be
+ * called, with @port as the parameter.
+ **/
void parport_announce_port (struct parport *port)
{
#ifdef CONFIG_PARPORT_1284
@@ -286,6 +363,23 @@ static void free_port (struct parport *port)
kfree(port);
}
+/**
+ * parport_unregister_port - deregister a parallel port
+ * @port: parallel port to deregister
+ *
+ * When a parallel port driver is forcibly unloaded, or a parallel
+ * port becomes inaccessible, the port driver must call this function
+ * in order to deal with device drivers that still want to use it.
+ *
+ * The parport structure associated with the port has its operations
+ * structure replaced with one containing 'null' operations that
+ * return errors or just don't do anything.
+ *
+ * Any drivers that have registered themselves using
+ * parport_register_driver() are notified that the port is no longer
+ * accessible by having their detach() routines called with @port as
+ * the parameter.
+ **/
void parport_unregister_port(struct parport *port)
{
struct parport *p;
@@ -320,10 +414,76 @@ void parport_unregister_port(struct parport *port)
free_port (port);
}
-struct pardevice *parport_register_device(struct parport *port, const char *name,
- int (*pf)(void *), void (*kf)(void *),
- void (*irq_func)(int, void *, struct pt_regs *),
- int flags, void *handle)
+/**
+ * parport_register_device - register a device on a parallel port
+ * @port: port to which the device is attached
+ * @name: a name to refer to the device
+ * @pf: preemption callback
+ * @kf: kick callback (wake-up)
+ * @irq_func: interrupt handler
+ * @flags: registration flags
+ * @handle: data for callback functions
+ *
+ * This function, called by parallel port device drivers, declares
+ * that a device is connected to a port, and tells the system all it
+ * needs to know.
+ *
+ * The @name is allocated by the caller and must not be deallocated
+ * until the caller calls @parport_unregister_device for that device.
+ *
+ * The preemption callback function, @pf, is called when this device
+ * driver has claimed access to the port but another device driver
+ * wants to use it. It is given @handle as its parameter, and should
+ * return zero if it is willing for the system to release the port to
+ * another driver on its behalf. If it wants to keep control of the
+ * port it should return non-zero, and no action will be taken. It is
+ * good manners for the driver to try to release the port at the
+ * earliest opportunity after its preemption callback rejects a
+ * preemption attempt. Note that if a preemption callback is happy
+ * for preemption to go ahead, there is no need to release the port;
+ * it is done automatically. This function may not block, as it may
+ * be called from interrupt context. If the device driver does not
+ * support preemption, @pf can be %NULL.
+ *
+ * The wake-up ("kick") callback function, @kf, is called when the
+ * port is available to be claimed for exclusive access; that is,
+ * parport_claim() is guaranteed to succeed when called from inside
+ * the wake-up callback function. If the driver wants to claim the
+ * port it should do so; otherwise, it need not take any action. This
+ * function may not block, as it may be called from interrupt context.
+ * If the device driver does not want to be explicitly invited to
+ * claim the port in this way, @kf can be %NULL.
+ *
+ * The interrupt handler, @irq_func, is called when an interrupt
+ * arrives from the parallel port. Note that if a device driver wants
+ * to use interrupts it should use parport_enable_irq(), and can also
+ * check the irq member of the parport structure representing the
+ * port.
+ *
+ * The parallel port (lowlevel) driver is the one that has called
+ * request_irq() and whose interrupt handler is called first. This
+ * handler does whatever needs to be done to the hardware to
+ * acknowledge the interrupt (for PC-style ports there is nothing
+ * special to be done). It then tells the IEEE 1284 code about the
+ * interrupt, which may involve reacting to an IEEE 1284 event
+ * depending on the current IEEE 1284 phase. After this, it calls
+ * @irq_func. Needless to say, @irq_func will be called from
+ * interrupt context, and may not block.
+ *
+ * The %PARPORT_DEV_EXCL flag is for preventing port sharing, and so
+ * should only be used when sharing the port with other device drivers
+ * is impossible and would lead to incorrect behaviour. Use it
+ * sparingly! Normally, @flags will be zero.
+ *
+ * This function returns a pointer to a structure that represents the
+ * device on the port, or %NULL if there is not enough memory to
+ * allocate space for that structure.
+ **/
+struct pardevice *
+parport_register_device(struct parport *port, const char *name,
+ int (*pf)(void *), void (*kf)(void *),
+ void (*irq_func)(int, void *, struct pt_regs *),
+ int flags, void *handle)
{
struct pardevice *tmp;
@@ -341,17 +501,25 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
}
}
+ /* We up our own module reference count, and that of the port
+ on which a device is to be registered, to ensure that
+ neither of us gets unloaded while we sleep in (e.g.)
+ kmalloc. To be absolutely safe, we have to require that
+ our caller doesn't sleep in between parport_enumerate and
+ parport_register_device.. */
+ inc_parport_count();
+ port->ops->inc_use_count();
+
tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
if (tmp == NULL) {
printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
- return NULL;
+ goto out;
}
tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
if (tmp->state == NULL) {
printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
- kfree(tmp);
- return NULL;
+ goto out_free_pardevice;
}
tmp->name = name;
@@ -376,12 +544,10 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
if (flags & PARPORT_DEV_EXCL) {
if (port->physport->devices) {
spin_unlock (&port->physport->pardevice_lock);
- kfree (tmp->state);
- kfree (tmp);
printk (KERN_DEBUG
"%s: cannot grant exclusive access for "
"device %s\n", port->name, name);
- return NULL;
+ goto out_free_all;
}
port->flags |= PARPORT_FLAG_EXCL;
}
@@ -392,9 +558,6 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
port->physport->devices = tmp;
spin_unlock(&port->physport->pardevice_lock);
- inc_parport_count();
- port->ops->inc_use_count();
-
init_waitqueue_head(&tmp->wait_q);
tmp->timeslice = parport_default_timeslice;
tmp->waitnext = tmp->waitprev = NULL;
@@ -406,8 +569,23 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
port->ops->init_state(tmp, tmp->state);
parport_device_proc_register(tmp);
return tmp;
+
+ out_free_all:
+ kfree (tmp->state);
+ out_free_pardevice:
+ kfree (tmp);
+ out:
+ dec_parport_count();
+ port->ops->dec_use_count();
+ return NULL;
}
+/**
+ * parport_unregister_device - deregister a device on a parallel port
+ * @dev: pointer to structure representing device
+ *
+ * This undoes the effect of parport_register_device().
+ **/
void parport_unregister_device(struct pardevice *dev)
{
struct parport *port;
@@ -454,6 +632,16 @@ void parport_unregister_device(struct pardevice *dev)
free_port (port);
}
+/**
+ * parport_claim - claim access to a parallel port device
+ * @dev: pointer to structure representing a device on the port
+ *
+ * This function will not block and so can be used from interrupt
+ * context. If parport_claim() succeeds in claiming access to the
+ * port it returns zero and the port is available to use. It may fail
+ * (returning non-zero) if the port is in use by another driver and
+ * that driver is not willing to relinquish control of the port.
+ **/
int parport_claim(struct pardevice *dev)
{
struct pardevice *oldcad;
@@ -555,6 +743,15 @@ blocked:
return -EAGAIN;
}
+/**
+ * parport_claim_or_block - claim access to a parallel port device
+ * @dev: pointer to structure representing a device on the port
+ *
+ * This behaves like parport_claim(), but will block if necessary to
+ * wait for the port to be free. A return value of 1 indicates that
+ * it slept; 0 means that it succeeded without needing to sleep. A
+ * negative error code indicates failure.
+ **/
int parport_claim_or_block(struct pardevice *dev)
{
int r;
@@ -597,6 +794,14 @@ int parport_claim_or_block(struct pardevice *dev)
return r;
}
+/**
+ * parport_release - give up access to a parallel port device
+ * @dev: pointer to structure representing parallel port device
+ *
+ * This function cannot fail, but it should not be called without the
+ * port claimed. Similarly, if the port is already claimed you should
+ * not try claiming it again.
+ **/
void parport_release(struct pardevice *dev)
{
struct parport *port = dev->port->physport;
diff --git a/drivers/pci/gen-devlist.c b/drivers/pci/gen-devlist.c
index ed0bcba16..9b2c652ac 100644
--- a/drivers/pci/gen-devlist.c
+++ b/drivers/pci/gen-devlist.c
@@ -1,12 +1,14 @@
/*
* Generate devlist.h and classlist.h from the PCI ID file.
*
- * (c) 1999 Martin Mares <mj@suse.cz>
+ * (c) 1999--2000 Martin Mares <mj@suse.cz>
*/
#include <stdio.h>
#include <string.h>
+#define MAX_NAME_SIZE 79
+
static void
pq(FILE *f, const char *c)
{
@@ -22,9 +24,11 @@ pq(FILE *f, const char *c)
int
main(void)
{
- char line[1024], *c, vend[8];
+ char line[1024], *c, *bra, vend[8];
int vendors = 0;
int mode = 0;
+ int lino = 0;
+ int vendor_len = 0;
FILE *devf, *clsf;
devf = fopen("devlist.h", "w");
@@ -35,6 +39,7 @@ main(void)
}
while (fgets(line, sizeof(line)-1, stdin)) {
+ lino++;
if ((c = strchr(line, '\n')))
*c = 0;
if (!line[0] || line[0] == '#')
@@ -56,6 +61,16 @@ main(void)
c = line + 5;
while (*c == ' ')
*c++ = 0;
+ if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
+ /* Too long, try cutting off long description */
+ bra = strchr(c, '[');
+ if (bra && bra > c && bra[-1] == ' ')
+ bra[-1] = 0;
+ if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
+ fprintf(stderr, "Line %d: Device name too long\n", lino);
+ return 1;
+ }
+ }
fprintf(devf, "\tDEVICE(%s,%s,\"", vend, line+1);
pq(devf, c);
fputs("\")\n", devf);
@@ -80,13 +95,18 @@ main(void)
fputs("ENDVENDOR()\n\n", devf);
vendors++;
strcpy(vend, line);
+ vendor_len = strlen(c);
+ if (vendor_len + 24 > MAX_NAME_SIZE) {
+ fprintf(stderr, "Line %d: Vendor name too long\n", lino);
+ return 1;
+ }
fprintf(devf, "VENDOR(%s,\"", vend);
pq(devf, c);
fputs("\")\n", devf);
mode = 1;
} else {
err:
- fprintf(stderr, "Syntax error in mode %d: %s\n", mode, line);
+ fprintf(stderr, "Line %d: Syntax error in mode %d: %s\n", lino, mode, line);
return 1;
}
}
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 9dae829b5..cdf4092fe 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -1245,7 +1245,7 @@
10db Rohm LSI Systems, Inc.
10dc CERN/ECP/EDU
0001 STAR/RD24 SCI-PCI (PMC)
- 0002 TAR/RD24 SCI-PCI (PMC) [ATT 2C15-3 (FPGA) SCI bridge on PCI 5 Volt card]
+ 0002 TAR/RD24 SCI-PCI (PMC)
0021 HIPPI destination
0022 HIPPI source
10dc ATT2C15-3 FPGA
@@ -1328,7 +1328,7 @@
8089 Kingsberg Spacetec Serial Output Board
809c S5933_HEPC3
811a PCI-IEEE1355-DS-DE Interface
- 8170 S5933 "Matchmaker" PCI Chipset Development Tool
+ 8170 S5933 "Matchmaker" [PCI Chipset Development Tool]
10e9 Alps Electric Co., Ltd.
10ea Intergraphics Systems
1680 IGA-1680
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 84639a5a2..679b5f49f 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -89,7 +89,7 @@ pci_assign_resource(struct pci_dev *dev, int i)
return 0;
}
-static void
+void
pdev_assign_unassigned_resources(struct pci_dev *dev)
{
u32 reg;
diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx
index 8f4d4f19c..678042b16 100644
--- a/drivers/scsi/ChangeLog.ncr53c8xx
+++ b/drivers/scsi/ChangeLog.ncr53c8xx
@@ -1,3 +1,13 @@
+Sat Apr 1 12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+ * revision 3.2h
+ - Fix a compilation problem on Alpha introduced in version 3.2g.
+ (`port' changed to `base_io').
+ - Move from `sym' to this driver a tiny change for __sparc__ that
+ applies to cache line size (? Probably from David S Miller).
+ - Make sure no data transfer will happen for Scsi_Cmnd requests
+ that supply SCSI_DATA_NONE direction (this avoids some BUG()
+ statement in the PCI code when a data buffer is also supplied).
+
Mon March 6 23:15 2000 Gerard Roudier (groudier@club-internet.fr)
* revision 3.2g
- Add the file sym53c8xx_comm.h that collects code that should
diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx
index 47448ec71..84f7ea1c8 100644
--- a/drivers/scsi/ChangeLog.sym53c8xx
+++ b/drivers/scsi/ChangeLog.sym53c8xx
@@ -1,3 +1,11 @@
+Sat Apr 1 12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+ * revision 1.5l
+ - Tiny change for __sparc__ appeared in 2.3.99-pre4.1 that
+ applies to cache line size (? Probably from David S Miller).
+ - Make sure no data transfer will happen for Scsi_Cmnd requests
+ that supply SCSI_DATA_NONE direction (this avoids some BUG()
+ statement in the PCI code when a data buffer is also supplied).
+
Mon Mar 6 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.5k
- Test against expected data transfer direction from SCRIPTS.
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index b0407de9e..a12560ec9 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -55,7 +55,9 @@ if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS
int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
fi
-dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI
+if [ "$CONFIG_X86" = "y" ]; then
+ dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI
+fi
dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
@@ -65,6 +67,7 @@ dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then
bool ' Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT
fi
+dep_tristate 'DMX3191D SCSI support' CONFIG_SCSI_DMX3191D $CONFIG_SCSI $CONFIG_PCI
dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI
if [ "$CONFIG_SCSI_EATA" != "n" ]; then
@@ -86,10 +89,8 @@ if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
"Port CONFIG_SCSI_G_NCR5380_PORT \
Memory CONFIG_SCSI_G_NCR5380_MEM" Port
fi
-if [ "$CONFIG_PCI" = "y" ]; then
- dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI
- dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI
-fi
+dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI $CONFIG_PCI
+dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI $CONFIG_PCI
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'IOMEGA parallel port (ppa - older drives)' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
dep_tristate 'IOMEGA parallel port (imm - newer drives)' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
@@ -101,13 +102,11 @@ fi
dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
dep_tristate 'symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI
dep_tristate 'Simple 53c710 SCSI support (Compaq, NCR machines)' CONFIG_SCSI_SIM710 $CONFIG_SCSI
-if [ "$CONFIG_PCI" = "y" ]; then
- dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI
- if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then
- bool ' always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync
- bool ' allow FAST-SCSI [10MHz]' CONFIG_SCSI_NCR53C7xx_FAST
- bool ' allow DISCONNECT' CONFIG_SCSI_NCR53C7xx_DISCONNECT
- fi
+dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI $CONFIG_PCI
+if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then
+ bool ' always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync
+ bool ' allow FAST-SCSI [10MHz]' CONFIG_SCSI_NCR53C7xx_FAST
+ bool ' allow DISCONNECT' CONFIG_SCSI_NCR53C7xx_DISCONNECT
fi
if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
@@ -149,7 +148,9 @@ if [ "$CONFIG_PCI" = "y" ]; then
dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
dep_tristate 'Qlogic QLA 1280 SCSI support' CONFIG_SCSI_QLOGIC_1280 $CONFIG_SCSI
fi
-dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+if [ "$CONFIG_X86" = "y" ]; then
+ dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+fi
if [ "$CONFIG_PCI" = "y" ]; then
dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
if [ "$CONFIG_SCSI_DC390T" != "n" ]; then
@@ -162,7 +163,9 @@ dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
bool ' enable elevator sorting' CONFIG_SCSI_U14_34F_LINKED_COMMANDS
int ' maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
fi
-dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
+if [ "$CONFIG_X86" = "y" ]; then
+ dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
+fi
#
# Note - this is a very special 'host' adapter that simulates the presence of some disks.
# It can come in very handy for troubleshooting. Anyone else is welcome to use it - all
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 81a164066..e5531e006 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -613,6 +613,14 @@ else
endif
endif
+ifeq ($(CONFIG_SCSI_DMX3191D),y)
+L_OBJS += dmx3191d.o
+else
+ ifeq ($(CONFIG_SCSI_DMX3191D),m)
+ M_OBJS += dmx3191d.o
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_DTC3280),y)
L_OBJS += dtc.o
else
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
new file mode 100644
index 000000000..2bc31ea28
--- /dev/null
+++ b/drivers/scsi/dmx3191d.c
@@ -0,0 +1,125 @@
+
+/*
+ dmx3191d.c - midlevel driver for the Domex DMX3191D SCSI card.
+ Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
+
+ Based on the generic NCR5380 driver by Drew Eckhardt et al.
+
+ 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.
+*/
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stat.h>
+#include <linux/version.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+#include "sd.h"
+
+#include "dmx3191d.h"
+
+/* play with these values to tune up your system performances */
+/* default setting from g_NCR5380.c */
+/*
+#define USLEEP
+#define USLEEP_POLL 1
+#define USLEEP_SLEEP 20
+#define USLEEP_WAITLONG 500
+*/
+
+#define AUTOSENSE
+#include "NCR5380.h"
+#include "NCR5380.c"
+
+
+int __init dmx3191d_detect(Scsi_Host_Template *tmpl) {
+ int boards = 0;
+ struct Scsi_Host *instance = NULL;
+ struct pci_dev *pdev = NULL;
+
+ if (!pci_present()) {
+ dmx3191d_printk("PCI support not enabled\n");
+ return 0;
+ }
+
+ tmpl->proc_name = DMX3191D_DRIVER_NAME;
+
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_DOMEX,
+ PCI_DEVICE_ID_DOMEX_DMX3191D, pdev))) {
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
+ unsigned long port = pdev->base_address[0] & PCI_IOADDRESS_MASK;
+#else
+ unsigned long port = pdev->resource[0].start;
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) */
+
+ if (check_region(port, DMX3191D_REGION)) {
+ dmx3191d_printk("region 0x%lx-0x%lx already reserved\n",
+ port, port + DMX3191D_REGION);
+ continue;
+ }
+
+ request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME);
+
+ instance = scsi_register(tmpl, sizeof(struct NCR5380_hostdata));
+ instance->io_port = port;
+ instance->irq = pdev->irq;
+ NCR5380_init(instance, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
+
+ if (request_irq(pdev->irq, dmx3191d_do_intr, SA_SHIRQ,
+ DMX3191D_DRIVER_NAME, instance)) {
+ dmx3191d_printk("irq %d not available\n", pdev->irq);
+ /* Steam powered scsi controllers run without an IRQ
+ anyway */
+ instance->irq = IRQ_NONE;
+ }
+
+ boards++;
+ }
+ return boards;
+}
+
+const char * dmx3191d_info(struct Scsi_Host *host) {
+ static const char *info ="Domex DMX3191D";
+
+ return info;
+}
+
+int dmx3191d_release_resources(struct Scsi_Host *instance)
+{
+ release_region(instance->io_port, DMX3191D_REGION);
+ if(instance->irq!=IRQ_NONE)
+ free_irq(instance->irq, instance);
+
+ return 0;
+}
+
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = DMX3191D;
+
+#include "scsi_module.c"
+
+#endif /* MODULE */
+
diff --git a/drivers/scsi/dmx3191d.h b/drivers/scsi/dmx3191d.h
new file mode 100644
index 000000000..c037d3bf0
--- /dev/null
+++ b/drivers/scsi/dmx3191d.h
@@ -0,0 +1,74 @@
+
+/*
+ dmx3191d.h - defines for the Domex DMX3191D SCSI card.
+ Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
+
+ 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.
+*/
+
+#ifndef __DMX3191D_H
+#define __DMX3191D_H
+
+#define DMX3191D_DRIVER_NAME "dmx3191d"
+#define DMX3191D_REGION 8
+
+#ifndef PCI_VENDOR_ID_DOMEX
+#define PCI_VENDOR_ID_DOMEX 0x134a
+#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001
+#endif
+
+#define dmx3191d_printk( args... ) printk(__FILE__": " ##args)
+
+#ifndef ASM
+int dmx3191d_abort(Scsi_Cmnd *);
+int dmx3191d_detect(Scsi_Host_Template *);
+const char* dmx3191d_info(struct Scsi_Host *);
+int dmx3191d_proc_info(char *, char **, off_t, int, int, int);
+int dmx3191d_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int dmx3191d_release_resources(struct Scsi_Host *);
+int dmx3191d_reset(Scsi_Cmnd *, unsigned int);
+
+
+#if defined(HOSTS_C) || defined(MODULE)
+#define DMX3191D { \
+ proc_info: dmx3191d_proc_info, \
+ name: "Domex DMX3191D", \
+ detect: dmx3191d_detect, \
+ release: dmx3191d_release_resources, \
+ info: dmx3191d_info, \
+ queuecommand: dmx3191d_queue_command, \
+ abort: dmx3191d_abort, \
+ reset: dmx3191d_reset, \
+ bios_param: NULL, \
+ can_queue: 32, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 2, \
+ use_clustering: DISABLE_CLUSTERING \
+}
+#endif /* HOSTS_C || MODULE */
+
+
+#ifndef HOSTS_C
+#define NCR5380_read(reg) inb(port + reg)
+#define NCR5380_write(reg, value) outb(value, port + reg)
+
+#define NCR5380_implementation_fields unsigned int port
+#define NCR5380_local_declare() NCR5380_implementation_fields
+#define NCR5380_setup(instance) port = instance->io_port
+
+#define NCR5380_abort dmx3191d_abort
+#define do_NCR5380_intr dmx3191d_do_intr
+#define NCR5380_intr dmx3191d_intr
+#define NCR5380_proc_info dmx3191d_proc_info
+#define NCR5380_queue_command dmx3191d_queue_command
+#define NCR5380_reset dmx3191d_reset
+
+#endif /* HOSTS_C */
+#endif /* ASM */
+
+#endif /* __DMX3191D_H */
+
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index fccfb59c8..1dcc8acb8 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.92 2000/02/18 13:49:58 davem Exp $
+/* $Id: esp.c,v 1.94 2000/03/30 02:09:10 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -4348,6 +4348,13 @@ static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
spin_unlock_irqrestore(&esp->lock, flags);
}
+int esp_revoke(Scsi_Device* SDptr)
+{
+ struct esp *esp = (struct esp *) SDptr->host->hostdata;
+ esp->targets_present &= ~(1 << SDptr->id);
+ return 0;
+}
+
#ifdef MODULE
Scsi_Host_Template driver_template = SCSI_SPARC_ESP;
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
index dfbfb9e53..9bebad41b 100644
--- a/drivers/scsi/esp.h
+++ b/drivers/scsi/esp.h
@@ -1,4 +1,4 @@
-/* $Id: esp.h,v 1.27 1999/12/15 14:12:52 davem Exp $
+/* $Id: esp.h,v 1.28 2000/03/30 01:33:17 davem Exp $
* esp.h: Defines and structures for the Sparc ESP (Enhanced SCSI
* Processor) driver under Linux.
*
@@ -398,12 +398,14 @@ extern int esp_abort(Scsi_Cmnd *);
extern int esp_reset(Scsi_Cmnd *, unsigned int);
extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout);
+extern int esp_revoke(Scsi_Device* SDptr);
#define SCSI_SPARC_ESP { \
proc_name: "esp", \
proc_info: &esp_proc_info, \
name: "Sun ESP 100/100a/200", \
detect: esp_detect, \
+ revoke: esp_revoke, \
info: esp_info, \
command: esp_command, \
queuecommand: esp_queue, \
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index b626d3fdd..56c441a62 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -205,6 +205,10 @@
#include "t128.h"
#endif
+#ifdef CONFIG_SCSI_DMX3191D
+#include "dmx3191d.h"
+#endif
+
#ifdef CONFIG_SCSI_DTC3280
#include "dtc.h"
#endif
@@ -554,6 +558,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#ifdef CONFIG_SCSI_T128
TRANTOR_T128,
#endif
+#ifdef CONFIG_SCSI_DMX3191D
+ DMX3191D,
+#endif
#ifdef CONFIG_SCSI_DTC3280
DTC3x80,
#endif
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index 685925e7d..f7e546fa6 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -96,6 +96,8 @@ typedef struct SHT
*/
int (* detect)(struct SHT *);
+ int (*revoke)(Scsi_Device *);
+
/* Used with loadable modules to unload the host structures. Note:
* there is a default action built into the modules code which may
* be sufficient for most host adapters. Thus you may not have to supply
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 5fc1bfaab..e40cdb7c2 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -104,7 +104,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2g"
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2h"
#define SCSI_NCR_DEBUG_FLAGS (0)
@@ -1120,7 +1120,7 @@ struct ncb {
u_char revision_id; /* PCI device revision id */
u_char bus; /* PCI BUS number */
u_char device_fn; /* PCI BUS device and function */
- u_long port; /* IO space base address */
+ u_long base_io; /* IO space base address */
u_int irq; /* IRQ level */
u_int features; /* Chip features map */
u_char myaddr; /* SCSI id of the adapter */
@@ -3734,7 +3734,7 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
*/
request_region(device->slot.io_port, 128, "ncr53c8xx");
- np->port = device->slot.io_port;
+ np->base_io = device->slot.io_port;
#ifdef SCSI_NCR_NVRAM_SUPPORT
if (nvram) {
@@ -3951,11 +3951,11 @@ attach_error:
unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
}
#endif /* !NCR_IOMAPPED */
- if (np->port) {
+ if (np->base_io) {
#ifdef DEBUG_NCR53C8XX
- printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+ printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
#endif
- release_region(np->port, 128);
+ release_region(np->base_io, 128);
}
if (np->irq) {
#ifdef DEBUG_NCR53C8XX
@@ -4260,11 +4260,17 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**----------------------------------------------------
*/
- segments = ncr_scatter (np, cp, cp->cmd);
-
- if (segments < 0) {
- ncr_free_ccb(np, cp);
- return(DID_ERROR);
+ direction = scsi_data_direction(cmd);
+ if (direction != SCSI_DATA_NONE) {
+ segments = ncr_scatter (np, cp, cp->cmd);
+ if (segments < 0) {
+ ncr_free_ccb(np, cp);
+ return(DID_ERROR);
+ }
+ }
+ else {
+ cp->data_len = 0;
+ segments = 0;
}
/*----------------------------------------------------
@@ -4275,8 +4281,6 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
*/
if (!cp->data_len)
direction = SCSI_DATA_NONE;
- else
- direction = scsi_data_direction(cmd);
/*
** If data direction is UNKNOWN, speculate DATA_READ
@@ -4796,9 +4800,9 @@ static int ncr_detach(ncb_p np)
#endif /* !NCR_IOMAPPED */
#ifdef DEBUG_NCR53C8XX
- printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+ printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
#endif
- release_region(np->port, 128);
+ release_region(np->base_io, 128);
/*
** Free allocated ccb(s)
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
index 8e9c314ba..b5da20220 100644
--- a/drivers/scsi/qlogicisp.c
+++ b/drivers/scsi/qlogicisp.c
@@ -1389,14 +1389,6 @@ static int isp1020_init(struct Scsi_Host *sh)
return 1;
}
-#ifdef __sparc__
- command |= (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY|
- PCI_COMMAND_INVALIDATE|PCI_COMMAND_SERR);
- pci_write_config_word(pdev, PCI_COMMAND, command);
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 16);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-#endif
#ifdef __alpha__
/* Force ALPHA to use bus I/O and not bus MEM.
This is to avoid having to use HAE_MEM registers,
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 9fa8bc444..87236abbb 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1866,6 +1866,8 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
* Nobody is using this device any more.
* Free all of the command structures.
*/
+ if (HBA_ptr->hostt->revoke)
+ HBA_ptr->hostt->revoke(scd);
devfs_unregister (scd->de);
scsi_release_commandblocks(scd);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 584a84905..ac162c564 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -120,7 +120,6 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
struct Scsi_Host * host;
Scsi_Device * SDev;
int diskinfo[4];
- struct hd_geometry *loc = (struct hd_geometry *) arg;
SDev = rscsi_disks[DEVICE_NR(dev)].device;
/*
@@ -138,6 +137,8 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
switch (cmd)
{
case HDIO_GETGEO: /* Return BIOS disk parameters */
+ {
+ struct hd_geometry *loc = (struct hd_geometry *) arg;
if(!loc)
return -EINVAL;
@@ -164,6 +165,7 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start))
return -EFAULT;
return 0;
+ }
case BLKGETSIZE: /* Return device size */
if (!arg)
return -EINVAL;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index daca9f800..4fca4d14d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -17,8 +17,8 @@
* any later version.
*
*/
- static char * sg_version_str = "Version: 3.1.12 (20000222)";
- static int sg_version_num = 30112; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 3.1.13 (20000323)";
+ static int sg_version_num = 30113; /* 2 digits for each component */
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -66,8 +66,10 @@
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
static int sg_proc_init(void);
+#ifdef MODULE
static void sg_proc_cleanup(void);
#endif
+#endif
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
@@ -548,12 +550,16 @@ static ssize_t sg_write(struct file * filp, const char * buf,
hp->cmd_len = (unsigned char)cmd_size;
hp->iovec_count = 0;
hp->mx_sb_len = 0;
+#if 1
+ hp->dxfer_direction = SG_DXFER_UNKNOWN;
+#else
if (input_size > 0)
hp->dxfer_direction = ((old_hdr.reply_len - size_sg_header) > 0) ?
SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
else
hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV :
SG_DXFER_NONE;
+#endif
hp->dxfer_len = mxsize;
hp->dxferp = (unsigned char *)buf + cmd_size;
hp->sbp = NULL;
@@ -671,6 +677,8 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
SCpnt->sc_data_direction = SCSI_DATA_READ; break;
case SG_DXFER_TO_DEV:
SCpnt->sc_data_direction = SCSI_DATA_WRITE; break;
+ case SG_DXFER_UNKNOWN:
+ SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; break;
default:
SCpnt->sc_data_direction = SCSI_DATA_NONE; break;
}
@@ -1166,9 +1174,10 @@ static int sg_attach(Scsi_Device * scsidp)
for(k = 0; k < sg_template.dev_max; k++)
if(! sg_dev_arr[k]) break;
- if(k >= sg_template.dev_max) panic ("sg_dev_arr corrupt");
-
- sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC);
+ if(k < sg_template.dev_max)
+ sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC);
+ else
+ sdp = NULL;
if (NULL == sdp) {
scsidp->attached--;
write_unlock_irqrestore(&sg_dev_arr_lock, flags);
@@ -1318,12 +1327,16 @@ static int sg_start_req(Sg_request * srp)
Sg_fd * sfp = srp->parentfp;
sg_io_hdr_t * hp = &srp->header;
int dxfer_len = (int)hp->dxfer_len;
+ int dxfer_dir = hp->dxfer_direction;
Sg_scatter_hold * req_schp = &srp->data;
Sg_scatter_hold * rsv_schp = &sfp->reserve;
SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
- if ((hp->flags & SG_FLAG_DIRECT_IO) && (dxfer_len > 0) &&
- (hp->dxfer_direction != SG_DXFER_NONE) && (0 == hp->iovec_count) &&
+ if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
+ return 0;
+ if ((hp->flags & SG_FLAG_DIRECT_IO) &&
+ (dxfer_dir != SG_DXFER_UNKNOWN) &&
+ (0 == hp->iovec_count) &&
(! sfp->parentdp->device->host->unchecked_isa_dma)) {
res = sg_build_dir(srp, sfp, dxfer_len);
if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */
@@ -1563,12 +1576,13 @@ static int sg_write_xfer(Sg_request * srp)
int num_xfer = 0;
int j, k, onum, usglen, ksglen, res, ok;
int iovec_count = (int)hp->iovec_count;
+ int dxfer_dir = hp->dxfer_direction;
unsigned char * p;
unsigned char * up;
int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
- if ((SG_DXFER_TO_DEV == hp->dxfer_direction) ||
- (SG_DXFER_TO_FROM_DEV == hp->dxfer_direction)) {
+ if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||
+ (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
num_xfer = (int)(new_interface ? hp->dxfer_len : hp->flags);
if (schp->bufflen < num_xfer)
num_xfer = schp->bufflen;
@@ -1711,12 +1725,13 @@ static int sg_read_xfer(Sg_request * srp)
int num_xfer = 0;
int j, k, onum, usglen, ksglen, res, ok;
int iovec_count = (int)hp->iovec_count;
+ int dxfer_dir = hp->dxfer_direction;
unsigned char * p;
unsigned char * up;
int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
- if ((SG_DXFER_FROM_DEV == hp->dxfer_direction) ||
- (SG_DXFER_TO_FROM_DEV == hp->dxfer_direction)) {
+ if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir) ||
+ (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
num_xfer = hp->dxfer_len;
if (schp->bufflen < num_xfer)
num_xfer = schp->bufflen;
@@ -2445,6 +2460,7 @@ static int sg_proc_init()
return 0;
}
+#ifdef MODULE
static void sg_proc_cleanup()
{
int k;
@@ -2456,6 +2472,7 @@ static void sg_proc_cleanup()
remove_proc_entry(sg_proc_leaf_names[k], sg_proc_sgp);
remove_proc_entry(sg_proc_sg_dirname, proc_scsi);
}
+#endif
static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
int size, int * eof, void * data)
@@ -2505,7 +2522,7 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
}
read_lock(&sg_dev_arr_lock);
max_dev = sg_last_dev();
- PRINT_PROC("dev_max=%d max_active_device=%d (origin 1)\n",
+ PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
sg_template.dev_max, max_dev);
PRINT_PROC(" scsi_dma_free_sectors=%u sg_pool_secs_aval=%d "
"def_reserved_size=%d\n",
@@ -2523,12 +2540,13 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
}
dev = MINOR(sdp->i_rdev);
- PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev);
- PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d"
+ if ((fp = sdp->headfp)) {
+ PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev);
+ PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d"
" excl=%d\n", scsidp->host->host_no, scsidp->channel,
scsidp->id, scsidp->lun, scsidp->host->hostt->emulated,
sdp->sg_tablesize, sdp->exclude);
- fp = sdp->headfp;
+ }
for (k = 1; fp; fp = fp->nextfp, ++k) {
PRINT_PROC(" FD(%d): timeout=%d bufflen=%d "
"(res)sgat=%d low_dma=%d\n",
@@ -2543,13 +2561,13 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
while (srp) {
hp = &srp->header;
/* stop indenting so far ... */
- PRINT_PROC(srp->res_used ? " reserved_buff>> " :
+ PRINT_PROC(srp->res_used ? " rb>> " :
((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " "));
blen = srp->my_cmdp ? srp->my_cmdp->bufflen : srp->data.bufflen;
usg = srp->my_cmdp ? srp->my_cmdp->use_sg : srp->data.k_use_sg;
PRINT_PROC(srp->done ? "rcv: id=%d" : (srp->my_cmdp ? "act: id=%d" :
"prior: id=%d"), srp->header.pack_id);
- if (! srp->res_used) PRINT_PROC(" blen=%d", blen);
+ PRINT_PROC(" blen=%d", blen);
if (srp->done)
PRINT_PROC(" dur=%d", sg_jif_to_ms(hp->duration));
else
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index f9bbce41e..5c57cb275 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -84,7 +84,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5k"
+#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5l"
/* #define DEBUG_896R1 */
#define SCSI_NCR_OPTIMIZE_896
@@ -6303,7 +6303,6 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
lcb_p lp = ncr_lp(np, tp, cmd->lun);
ccb_p cp;
- int segments;
u_char idmsg, *msgptr;
u_int msglen;
int direction;
@@ -6452,11 +6451,17 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**----------------------------------------------------
*/
- cp->segments = segments = np->scatter (np, cp, cp->cmd);
-
- if (segments < 0) {
- ncr_free_ccb(np, cp);
- return(DID_ERROR);
+ direction = scsi_data_direction(cmd);
+ if (direction != SCSI_DATA_NONE) {
+ cp->segments = np->scatter (np, cp, cp->cmd);
+ if (cp->segments < 0) {
+ ncr_free_ccb(np, cp);
+ return(DID_ERROR);
+ }
+ }
+ else {
+ cp->data_len = 0;
+ cp->segments = 0;
}
/*----------------------------------------------------
@@ -6467,8 +6472,6 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
*/
if (!cp->data_len)
direction = SCSI_DATA_NONE;
- else
- direction = scsi_data_direction(cmd);
/*
** If data direction is UNKNOWN, speculate DATA_READ
@@ -6480,7 +6483,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
case SCSI_DATA_UNKNOWN:
case SCSI_DATA_WRITE:
goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
- lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
+ lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4));
if (direction != SCSI_DATA_UNKNOWN)
break;
cp->phys.header.wgoalp = cpu_to_scr(goalp);
@@ -6489,7 +6492,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
case SCSI_DATA_READ:
cp->host_flags |= HF_DATA_IN;
goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
- lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
+ lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4));
break;
default:
case SCSI_DATA_NONE:
@@ -12317,16 +12320,6 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
#endif
#endif /* __powerpc__ */
-#ifdef __sparc__
- /*
- ** Fix-ups for sparc.
- */
- if (!cache_line_size)
- suggested_cache_line_size = 16;
-
- driver_setup.pci_fix_up |= 0x7;
-#endif /* __sparc__ */
-
#if defined(__i386__) && !defined(MODULE)
if (!cache_line_size) {
#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
diff --git a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h
index fa02ff585..a9cc78a54 100644
--- a/drivers/scsi/sym53c8xx_comm.h
+++ b/drivers/scsi/sym53c8xx_comm.h
@@ -2497,16 +2497,6 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
#endif
#endif /* __powerpc__ */
-#ifdef __sparc__
- /*
- ** Fix-ups for sparc.
- */
- if (!cache_line_size)
- suggested_cache_line_size = 16;
-
- driver_setup.pci_fix_up |= 0x7;
-#endif /* __sparc__ */
-
#if defined(__i386__) && !defined(MODULE)
if (!cache_line_size) {
#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 9234c2393..4f351e7aa 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -1657,7 +1657,7 @@ int wd33c93_setup (char *str)
setup_used[i] = 0;
done_setup = 1;
- return 0;
+ return 1;
}
__setup("wd33c93", wd33c93_setup);
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 046379d37..876daf485 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -35,7 +35,6 @@ obj- :=
# Each configuration option enables a list of files.
obj-$(CONFIG_SOUND) += soundcore.o
-obj-$(CONFIG_DMASOUND) += dmasound.o
obj-$(CONFIG_SOUND_OSS) += sound.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
@@ -81,6 +80,17 @@ obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
+ifeq ($(CONFIG_DMASOUND),y)
+ SUB_DIRS += dmasound
+ MOD_SUB_DIRS += dmasound
+ obj-y += dmasound/dmasound.o
+else
+ ifeq ($(CONFIG_DMASOUND),m)
+ MOD_SUB_DIRS += dmasound
+ endif
+endif
+
+
# Declare multi-part drivers.
list-multi := sound.o gus.o pas2.o sb.o sb_lib.o softoss2.o vidc_mod.o \
@@ -138,10 +148,6 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
- O_OBJS += lowlevel/lowlevel.o
-endif
-
include $(TOPDIR)/Rules.make
diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c
index e91d71909..bdab8a85b 100644
--- a/drivers/sound/ad1816.c
+++ b/drivers/sound/ad1816.c
@@ -1266,8 +1266,7 @@ static int __initdata dma = -1;
static int __initdata dma2 = -1;
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-struct pci_dev *ad1816_dev = NULL,
- *mpu_dev = NULL;
+struct pci_dev *ad1816_dev = NULL;
static int activated = 1;
diff --git a/drivers/sound/aedsp16.c b/drivers/sound/aedsp16.c
index 74b961521..6ea812a38 100644
--- a/drivers/sound/aedsp16.c
+++ b/drivers/sound/aedsp16.c
@@ -1383,6 +1383,7 @@ static int __init setup_aedsp16(char *str)
mss_base = ints[4];
mpu_base = ints[5];
mpu_irq = ints[6];
+ return 1;
}
__setup("aedsp16=", setup_aedsp16);
diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c
index 0a1e2981c..4a1a39506 100644
--- a/drivers/sound/dev_table.c
+++ b/drivers/sound/dev_table.c
@@ -26,15 +26,13 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
struct audio_operations *op;
int l, num;
- if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver))
- {
+ if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) {
printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name);
return -(EINVAL);
}
num = sound_alloc_audiodev();
- if (num == -1)
- {
+ if (num == -1) {
printk(KERN_ERR "sound: Too many audio drivers\n");
return -(EBUSY);
}
@@ -47,8 +45,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
if (sound_nblocks < 1024)
sound_nblocks++;
- if (d == NULL || op == NULL)
- {
+ if (d == NULL || op == NULL) {
printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name);
sound_unload_audiodev(num);
return -(ENOMEM);
@@ -91,14 +88,12 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
int n = sound_alloc_mixerdev();
- if (n == -1)
- {
+ if (n == -1) {
printk(KERN_ERR "Sound: Too many mixer drivers\n");
return -EBUSY;
}
if (vers != MIXER_DRIVER_VERSION ||
- driver_size > sizeof(struct mixer_operations))
- {
+ driver_size > sizeof(struct mixer_operations)) {
printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name);
return -EINVAL;
}
@@ -110,8 +105,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
if (sound_nblocks < 1024)
sound_nblocks++;
- if (op == NULL)
- {
+ if (op == NULL) {
printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
return -ENOMEM;
}
@@ -131,8 +125,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
void sound_unload_audiodev(int dev)
{
- if (dev != -1)
- {
+ if (dev != -1) {
DMAbuf_deinit(dev);
audio_devs[dev] = NULL;
unregister_sound_dsp((dev<<4)+3);
@@ -165,10 +158,8 @@ int sound_alloc_synthdev(void)
{
int i;
- for (i = 0; i < MAX_SYNTH_DEV; i++)
- {
- if (synth_devs[i] == NULL)
- {
+ for (i = 0; i < MAX_SYNTH_DEV; i++) {
+ if (synth_devs[i] == NULL) {
if (i >= num_synths)
num_synths++;
return i;
@@ -192,10 +183,8 @@ int sound_alloc_timerdev(void)
{
int i;
- for (i = 0; i < MAX_TIMER_DEV; i++)
- {
- if (sound_timer_devs[i] == NULL)
- {
+ for (i = 0; i < MAX_TIMER_DEV; i++) {
+ if (sound_timer_devs[i] == NULL) {
if (i >= num_sound_timers)
num_sound_timers++;
return i;
@@ -206,8 +195,7 @@ int sound_alloc_timerdev(void)
void sound_unload_mixerdev(int dev)
{
- if (dev != -1)
- {
+ if (dev != -1) {
mixer_devs[dev] = NULL;
unregister_sound_mixer(dev<<4);
num_mixers--;
@@ -216,8 +204,7 @@ void sound_unload_mixerdev(int dev)
void sound_unload_mididev(int dev)
{
- if (dev != -1)
- {
+ if (dev != -1) {
midi_devs[dev] = NULL;
unregister_sound_midi((dev<<4)+2);
}
diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h
index a5525a4bf..4c71c1265 100644
--- a/drivers/sound/dev_table.h
+++ b/drivers/sound/dev_table.h
@@ -133,9 +133,6 @@ struct dma_buffparms
char neutral_byte;
int dma; /* DMA channel */
-#ifdef OS_DMA_PARMS
- OS_DMA_PARMS
-#endif
int applic_profile; /* Application profile (APF_*) */
/* Interrupt callback stuff */
void (*audio_callback) (int dev, int parm);
@@ -347,7 +344,6 @@ struct sound_timer_operations
};
#ifdef _DEV_TABLE_C_
-
struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL};
int num_audiodevs = 0;
struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL};
@@ -356,21 +352,13 @@ struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL};
int num_synths = 0;
struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL};
int num_midis = 0;
-#ifndef EXCLUDE_TIMERS
+
extern struct sound_timer_operations default_sound_timer;
struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
&default_sound_timer, NULL
};
int num_sound_timers = 1;
#else
-struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
- NULL
-};
-int num_sound_timers = 0;
-#endif
-
-
-#else
extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
extern int num_audiodevs;
extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
@@ -384,8 +372,6 @@ extern int num_sound_timers;
#endif /* _DEV_TABLE_C_ */
extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
-int sndtable_probe (int unit, struct address_info *hw_config);
-int sndtable_start_card (int unit, struct address_info *hw_config);
void sound_timer_init (struct sound_lowlev_timer *t, char *name);
void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan);
diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c
deleted file mode 100644
index b6298ca83..000000000
--- a/drivers/sound/dmasound.c
+++ /dev/null
@@ -1,5821 +0,0 @@
-
-/* linux/drivers/sound/dmasound.c */
-
-/*
-
-OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
-Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
-
-(c) 1995 by Michael Schlueter & Michael Marte
-
-Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
-interface and the u-law to signed byte conversion.
-
-Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
-/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
-to thank:
-Michael Schlueter for initial ideas and documentation on the MFP and
-the DMA sound hardware.
-Therapy? for their CD 'Troublegum' which really made me rock.
-
-/dev/sndstat is based on code by Hannu Savolainen, the author of the
-VoxWare family of drivers.
-
-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.
-
-History:
-1995/8/25 first release
-
-1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming
- and several race conditions
-
-1995/9/14 ++roman: After some discussion with Michael Schlueter, revised
- the interrupt disabling
- Slightly speeded up U8->S8 translation by using long
- operations where possible
- Added 4:3 interpolation for /dev/audio
-
-1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio
- converting to play at 12517Hz instead of 6258Hz.
-
-1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program
- the DMA for another frame while there's still one
- running. This allows the IRQ response to be
- arbitrarily delayed and playing will still continue.
-
-1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for
- Falcon audio (the Falcon doesn't raise an IRQ at the
- end of a frame, but at the beginning instead!). uses
- 'if (codec_dma)' in lots of places to simply switch
- between Falcon and TT code.
-
-1995/11/06 ++TeSche: started introducing a hardware abstraction scheme
- (may perhaps also serve for Amigas?), can now play
- samples at almost all frequencies by means of a more
- generalized expand routine, takes a good deal of care
- to cut data only at sample sizes, buffer size is now
- a kernel runtime option, implemented fsync() & several
- minor improvements
- ++Guenther: useful hints and bug fixes, cross-checked it for
- Falcons
-
-1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian.
- Unification to drivers/sound/dmasound.c.
-
-1996/4/6 ++Martin Mitchell: updated to 1.3 kernel.
-
-1996/6/13 ++topi: fixed things that were broken (mainly the amiga
- 14-bit routines), /dev/sndstat shows now the real
- hardware frequency, the lowpass filter is disabled
- by default now.
-
-1996/9/25 ++geert: modularization
-
-1998-06-10 ++andreas: converted to use sound_core
-
-*/
-
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/config.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-#include <asm/setup.h>
-#endif
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stram.h>
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/feature.h>
-#include "awacs_defs.h"
-#include <linux/nvram.h>
-#include <linux/vt_kern.h>
-#endif /* CONFIG_PPC */
-
-#include "dmasound.h"
-#include <linux/soundcard.h>
-
-#define HAS_8BIT_TABLES
-
-#ifdef MODULE
-static int sq_unit = -1;
-static int mixer_unit = -1;
-static int state_unit = -1;
-static int irq_installed = 0;
-#endif /* MODULE */
-static char **sound_buffers = NULL;
-#ifdef CONFIG_PPC
-static char **sound_read_buffers = NULL;
-#endif
-
-#ifdef CONFIG_ATARI
-extern void atari_microwire_cmd(int cmd);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
- /*
- * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern volatile u_short amiga_audio_min_period;
-
-
- /*
- * amiga_mksound() should be able to restore the period after beeping
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern u_short amiga_audio_period;
-
-
- /*
- * Audio DMA masks
- */
-
-#define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
-#define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
-#define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
-
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-/*
- * Interrupt numbers and addresses, obtained from the device tree.
- */
-static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
-static volatile struct awacs_regs *awacs;
-static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
-static int awacs_rate_index;
-static int awacs_subframe;
-static int awacs_spkr_vol;
-static struct device_node* awacs_node;
-
-static int awacs_revision;
-#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
-
-/*
- * Space for the DBDMA command blocks.
- */
-static void *awacs_tx_cmd_space;
-static volatile struct dbdma_cmd *awacs_tx_cmds;
-
-static void *awacs_rx_cmd_space;
-static volatile struct dbdma_cmd *awacs_rx_cmds;
-
-/*
- * Cached values of AWACS registers (we can't read them).
- * Except on the burgundy. XXX
- */
-int awacs_reg[5];
-
-#define HAS_16BIT_TABLES
-#undef HAS_8BIT_TABLES
-
-/*
- * Stuff for outputting a beep. The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
- 0, 40, 79, 117, 153, 187, 218, 245,
- 269, 288, 304, 316, 323, 327, 327, 324,
- 318, 310, 299, 288, 275, 262, 249, 236,
- 224, 213, 204, 196, 190, 186, 183, 182,
- 182, 183, 186, 189, 192, 196, 200, 203,
- 206, 208, 209, 209, 209, 207, 204, 201,
- 197, 193, 188, 183, 179, 174, 170, 166,
- 163, 161, 160, 159, 159, 160, 161, 162,
- 164, 166, 168, 169, 171, 171, 171, 170,
- 169, 167, 163, 159, 155, 150, 144, 139,
- 133, 128, 122, 117, 113, 110, 107, 105,
- 103, 103, 103, 103, 104, 104, 105, 105,
- 105, 103, 101, 97, 92, 86, 78, 68,
- 58, 45, 32, 18, 3, -11, -26, -41,
- -55, -68, -79, -88, -95, -100, -102, -102,
- -99, -93, -85, -75, -62, -48, -33, -16,
- 0, 16, 33, 48, 62, 75, 85, 93,
- 99, 102, 102, 100, 95, 88, 79, 68,
- 55, 41, 26, 11, -3, -18, -32, -45,
- -58, -68, -78, -86, -92, -97, -101, -103,
- -105, -105, -105, -104, -104, -103, -103, -103,
- -103, -105, -107, -110, -113, -117, -122, -128,
- -133, -139, -144, -150, -155, -159, -163, -167,
- -169, -170, -171, -171, -171, -169, -168, -166,
- -164, -162, -161, -160, -159, -159, -160, -161,
- -163, -166, -170, -174, -179, -183, -188, -193,
- -197, -201, -204, -207, -209, -209, -209, -208,
- -206, -203, -200, -196, -192, -189, -186, -183,
- -182, -182, -183, -186, -190, -196, -204, -213,
- -224, -236, -249, -262, -275, -288, -299, -310,
- -318, -324, -327, -327, -323, -316, -304, -288,
- -269, -245, -218, -187, -153, -117, -79, -40,
-};
-
-#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
-#define BEEP_BUFLEN 512
-#define BEEP_VOLUME 15 /* 0 - 100 */
-
-static int beep_volume = BEEP_VOLUME;
-static int beep_playing = 0;
-static int awacs_beep_state = 0;
-static short *beep_buf;
-static volatile struct dbdma_cmd *beep_dbdma_cmd;
-static void (*orig_mksound)(unsigned int, unsigned int);
-static int is_pbook_3400;
-static unsigned char *latch_base;
-static int is_pbook_G3;
-static unsigned char *macio_base;
-
-/* Burgundy functions */
-static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
-static unsigned awacs_burgundy_rcw(unsigned addr);
-static void awacs_burgundy_write_volume(unsigned address, int volume);
-static int awacs_burgundy_read_volume(unsigned address);
-static void awacs_burgundy_write_mvolume(unsigned address, int volume);
-static int awacs_burgundy_read_mvolume(unsigned address);
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Stuff for restoring after a sleep.
- */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier awacs_sleep_notifier = {
- awacs_sleep_notify, SLEEP_LEVEL_SOUND,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-#endif /* CONFIG_PPC */
-
-/*** Some declarations *******************************************************/
-
-
-#define DMASND_TT 1
-#define DMASND_FALCON 2
-#define DMASND_AMIGA 3
-#define DMASND_AWACS 4
-
-#define MAX_CATCH_RADIUS 10
-#define MIN_BUFFERS 4
-#define MIN_BUFSIZE 4
-#define MAX_BUFSIZE 128 /* Limit for Amiga */
-
-static int catchRadius = 0;
-static int numBufs = 4, bufSize = 32;
-#ifdef CONFIG_PPC
-static int numReadBufs = 4, readbufSize = 32;
-#endif
-
-MODULE_PARM(catchRadius, "i");
-MODULE_PARM(numBufs, "i");
-MODULE_PARM(bufSize, "i");
-MODULE_PARM(numReadBufs, "i");
-MODULE_PARM(readbufSize, "i");
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-#define min(x, y) ((x) < (y) ? (x) : (y))
-#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
- } while (0)
-#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
-
-
-/*** Some low level helpers **************************************************/
-
-#ifdef HAS_8BIT_TABLES
-/* 8 bit mu-law */
-
-static char ulaw2dma8[] = {
- -126, -122, -118, -114, -110, -106, -102, -98,
- -94, -90, -86, -82, -78, -74, -70, -66,
- -63, -61, -59, -57, -55, -53, -51, -49,
- -47, -45, -43, -41, -39, -37, -35, -33,
- -31, -30, -29, -28, -27, -26, -25, -24,
- -23, -22, -21, -20, -19, -18, -17, -16,
- -16, -15, -15, -14, -14, -13, -13, -12,
- -12, -11, -11, -10, -10, -9, -9, -8,
- -8, -8, -7, -7, -7, -7, -6, -6,
- -6, -6, -5, -5, -5, -5, -4, -4,
- -4, -4, -4, -4, -3, -3, -3, -3,
- -3, -3, -3, -3, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 0,
- 125, 121, 117, 113, 109, 105, 101, 97,
- 93, 89, 85, 81, 77, 73, 69, 65,
- 62, 60, 58, 56, 54, 52, 50, 48,
- 46, 44, 42, 40, 38, 36, 34, 32,
- 30, 29, 28, 27, 26, 25, 24, 23,
- 22, 21, 20, 19, 18, 17, 16, 15,
- 15, 14, 14, 13, 13, 12, 12, 11,
- 11, 10, 10, 9, 9, 8, 8, 7,
- 7, 7, 6, 6, 6, 6, 5, 5,
- 5, 5, 4, 4, 4, 4, 3, 3,
- 3, 3, 3, 3, 2, 2, 2, 2,
- 2, 2, 2, 2, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* 8 bit A-law */
-
-static char alaw2dma8[] = {
- -22, -21, -24, -23, -18, -17, -20, -19,
- -30, -29, -32, -31, -26, -25, -28, -27,
- -11, -11, -12, -12, -9, -9, -10, -10,
- -15, -15, -16, -16, -13, -13, -14, -14,
- -86, -82, -94, -90, -70, -66, -78, -74,
- -118, -114, -126, -122, -102, -98, -110, -106,
- -43, -41, -47, -45, -35, -33, -39, -37,
- -59, -57, -63, -61, -51, -49, -55, -53,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -6, -6, -6, -6, -5, -5, -5, -5,
- -8, -8, -8, -8, -7, -7, -7, -7,
- -3, -3, -3, -3, -3, -3, -3, -3,
- -4, -4, -4, -4, -4, -4, -4, -4,
- 21, 20, 23, 22, 17, 16, 19, 18,
- 29, 28, 31, 30, 25, 24, 27, 26,
- 10, 10, 11, 11, 8, 8, 9, 9,
- 14, 14, 15, 15, 12, 12, 13, 13,
- 86, 82, 94, 90, 70, 66, 78, 74,
- 118, 114, 126, 122, 102, 98, 110, 106,
- 43, 41, 47, 45, 35, 33, 39, 37,
- 59, 57, 63, 61, 51, 49, 55, 53,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 5, 5, 5, 5, 4, 4, 4, 4,
- 7, 7, 7, 7, 6, 6, 6, 6,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3
-};
-#endif /* HAS_8BIT_TABLES */
-
-#ifdef HAS_16BIT_TABLES
-
-/* 16 bit mu-law */
-
-static short ulaw2dma16[] = {
- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
- -876, -844, -812, -780, -748, -716, -684, -652,
- -620, -588, -556, -524, -492, -460, -428, -396,
- -372, -356, -340, -324, -308, -292, -276, -260,
- -244, -228, -212, -196, -180, -164, -148, -132,
- -120, -112, -104, -96, -88, -80, -72, -64,
- -56, -48, -40, -32, -24, -16, -8, 0,
- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
- 876, 844, 812, 780, 748, 716, 684, 652,
- 620, 588, 556, 524, 492, 460, 428, 396,
- 372, 356, 340, 324, 308, 292, 276, 260,
- 244, 228, 212, 196, 180, 164, 148, 132,
- 120, 112, 104, 96, 88, 80, 72, 64,
- 56, 48, 40, 32, 24, 16, 8, 0,
-};
-
-/* 16 bit A-law */
-
-static short alaw2dma16[] = {
- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
- -344, -328, -376, -360, -280, -264, -312, -296,
- -472, -456, -504, -488, -408, -392, -440, -424,
- -88, -72, -120, -104, -24, -8, -56, -40,
- -216, -200, -248, -232, -152, -136, -184, -168,
- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
- -688, -656, -752, -720, -560, -528, -624, -592,
- -944, -912, -1008, -976, -816, -784, -880, -848,
- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
- 344, 328, 376, 360, 280, 264, 312, 296,
- 472, 456, 504, 488, 408, 392, 440, 424,
- 88, 72, 120, 104, 24, 8, 56, 40,
- 216, 200, 248, 232, 152, 136, 184, 168,
- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
- 688, 656, 752, 720, 560, 528, 624, 592,
- 944, 912, 1008, 976, 816, 784, 880, 848,
-};
-#endif /* HAS_16BIT_TABLES */
-
-
-#ifdef HAS_14BIT_TABLES
-
-/* 14 bit mu-law (LSB) */
-
-static char alaw2dma14l[] = {
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 49, 17, 49, 17, 49, 17, 49, 17,
- 49, 17, 49, 17, 49, 17, 49, 17,
- 41, 57, 9, 25, 41, 57, 9, 25,
- 41, 57, 9, 25, 41, 57, 9, 25,
- 37, 45, 53, 61, 5, 13, 21, 29,
- 37, 45, 53, 61, 5, 13, 21, 29,
- 35, 39, 43, 47, 51, 55, 59, 63,
- 3, 7, 11, 15, 19, 23, 27, 31,
- 34, 36, 38, 40, 42, 44, 46, 48,
- 50, 52, 54, 56, 58, 60, 62, 0,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 15, 47, 15, 47, 15, 47, 15, 47,
- 15, 47, 15, 47, 15, 47, 15, 47,
- 23, 7, 55, 39, 23, 7, 55, 39,
- 23, 7, 55, 39, 23, 7, 55, 39,
- 27, 19, 11, 3, 59, 51, 43, 35,
- 27, 19, 11, 3, 59, 51, 43, 35,
- 29, 25, 21, 17, 13, 9, 5, 1,
- 61, 57, 53, 49, 45, 41, 37, 33,
- 30, 28, 26, 24, 22, 20, 18, 16,
- 14, 12, 10, 8, 6, 4, 2, 0
-};
-
-/* 14 bit A-law (LSB) */
-
-static char alaw2dma14l[] = {
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 16, 48, 16, 48, 16, 48, 16, 48,
- 16, 48, 16, 48, 16, 48, 16, 48,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 42, 46, 34, 38, 58, 62, 50, 54,
- 10, 14, 2, 6, 26, 30, 18, 22,
- 42, 46, 34, 38, 58, 62, 50, 54,
- 10, 14, 2, 6, 26, 30, 18, 22,
- 40, 56, 8, 24, 40, 56, 8, 24,
- 40, 56, 8, 24, 40, 56, 8, 24,
- 20, 28, 4, 12, 52, 60, 36, 44,
- 20, 28, 4, 12, 52, 60, 36, 44,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 48, 16, 48, 16, 48, 16, 48, 16,
- 48, 16, 48, 16, 48, 16, 48, 16,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 22, 18, 30, 26, 6, 2, 14, 10,
- 54, 50, 62, 58, 38, 34, 46, 42,
- 22, 18, 30, 26, 6, 2, 14, 10,
- 54, 50, 62, 58, 38, 34, 46, 42,
- 24, 8, 56, 40, 24, 8, 56, 40,
- 24, 8, 56, 40, 24, 8, 56, 40,
- 44, 36, 60, 52, 12, 4, 28, 20,
- 44, 36, 60, 52, 12, 4, 28, 20
-};
-#endif /* HAS_14BIT_TABLES */
-
-
-/*** Translations ************************************************************/
-
-
-#ifdef CONFIG_ATARI
-static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif /* CONFIG_PPC */
-
-/*** Machine definitions *****************************************************/
-
-
-typedef struct {
- int type;
- void *(*dma_alloc)(unsigned int, int);
- void (*dma_free)(void *, unsigned int);
- int (*irqinit)(void);
-#ifdef MODULE
- void (*irqcleanup)(void);
-#endif /* MODULE */
- void (*init)(void);
- void (*silence)(void);
- int (*setFormat)(int);
- int (*setVolume)(int);
- int (*setBass)(int);
- int (*setTreble)(int);
- int (*setGain)(int);
- void (*play)(void);
-} MACHINE;
-
-
-/*** Low level stuff *********************************************************/
-
-
-typedef struct {
- int format; /* AFMT_* */
- int stereo; /* 0 = mono, 1 = stereo */
- int size; /* 8/16 bit*/
- int speed; /* speed */
-} SETTINGS;
-
-typedef struct {
- ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-} TRANS;
-
-struct sound_settings {
- MACHINE mach; /* machine dependent things */
- SETTINGS hard; /* hardware settings */
- SETTINGS soft; /* software settings */
- SETTINGS dsp; /* /dev/dsp default settings */
- TRANS *trans; /* supported translations */
-#if defined(CONFIG_PPC)
- TRANS *read_trans; /* supported translations */
-#endif
- int volume_left; /* volume (range is machine dependent) */
- int volume_right;
- int bass; /* tone (range is machine dependent) */
- int treble;
- int gain;
- int minDev; /* minor device number currently open */
-#if defined(CONFIG_ATARI) || defined(CONFIG_PPC)
- int bal; /* balance factor for expanding (not volume!) */
- u_long data; /* data for expanding */
-#endif /* CONFIG_ATARI */
-};
-
-static struct sound_settings sound;
-
-
-#ifdef CONFIG_ATARI
-static void *AtaAlloc(unsigned int size, int flags);
-static void AtaFree(void *, unsigned int size);
-static int AtaIrqInit(void);
-#ifdef MODULE
-static void AtaIrqCleanUp(void);
-#endif /* MODULE */
-static int AtaSetBass(int bass);
-static int AtaSetTreble(int treble);
-static void TTSilence(void);
-static void TTInit(void);
-static int TTSetFormat(int format);
-static int TTSetVolume(int volume);
-static int TTSetGain(int gain);
-static void FalconSilence(void);
-static void FalconInit(void);
-static int FalconSetFormat(int format);
-static int FalconSetVolume(int volume);
-static void ata_sq_play_next_frame(int index);
-static void AtaPlay(void);
-static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static void *AmiAlloc(unsigned int size, int flags);
-static void AmiFree(void *, unsigned int);
-static int AmiIrqInit(void);
-#ifdef MODULE
-static void AmiIrqCleanUp(void);
-#endif /* MODULE */
-static void AmiSilence(void);
-static void AmiInit(void);
-static int AmiSetFormat(int format);
-static int AmiSetVolume(int volume);
-static int AmiSetTreble(int treble);
-static void ami_sq_play_next_frame(int index);
-static void AmiPlay(void);
-static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static void *PMacAlloc(unsigned int size, int flags);
-static void PMacFree(void *ptr, unsigned int size);
-static int PMacIrqInit(void);
-#ifdef MODULE
-static void PMacIrqCleanup(void);
-#endif /* MODULE */
-static void PMacSilence(void);
-static void PMacInit(void);
-static void PMacPlay(void);
-static void PMacRecord(void);
-static int PMacSetFormat(int format);
-static int PMacSetVolume(int volume);
-static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
-static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
-static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
-static void awacs_write(int val);
-static int awacs_get_volume(int reg, int lshift);
-static int awacs_volume_setter(int volume, int n, int mute, int lshift);
-static void awacs_mksound(unsigned int hz, unsigned int ticks);
-static void awacs_nosound(unsigned long xx);
-#endif /* CONFIG_PPC */
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-#ifdef CONFIG_ATARI
-static int sound_set_bass(int bass);
-#endif /* CONFIG_ATARI */
-#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
-static int sound_set_treble(int treble);
-#endif /* CONFIG_ATARI || CONFIG_AMIGA */
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#ifdef CONFIG_PPC
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
- int busy;
- int modify_counter;
-};
-
-static struct sound_mixer mixer;
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-struct sound_queue {
- int max_count, block_size;
- char **buffers;
- int max_active;
-
- /* it shouldn't be necessary to declare any of these volatile */
- int front, rear, count;
- int rear_size;
- /*
- * The use of the playing field depends on the hardware
- *
- * Atari, PMac: The number of frames that are loaded/playing
- *
- * Amiga: Bit 0 is set: a frame is loaded
- * Bit 1 is set: a frame is playing
- */
- int active;
- wait_queue_head_t action_queue, open_queue, sync_queue;
- int open_mode;
- int busy, syncing;
-#ifdef CONFIG_ATARI
- int ignore_int; /* ++TeSche: used for Falcon */
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- int block_size_half, block_size_quarter;
-#endif /* CONFIG_AMIGA */
-};
-
-static struct sound_queue sq;
-#ifdef CONFIG_PPC
-static struct sound_queue read_sq;
-#endif
-
-#define sq_block_address(i) (sq.buffers[i])
-#define SIGNAL_RECEIVED (signal_pending(current))
-#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK)
-#define ONE_SECOND HZ /* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT 0xffffffff
-#define SLEEP(queue, time_limit) \
- interruptible_sleep_on_timeout(&queue, (time_limit));
-#define WAKE_UP(queue) (wake_up_interruptible(&queue))
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
- int busy;
- char buf[512];
- int len, ptr;
-};
-
-static struct sound_state state;
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig);
-static inline int ioctl_return(int *addr, int value)
-{
- if (value < 0)
- return(value);
-
- return put_user(value, addr);
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-void dmasound_init(void);
-static int dmasound_setup(char *str);
-
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-#ifdef CONFIG_ATARI
-static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- ssize_t count, used;
- u_char *p = &frame[*frameUsed];
-
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = table[data];
- count--;
- }
- *frameUsed += used;
- return used;
-}
-
-
-static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- void *p = &frame[*frameUsed];
-
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- if (copy_from_user(p, userPtr, count))
- return -EFAULT;
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft);
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = data ^ 0x80;
- count--;
- }
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *p++ = data ^ 0x8080;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- void *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft) & ~3;
- used = count;
- if (copy_from_user(p, userPtr, count))
- return -EFAULT;
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count*4;
- while (count > 0) {
- u_long data;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- *p++ = data ^ 0x80008000;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- count = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count*4;
- while (count > 0) {
- u_long data;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data);
- *p++ = data;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- count = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *p++ = data;
- *p++ = data;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count;
- while (count > 0) {
- u_long data;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data) ^ 0x80008000;
- *p++ = data;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- u_char data = sound.data;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (!userCount)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c];
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 2) {
- u_char c;
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c] << 8;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data |= table[c];
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- u_char data = sound.data;
- while (frameLeft) {
- if (bal < 0) {
- if (!userCount)
- break;
- if (get_user(data, userPtr++))
- return -EFAULT;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 2) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- u_char data = sound.data;
- while (frameLeft) {
- if (bal < 0) {
- if (!userCount)
- break;
- if (get_user(data, userPtr++))
- return -EFAULT;
- data ^= 0x80;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 2) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8080;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data ^= 0x80008000;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data);
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data) ^ 0x80008000;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = table[data];
- count--;
- }
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *left++ = table[data];
- if (get_user(data, userPtr++))
- return -EFAULT;
- *right++ = table[data];
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- void *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- if (copy_from_user(p, userPtr, count))
- return -EFAULT;
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(*left++, userPtr++)
- || get_user(*right++, userPtr++))
- return -EFAULT;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = data ^ 0x80;
- count--;
- }
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *left++ = data ^ 0x80;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *right++ = data ^ 0x80;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- if (get_user(data, up++))
- return -EFAULT;
- *fp++ = data;
- *fp++ = data;
- count--;
- }
- } else {
- if (copy_from_user(fp, userPtr, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- *fp++ = data;
- if (stereo) {
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- }
- *fp++ = data;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned short *table = (unsigned short *)
- (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
- unsigned int data = sound.data;
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int utotal, ftotal;
- int stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c];
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + table[c];
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = c << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + (c << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (c ^ 0x80) << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + ((c ^ 0x80) << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + c;
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + (c ^ mask);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- data = *fp;
- if (put_user(data, up++))
- return -EFAULT;
- fp+=2;
- count--;
- }
- } else {
- if (copy_to_user((u_char *)userPtr, fp, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
-
- data = *fp++;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- if (stereo) {
- data = *fp;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- }
- fp++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-
-#endif /* CONFIG_PPC */
-
-
-#ifdef CONFIG_ATARI
-static TRANS transTTNormal = {
- ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
-};
-
-static TRANS transTTExpanding = {
- ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
-};
-
-static TRANS transFalconNormal = {
- ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8,
- ata_ct_s16be, ata_ct_u16be, ata_ct_s16le, ata_ct_u16le
-};
-
-static TRANS transFalconExpanding = {
- ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8,
- ata_ctx_s16be, ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
-};
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static TRANS transAmiga = {
- ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8,
- ami_ct_s16be, ami_ct_u16be, ami_ct_s16le, ami_ct_u16le
-};
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static TRANS transAwacsNormal = {
- pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
- pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
-};
-
-static TRANS transAwacsExpand = {
- pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
- pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
-};
-
-static TRANS transAwacsNormalRead = {
- NULL, NULL, pmac_ct_s8_read, pmac_ct_u8_read,
- pmac_ct_s16_read, pmac_ct_u16_read, pmac_ct_s16_read, pmac_ct_u16_read
-};
-#endif /* CONFIG_PPC */
-
-/*** Low level stuff *********************************************************/
-
-
-#ifdef CONFIG_ATARI
-
-/*
- * Atari (TT/Falcon)
- */
-
-static void *AtaAlloc(unsigned int size, int flags)
-{
- return( atari_stram_alloc( size, NULL, "dmasound" ));
-}
-
-static void AtaFree(void *obj, unsigned int size)
-{
- atari_stram_free( obj );
-}
-
-static int __init AtaIrqInit(void)
-{
- /* Set up timer A. Timer A
- will receive a signal upon end of playing from the sound
- hardware. Furthermore Timer A is able to count events
- and will cause an interrupt after a programmed number
- of events. So all we need to keep the music playing is
- to provide the sound hardware with new data upon
- an interrupt from timer A. */
- mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
- mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
- mfp.tim_ct_a = 8; /* Turn on event counting. */
- /* Register interrupt handler. */
- request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
- "DMA sound", ata_sq_interrupt);
- mfp.int_en_a |= 0x20; /* Turn interrupt on. */
- mfp.int_mk_a |= 0x20;
- return(1);
-}
-
-#ifdef MODULE
-static void AtaIrqCleanUp(void)
-{
- mfp.tim_ct_a = 0; /* stop timer */
- mfp.int_en_a &= ~0x20; /* turn interrupt off */
- free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
-}
-#endif /* MODULE */
-
-
-#define TONE_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
-#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
-
-
-static int AtaSetBass(int bass)
-{
- sound.bass = TONE_VOXWARE_TO_DB(bass);
- atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
- return(TONE_DB_TO_VOXWARE(sound.bass));
-}
-
-
-static int AtaSetTreble(int treble)
-{
- sound.treble = TONE_VOXWARE_TO_DB(treble);
- atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
- return(TONE_DB_TO_VOXWARE(sound.treble));
-}
-
-
-
-/*
- * TT
- */
-
-
-static void TTSilence(void)
-{
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
-}
-
-
-static void TTInit(void)
-{
- int mode, i, idx;
- const int freq[4] = {50066, 25033, 12517, 6258};
-
- /* search a frequency that fits into the allowed error range */
-
- idx = -1;
- for (i = 0; i < arraysize(freq); i++)
- /* this isn't as much useful for a TT than for a Falcon, but
- * then it doesn't hurt very much to implement it for a TT too.
- */
- if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
- idx = i;
- if (idx > -1) {
- sound.soft.speed = freq[idx];
- sound.trans = &transTTNormal;
- } else
- sound.trans = &transTTExpanding;
-
- TTSilence();
- sound.hard = sound.soft;
-
- if (sound.hard.speed > 50066) {
- /* we would need to squeeze the sound, but we won't do that */
- sound.hard.speed = 50066;
- mode = DMASND_MODE_50KHZ;
- sound.trans = &transTTNormal;
- } else if (sound.hard.speed > 25033) {
- sound.hard.speed = 50066;
- mode = DMASND_MODE_50KHZ;
- } else if (sound.hard.speed > 12517) {
- sound.hard.speed = 25033;
- mode = DMASND_MODE_25KHZ;
- } else if (sound.hard.speed > 6258) {
- sound.hard.speed = 12517;
- mode = DMASND_MODE_12KHZ;
- } else {
- sound.hard.speed = 6258;
- mode = DMASND_MODE_6KHZ;
- }
-
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- DMASND_MODE_8BIT | mode;
-
- sound.bal = -sound.soft.speed;
-}
-
-
-static int TTSetFormat(int format)
-{
- /* TT sound DMA supports only 8bit modes */
-
- switch (format) {
- case AFMT_QUERY:
- return(sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_S8:
- case AFMT_U8:
- break;
- default:
- format = AFMT_S8;
- }
-
- sound.soft.format = format;
- sound.soft.size = 8;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = 8;
- }
- TTInit();
-
- return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
-#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
-
-
-static int TTSetVolume(int volume)
-{
- sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
- atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
- sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
- atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
- return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
- (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
-}
-
-
-#define GAIN_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
-#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)
-
-static int TTSetGain(int gain)
-{
- sound.gain = GAIN_VOXWARE_TO_DB(gain);
- atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
- return GAIN_DB_TO_VOXWARE(sound.gain);
-}
-
-
-
-/*
- * Falcon
- */
-
-
-static void FalconSilence(void)
-{
- /* stop playback, set sample rate 50kHz for PSG sound */
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
- tt_dmasnd.int_div = 0; /* STE compatible divider */
- tt_dmasnd.int_ctrl = 0x0;
- tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
- tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
- tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
- tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
-}
-
-
-static void FalconInit(void)
-{
- int divider, i, idx;
- const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
-
- /* search a frequency that fits into the allowed error range */
-
- idx = -1;
- for (i = 0; i < arraysize(freq); i++)
- /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
- * be playable without expanding, but that now a kernel runtime
- * option
- */
- if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
- idx = i;
- if (idx > -1) {
- sound.soft.speed = freq[idx];
- sound.trans = &transFalconNormal;
- } else
- sound.trans = &transFalconExpanding;
-
- FalconSilence();
- sound.hard = sound.soft;
-
- if (sound.hard.size == 16) {
- /* the Falcon can play 16bit samples only in stereo */
- sound.hard.stereo = 1;
- }
-
- if (sound.hard.speed > 49170) {
- /* we would need to squeeze the sound, but we won't do that */
- sound.hard.speed = 49170;
- divider = 1;
- sound.trans = &transFalconNormal;
- } else if (sound.hard.speed > 32780) {
- sound.hard.speed = 49170;
- divider = 1;
- } else if (sound.hard.speed > 24585) {
- sound.hard.speed = 32780;
- divider = 2;
- } else if (sound.hard.speed > 19668) {
- sound.hard.speed = 24585;
- divider = 3;
- } else if (sound.hard.speed > 16390) {
- sound.hard.speed = 19668;
- divider = 4;
- } else if (sound.hard.speed > 12292) {
- sound.hard.speed = 16390;
- divider = 5;
- } else if (sound.hard.speed > 9834) {
- sound.hard.speed = 12292;
- divider = 7;
- } else if (sound.hard.speed > 8195) {
- sound.hard.speed = 9834;
- divider = 9;
- } else {
- sound.hard.speed = 8195;
- divider = 11;
- }
- tt_dmasnd.int_div = divider;
-
- /* Setup Falcon sound DMA for playback */
- tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
- tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
- tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
- tt_dmasnd.cbar_dst = 0x0000;
- tt_dmasnd.rec_track_select = 0;
- tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
- tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
-
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- ((sound.hard.size == 8) ?
- DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
- DMASND_MODE_6KHZ;
-
- sound.bal = -sound.soft.speed;
-}
-
-
-static int FalconSetFormat(int format)
-{
- int size;
- /* Falcon sound DMA supports 8bit and 16bit modes */
-
- switch (format) {
- case AFMT_QUERY:
- return(sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- size = 8;
- format = AFMT_S8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = sound.soft.size;
- }
-
- FalconInit();
-
- return(format);
-}
-
-
-/* This is for the Falcon output *attenuation* in 1.5dB steps,
- * i.e. output level from 0 to -22.5dB in -1.5dB steps.
- */
-#define VOLUME_VOXWARE_TO_ATT(v) \
- ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
-#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
-
-
-static int FalconSetVolume(int volume)
-{
- sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
- sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
- tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
- return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
- VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
-}
-
-
-static void ata_sq_play_next_frame(int index)
-{
- char *start, *end;
-
- /* used by AtaPlay() if all doubts whether there really is something
- * to be played are already wiped out.
- */
- start = sq_block_address(sq.front);
- end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
- /* end might not be a legal virtual address. */
- DMASNDSetEnd(virt_to_phys(end - 1) + 1);
- DMASNDSetBase(virt_to_phys(start));
- /* Since only an even number of samples per frame can
- be played, we might lose one byte here. (TO DO) */
- sq.front = (sq.front+1) % sq.max_count;
- sq.active++;
- tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
-}
-
-
-static void AtaPlay(void)
-{
- /* ++TeSche: Note that sq.active is no longer just a flag but holds
- * the number of frames the DMA is currently programmed for instead,
- * may be 0, 1 (currently being played) or 2 (pre-programmed).
- *
- * Changes done to sq.count and sq.active are a bit more subtle again
- * so now I must admit I also prefer disabling the irq here rather
- * than considering all possible situations. But the point is that
- * disabling the irq doesn't have any bad influence on this version of
- * the driver as we benefit from having pre-programmed the DMA
- * wherever possible: There's no need to reload the DMA at the exact
- * time of an interrupt but only at some time while the pre-programmed
- * frame is playing!
- */
- atari_disable_irq(IRQ_MFP_TIMA);
-
- if (sq.active == 2 || /* DMA is 'full' */
- sq.count <= 0) { /* nothing to do */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
-
- if (sq.active == 0) {
- /* looks like there's nothing 'in' the DMA yet, so try
- * to put two frames into it (at least one is available).
- */
- if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(1);
- if (sq.count == 1) {
- /* no more frames */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, there were two frames, but the second
- * one is not yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(2);
- } else {
- /* there's already a frame being played so we may only stuff
- * one new into the DMA, but even if this may be the last
- * frame existing the previous one is still on sq.count.
- */
- if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(2);
- }
- atari_enable_irq(IRQ_MFP_TIMA);
-}
-
-
-static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-#if 0
- /* ++TeSche: if you should want to test this... */
- static int cnt = 0;
- if (sq.active == 2)
- if (++cnt == 10) {
- /* simulate losing an interrupt */
- cnt = 0;
- return;
- }
-#endif
-
- if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
- /* ++TeSche: Falcon only: ignore first irq because it comes
- * immediately after starting a frame. after that, irqs come
- * (almost) like on the TT.
- */
- sq.ignore_int = 0;
- return;
- }
-
- if (!sq.active) {
- /* playing was interrupted and sq_reset() has already cleared
- * the sq variables, so better don't do anything here.
- */
- WAKE_UP(sq.sync_queue);
- return;
- }
-
- /* Probably ;) one frame is finished. Well, in fact it may be that a
- * pre-programmed one is also finished because there has been a long
- * delay in interrupt delivery and we've completely lost one, but
- * there's no way to detect such a situation. In such a case the last
- * frame will be played more than once and the situation will recover
- * as soon as the irq gets through.
- */
- sq.count--;
- sq.active--;
-
- if (!sq.active) {
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- sq.ignore_int = 1;
- }
-
- WAKE_UP(sq.action_queue);
- /* At least one block of the queue is free now
- so wake up a writing process blocked because
- of a full queue. */
-
- if ((sq.active != 1) || (sq.count != 1))
- /* We must be a bit carefully here: sq.count indicates the
- * number of buffers used and not the number of frames to
- * be played. If sq.count==1 and sq.active==1 that means
- * the only remaining frame was already programmed earlier
- * (and is currently running) so we mustn't call AtaPlay()
- * here, otherwise we'll play one frame too much.
- */
- AtaPlay();
-
- if (!sq.active) WAKE_UP(sq.sync_queue);
- /* We are not playing after AtaPlay(), so there
- is nothing to play any more. Wake up a process
- waiting for audio output to drain. */
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-
-/*
- * Amiga
- */
-
-#define StopDMA() custom.aud[0].audvol = custom.aud[1].audvol = 0; \
- custom.aud[2].audvol = custom.aud[3].audvol = 0; \
- custom.dmacon = AMI_AUDIO_OFF;
-
-static void *AmiAlloc(unsigned int size, int flags)
-{
- return amiga_chip_alloc((long)size, "dmasound");
-}
-
-static void AmiFree(void *obj, unsigned int size)
-{
- amiga_chip_free (obj);
-}
-
-static int __init AmiIrqInit(void)
-{
- /* turn off DMA for audio channels */
- StopDMA();
-
- /* Register interrupt handler. */
- if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
- "DMA sound", ami_sq_interrupt))
- return(0);
- return(1);
-}
-
-#ifdef MODULE
-static void AmiIrqCleanUp(void)
-{
- /* turn off DMA for audio channels */
- StopDMA();
- /* release the interrupt */
- free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
-}
-#endif /* MODULE */
-
-static void AmiSilence(void)
-{
- /* turn off DMA for audio channels */
- StopDMA();
-}
-
-
-static void AmiInit(void)
-{
- int period, i;
-
- AmiSilence();
-
- if (sound.soft.speed)
- period = amiga_colorclock/sound.soft.speed-1;
- else
- period = amiga_audio_min_period;
- sound.hard = sound.soft;
- sound.trans = &transAmiga;
-
- if (period < amiga_audio_min_period) {
- /* we would need to squeeze the sound, but we won't do that */
- period = amiga_audio_min_period;
- } else if (period > 65535) {
- period = 65535;
- }
- sound.hard.speed = amiga_colorclock/(period+1);
-
- for (i = 0; i < 4; i++)
- custom.aud[i].audper = period;
- amiga_audio_period = period;
-
- AmiSetTreble(50); /* recommended for newer amiga models */
-}
-
-
-static int AmiSetFormat(int format)
-{
- int size;
-
- /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
-
- switch (format) {
- case AFMT_QUERY:
- return(sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- size = 8;
- format = AFMT_S8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = sound.soft.size;
- }
- AmiInit();
-
- return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_AMI(v) \
- (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
-#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
-
-static int AmiSetVolume(int volume)
-{
- sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
- custom.aud[0].audvol = sound.volume_left;
- sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
- custom.aud[1].audvol = sound.volume_right;
- if (sound.hard.size == 16) {
- if (sound.volume_left == 64 && sound.volume_right == 64) {
- custom.aud[2].audvol = 1;
- custom.aud[3].audvol = 1;
- } else {
- custom.aud[2].audvol = 0;
- custom.aud[3].audvol = 0;
- }
- }
- return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
- (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
-}
-
-static int AmiSetTreble(int treble)
-{
- sound.treble = treble;
- if (treble < 50)
- ciaa.pra &= ~0x02;
- else
- ciaa.pra |= 0x02;
- return(treble);
-}
-
-
-#define AMI_PLAY_LOADED 1
-#define AMI_PLAY_PLAYING 2
-#define AMI_PLAY_MASK 3
-
-
-static void ami_sq_play_next_frame(int index)
-{
- u_char *start, *ch0, *ch1, *ch2, *ch3;
- u_long size;
-
- /* used by AmiPlay() if all doubts whether there really is something
- * to be played are already wiped out.
- */
- start = sq_block_address(sq.front);
- size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
-
- if (sound.hard.stereo) {
- ch0 = start;
- ch1 = start+sq.block_size_half;
- size >>= 1;
- } else {
- ch0 = start;
- ch1 = start;
- }
-
- custom.aud[0].audvol = sound.volume_left;
- custom.aud[1].audvol = sound.volume_right;
- if (sound.hard.size == 8) {
- custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
- custom.aud[0].audlen = size;
- custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
- custom.aud[1].audlen = size;
- custom.dmacon = AMI_AUDIO_8;
- } else {
- size >>= 1;
- custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
- custom.aud[0].audlen = size;
- custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
- custom.aud[1].audlen = size;
- if (sound.volume_left == 64 && sound.volume_right == 64) {
- /* We can play pseudo 14-bit only with the maximum volume */
- ch3 = ch0+sq.block_size_quarter;
- ch2 = ch1+sq.block_size_quarter;
- custom.aud[2].audvol = 1; /* we are being affected by the beeps */
- custom.aud[3].audvol = 1; /* restoring volume here helps a bit */
- custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
- custom.aud[2].audlen = size;
- custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
- custom.aud[3].audlen = size;
- custom.dmacon = AMI_AUDIO_14;
- } else {
- custom.aud[2].audvol = 0;
- custom.aud[3].audvol = 0;
- custom.dmacon = AMI_AUDIO_8;
- }
- }
- sq.front = (sq.front+1) % sq.max_count;
- sq.active |= AMI_PLAY_LOADED;
-}
-
-
-static void AmiPlay(void)
-{
- int minframes = 1;
-
- custom.intena = IF_AUD0;
-
- if (sq.active & AMI_PLAY_LOADED) {
- /* There's already a frame loaded */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
-
- if (sq.active & AMI_PLAY_PLAYING)
- /* Increase threshold: frame 1 is already being played */
- minframes = 2;
-
- if (sq.count < minframes) {
- /* Nothing to do */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
-
- if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
-
- ami_sq_play_next_frame(minframes);
-
- custom.intena = IF_SETCLR | IF_AUD0;
-}
-
-
-static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
- int minframes = 1;
-
- custom.intena = IF_AUD0;
-
- if (!sq.active) {
- /* Playing was interrupted and sq_reset() has already cleared
- * the sq variables, so better don't do anything here.
- */
- WAKE_UP(sq.sync_queue);
- return;
- }
-
- if (sq.active & AMI_PLAY_PLAYING) {
- /* We've just finished a frame */
- sq.count--;
- WAKE_UP(sq.action_queue);
- }
-
- if (sq.active & AMI_PLAY_LOADED)
- /* Increase threshold: frame 1 is already being played */
- minframes = 2;
-
- /* Shift the flags */
- sq.active = (sq.active<<1) & AMI_PLAY_MASK;
-
- if (!sq.active)
- /* No frame is playing, disable audio DMA */
- StopDMA();
-
- custom.intena = IF_SETCLR | IF_AUD0;
-
- if (sq.count >= minframes)
- /* Try to play the next frame */
- AmiPlay();
-
- if (!sq.active)
- /* Nothing to play anymore.
- Wake up a process waiting for audio output to drain. */
- WAKE_UP(sq.sync_queue);
-}
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-
-/*
- * PCI PowerMac, with AWACS and DBDMA.
- */
-
-static void *PMacAlloc(unsigned int size, int flags)
-{
- return kmalloc(size, flags);
-}
-
-static void PMacFree(void *ptr, unsigned int size)
-{
- kfree(ptr);
-}
-
-static int __init PMacIrqInit(void)
-{
- if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
- || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
- || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
- return 0;
- return 1;
-}
-
-#ifdef MODULE
-static void PMacIrqCleanup(void)
-{
- /* turn off output dma */
- out_le32(&awacs_txdma->control, RUN<<16);
- /* disable interrupts from awacs interface */
- out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-#ifdef CONFIG_PMAC_PBOOK
- if (is_pbook_G3) {
- feature_clear(awacs_node, FEATURE_Sound_power);
- feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
- }
-#endif
- free_irq(awacs_irq, 0);
- free_irq(awacs_tx_irq, 0);
- free_irq(awacs_rx_irq, 0);
- kfree(awacs_tx_cmd_space);
- if (awacs_rx_cmd_space)
- kfree(awacs_rx_cmd_space);
- if (beep_buf)
- kfree(beep_buf);
- kd_mksound = orig_mksound;
-#ifdef CONFIG_PMAC_PBOOK
- pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
-#endif
-}
-#endif /* MODULE */
-
-static void PMacSilence(void)
-{
- /* turn off output dma */
- out_le32(&awacs_txdma->control, RUN<<16);
-}
-
-static int awacs_freqs[8] = {
- 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
-};
-static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-static void PMacInit(void)
-{
- int i, tolerance;
-
- switch (sound.soft.format) {
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- sound.hard.format = AFMT_S16_LE;
- break;
- default:
- sound.hard.format = AFMT_S16_BE;
- break;
- }
- sound.hard.stereo = 1;
- sound.hard.size = 16;
-
- /*
- * If we have a sample rate which is within catchRadius percent
- * of the requested value, we don't have to expand the samples.
- * Otherwise choose the next higher rate.
- * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
- */
- i = 8;
- do {
- tolerance = catchRadius * awacs_freqs[--i] / 100;
- if (awacs_freqs_ok[i]
- && sound.soft.speed <= awacs_freqs[i] + tolerance)
- break;
- } while (i > 0);
- if (sound.soft.speed >= awacs_freqs[i] - tolerance)
- sound.trans = &transAwacsNormal;
- else
- sound.trans = &transAwacsExpand;
- sound.read_trans = &transAwacsNormalRead;
- sound.hard.speed = awacs_freqs[i];
- awacs_rate_index = i;
-
- /* XXX disable error interrupt on burgundy for now */
- out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
- | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
- awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-
- /* We really want to execute a DMA stop command, after the AWACS
- * is initialized.
- * For reasons I don't understand, it stops the hissing noise
- * common to many PowerBook G3 systems (like mine :-).
- */
- out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
- st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- out_le32(&awacs_txdma->control, RUN | (RUN << 16));
-
- sound.bal = -sound.soft.speed;
-}
-
-static int PMacSetFormat(int format)
-{
- int size;
-
- switch (format) {
- case AFMT_QUERY:
- return sound.soft.format;
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
- format);
- size = 8;
- format = AFMT_U8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = size;
- }
-
- PMacInit();
-
- return format;
-}
-
-#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))
-#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))
-
-static int awacs_get_volume(int reg, int lshift)
-{
- int volume;
-
- volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
- volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
- return volume;
-}
-
-static int awacs_volume_setter(int volume, int n, int mute, int lshift)
-{
- int r1, rn;
-
- if (mute && volume == 0) {
- r1 = awacs_reg[1] | mute;
- } else {
- r1 = awacs_reg[1] & ~mute;
- rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
- rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
- rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
- awacs_reg[n] = rn;
- awacs_write((n << 12) | rn);
- volume = awacs_get_volume(rn, lshift);
- }
- if (r1 != awacs_reg[1]) {
- awacs_reg[1] = r1;
- awacs_write(r1 | MASK_ADDR1);
- }
- return volume;
-}
-
-static int PMacSetVolume(int volume)
-{
- return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
-}
-
-static void PMacPlay(void)
-{
- volatile struct dbdma_cmd *cp;
- int i, count;
- unsigned long flags;
-
- save_flags(flags); cli();
- if (awacs_beep_state) {
- /* sound takes precedence over beeps */
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (awacs_rate_index << 8));
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
-
- beep_playing = 0;
- awacs_beep_state = 0;
- }
- i = sq.front + sq.active;
- if (i >= sq.max_count)
- i -= sq.max_count;
- while (sq.active < 2 && sq.active < sq.count) {
- count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
- if (count < sq.block_size && !sq.syncing)
- /* last block not yet filled, and we're not syncing. */
- break;
- cp = &awacs_tx_cmds[i];
- st_le16(&cp->req_count, count);
- st_le16(&cp->xfer_status, 0);
- if (++i >= sq.max_count)
- i = 0;
- out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
- out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
- if (sq.active == 0)
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
- out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- ++sq.active;
- }
- restore_flags(flags);
-}
-
-
-static void PMacRecord(void)
-{
- unsigned long flags;
-
- if (read_sq.active)
- return;
-
- save_flags(flags); cli();
-
- /* This is all we have to do......Just start it up.
- */
- out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- read_sq.active = 1;
-
- restore_flags(flags);
-}
-
-
-static void
-pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
-{
- int i = sq.front;
- int stat;
- volatile struct dbdma_cmd *cp;
-
- while (sq.active > 0) {
- cp = &awacs_tx_cmds[i];
- stat = ld_le16(&cp->xfer_status);
- if ((stat & ACTIVE) == 0)
- break; /* this frame is still going */
- --sq.count;
- --sq.active;
- if (++i >= sq.max_count)
- i = 0;
- }
- if (i != sq.front)
- WAKE_UP(sq.action_queue);
- sq.front = i;
-
- PMacPlay();
-
- if (!sq.active)
- WAKE_UP(sq.sync_queue);
-}
-
-
-static void
-pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
-{
-
- /* For some reason on my PowerBook G3, I get one interrupt
- * when the interrupt vector is installed (like something is
- * pending). This happens before the dbdma is initialize by
- * us, so I just check the command pointer and if it is zero,
- * just blow it off.
- */
- if (in_le32(&awacs_rxdma->cmdptr) == 0)
- return;
-
- /* We also want to blow 'em off when shutting down.
- */
- if (read_sq.active == 0)
- return;
-
- /* Check multiple buffers in case we were held off from
- * interrupt processing for a long time. Geeze, I really hope
- * this doesn't happen.
- */
- while (awacs_rx_cmds[read_sq.rear].xfer_status) {
-
- /* Clear status and move on to next buffer.
- */
- awacs_rx_cmds[read_sq.rear].xfer_status = 0;
- read_sq.rear++;
-
- /* Wrap the buffer ring.
- */
- if (read_sq.rear >= read_sq.max_active)
- read_sq.rear = 0;
-
- /* If we have caught up to the front buffer, bump it.
- * This will cause weird (but not fatal) results if the
- * read loop is currently using this buffer. The user is
- * behind in this case anyway, so weird things are going
- * to happen.
- */
- if (read_sq.rear == read_sq.front) {
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
-
- WAKE_UP(read_sq.action_queue);
-}
-
-
-static void
-pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
-{
- int ctrl = in_le32(&awacs->control);
-
- if (ctrl & MASK_PORTCHG) {
- /* do something when headphone is plugged/unplugged? */
- }
- if (ctrl & MASK_CNTLERR) {
- int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
- if (err != 0 && awacs_revision < AWACS_BURGUNDY)
- printk(KERN_ERR "AWACS: error %x\n", err);
- }
- /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
- out_le32(&awacs->control, ctrl);
-}
-
-static void
-awacs_write(int val)
-{
- if (awacs_revision >= AWACS_BURGUNDY)
- return;
- while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
- ; /* XXX should have timeout */
- out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
-}
-
-static void awacs_nosound(unsigned long xx)
-{
- unsigned long flags;
-
- save_flags(flags); cli();
- if (beep_playing) {
- st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (awacs_rate_index << 8));
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- beep_playing = 0;
- }
- restore_flags(flags);
-}
-
-static struct timer_list beep_timer = {
- NULL, NULL, 0, 0, awacs_nosound
-};
-
-static void awacs_mksound(unsigned int hz, unsigned int ticks)
-{
- unsigned long flags;
- int beep_speed = 0;
- int srate;
- int period, ncycles, nsamples;
- int i, j, f;
- short *p;
- static int beep_hz_cache;
- static int beep_nsamples_cache;
- static int beep_volume_cache;
-
- for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
- if (awacs_freqs_ok[i])
- beep_speed = i;
- srate = awacs_freqs[beep_speed];
-
- if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
-#if 1
- /* this is a hack for broken X server code */
- hz = 750;
- ticks = 12;
-#else
- /* cancel beep currently playing */
- awacs_nosound(0);
- return;
-#endif
- }
- save_flags(flags); cli();
- del_timer(&beep_timer);
- if (ticks) {
- beep_timer.expires = jiffies + ticks;
- add_timer(&beep_timer);
- }
- if (beep_playing || sq.active || beep_buf == NULL) {
- restore_flags(flags);
- return; /* too hard, sorry :-( */
- }
- beep_playing = 1;
- st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
- restore_flags(flags);
-
- if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
- nsamples = beep_nsamples_cache;
- } else {
- period = srate * 256 / hz; /* fixed point */
- ncycles = BEEP_BUFLEN * 256 / period;
- nsamples = (period * ncycles) >> 8;
- f = ncycles * 65536 / nsamples;
- j = 0;
- p = beep_buf;
- for (i = 0; i < nsamples; ++i, p += 2) {
- p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
- j = (j + f) & 0xffff;
- }
- beep_hz_cache = hz;
- beep_volume_cache = beep_volume;
- beep_nsamples_cache = nsamples;
- }
-
- st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
- st_le16(&beep_dbdma_cmd->xfer_status, 0);
- st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
- st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
- awacs_beep_state = 1;
-
- save_flags(flags); cli();
- if (beep_playing) { /* i.e. haven't been terminated already */
- out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (beep_speed << 8));
- out_le32(&awacs->byteswap, 0);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- out_le32(&awacs_txdma->control, RUN | (RUN << 16));
- }
- restore_flags(flags);
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save state when going to sleep, restore it afterwards.
- */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
- switch (when) {
- case PBOOK_SLEEP_NOW:
- /* XXX we should stop any dma in progress when going to sleep
- and restart it when we wake. */
- PMacSilence();
- disable_irq(awacs_irq);
- disable_irq(awacs_tx_irq);
- if (is_pbook_G3) {
- feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
- feature_clear(awacs_node, FEATURE_Sound_power);
- }
- break;
- case PBOOK_WAKE:
- /* There is still a problem on wake. Sound seems to work fine
- if I launch mpg123 and resumes fine if mpg123 was playing,
- but the console beep is dead until I do something with the
- mixer. Probably yet another timing issue */
- if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
- || !feature_test(awacs_node, FEATURE_Sound_power)) {
- /* these aren't present on the 3400 AFAIK -- paulus */
- feature_set(awacs_node, FEATURE_Sound_CLK_enable);
- feature_set(awacs_node, FEATURE_Sound_power);
- mdelay(1000);
- }
- out_le32(&awacs->control, MASK_IEPC
- | (awacs_rate_index << 8) | 0x11
- | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- awacs_write(awacs_reg[2] | MASK_ADDR2);
- awacs_write(awacs_reg[4] | MASK_ADDR4);
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- enable_irq(awacs_irq);
- enable_irq(awacs_tx_irq);
- if (awacs_revision == 3) {
- mdelay(100);
- awacs_write(0x6000);
- mdelay(2);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- }
- /* enable CD sound input */
- if (macio_base && is_pbook_G3) {
- out_8(macio_base + 0x37, 3);
- } else if (is_pbook_3400) {
- feature_set(awacs_node, FEATURE_IOBUS_enable);
- udelay(10);
- in_8(latch_base + 0x190);
- }
- /* Resume pending sounds. */
- PMacPlay();
- }
- return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-
-/* All the burgundy functions: */
-
-/* Waits for busy flag to clear */
-inline static void
-awacs_burgundy_busy_wait(void)
-{
- while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
- ;
-}
-
-inline static void
-awacs_burgundy_extend_wait(void)
-{
- while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND))
- ;
- while (in_le32(&awacs->codec_stat) & MASK_EXTEND)
- ;
-}
-
-static void
-awacs_burgundy_wcw(unsigned addr, unsigned val)
-{
- out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
- awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcw(unsigned addr)
-{
- unsigned val = 0;
- unsigned long flags;
-
- /* should have timeouts here */
- save_flags(flags); cli();
-
- out_le32(&awacs->codec_ctrl, addr + 0x100000);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100100);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100200);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100300);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
-
- restore_flags(flags);
-
- return val;
-}
-
-
-static void
-awacs_burgundy_wcb(unsigned addr, unsigned val)
-{
- out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
- awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcb(unsigned addr)
-{
- unsigned val = 0;
- unsigned long flags;
-
- /* should have timeouts here */
- save_flags(flags); cli();
-
- out_le32(&awacs->codec_ctrl, addr + 0x100000);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
- restore_flags(flags);
-
- return val;
-}
-
-static int
-awacs_burgundy_check(void)
-{
- /* Checks to see the chip is alive and kicking */
- int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE;
-
- return error == 0xf0000;
-}
-
-static int
-awacs_burgundy_init(void)
-{
- if (awacs_burgundy_check()) {
- printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n");
- return 1;
- }
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES,
- DEF_BURGUNDY_OUTPUTENABLES);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- DEF_BURGUNDY_MORE_OUTPUTENABLES);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
- DEF_BURGUNDY_OUTPUTSELECTS);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21,
- DEF_BURGUNDY_INPSEL21);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3,
- DEF_BURGUNDY_INPSEL3);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD,
- DEF_BURGUNDY_GAINCD);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE,
- DEF_BURGUNDY_GAINLINE);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC,
- DEF_BURGUNDY_GAINMIC);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM,
- DEF_BURGUNDY_GAINMODEM);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER,
- DEF_BURGUNDY_ATTENSPEAKER);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT,
- DEF_BURGUNDY_ATTENLINEOUT);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP,
- DEF_BURGUNDY_ATTENHP);
-
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME,
- DEF_BURGUNDY_MASTER_VOLUME);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD,
- DEF_BURGUNDY_VOLCD);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE,
- DEF_BURGUNDY_VOLLINE);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC,
- DEF_BURGUNDY_VOLMIC);
- return 0;
-}
-
-static void
-awacs_burgundy_write_volume(unsigned address, int volume)
-{
- int hardvolume,lvolume,rvolume;
-
- lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0;
- rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0;
-
- hardvolume = lvolume + (rvolume << 16);
-
- awacs_burgundy_wcw(address, hardvolume);
-}
-
-static int
-awacs_burgundy_read_volume(unsigned address)
-{
- int softvolume,wvolume;
-
- wvolume = awacs_burgundy_rcw(address);
-
- softvolume = (wvolume & 0xff) - 155;
- softvolume += (((wvolume >> 16) & 0xff) - 155)<<8;
-
- return softvolume > 0 ? softvolume : 0;
-}
-
-
-
-
-static int
-awacs_burgundy_read_mvolume(unsigned address)
-{
- int lvolume,rvolume,wvolume;
-
- wvolume = awacs_burgundy_rcw(address);
-
- wvolume &= 0xffff;
-
- rvolume = (wvolume & 0xff) - 155;
- lvolume = ((wvolume & 0xff00)>>8) - 155;
-
- return lvolume + (rvolume << 8);
-}
-
-
-static void
-awacs_burgundy_write_mvolume(unsigned address, int volume)
-{
- int lvolume,rvolume,hardvolume;
-
- lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0;
- rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0;
-
- hardvolume = lvolume + (rvolume << 8);
- hardvolume += (hardvolume << 16);
-
- awacs_burgundy_wcw(address, hardvolume);
-}
-
-/* End burgundy functions */
-
-
-
-
-
-/* Turn on sound output, needed on G3 desktop powermacs */
-static void
-awacs_enable_amp(int spkr_vol)
-{
- struct adb_request req;
-
- awacs_spkr_vol = spkr_vol;
- if (sys_ctrler != SYS_CTRLER_CUDA)
- return;
-
- /* turn on headphones */
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 4, 0);
- while (!req.complete) cuda_poll();
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 6, 0);
- while (!req.complete) cuda_poll();
-
- /* turn on speaker */
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
- while (!req.complete) cuda_poll();
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
- while (!req.complete) cuda_poll();
-
- cuda_request(&req, NULL, 5, CUDA_PACKET,
- CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
- while (!req.complete) cuda_poll();
-}
-
-#endif /* CONFIG_PPC */
-
-/*** Machine definitions *****************************************************/
-
-
-#ifdef CONFIG_ATARI
-static MACHINE machTT = {
- DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
-#ifdef MODULE
- AtaIrqCleanUp,
-#endif /* MODULE */
- TTInit, TTSilence, TTSetFormat, TTSetVolume,
- AtaSetBass, AtaSetTreble, TTSetGain,
- AtaPlay
-};
-
-static MACHINE machFalcon = {
- DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
-#ifdef MODULE
- AtaIrqCleanUp,
-#endif /* MODULE */
- FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume,
- AtaSetBass, AtaSetTreble, NULL,
- AtaPlay
-};
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static MACHINE machAmiga = {
- DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
-#ifdef MODULE
- AmiIrqCleanUp,
-#endif /* MODULE */
- AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume,
- NULL, AmiSetTreble, NULL,
- AmiPlay
-};
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static MACHINE machPMac = {
- DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
-#ifdef MODULE
- PMacIrqCleanup,
-#endif /* MODULE */
- PMacInit, PMacSilence, PMacSetFormat, PMacSetVolume,
- NULL, NULL, NULL, /* bass, treble, gain */
- PMacPlay
-};
-#endif /* CONFIG_AMIGA */
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
- /* update hardware settings one more */
- (*sound.mach.init)();
-
- (*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
- (*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
- return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int speed)
-{
- if (speed < 0)
- return(sound.soft.speed);
-
- sound.soft.speed = speed;
- (*sound.mach.init)();
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.speed = sound.soft.speed;
-
- return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
- if (stereo < 0)
- return(sound.soft.stereo);
-
- stereo = !!stereo; /* should be 0 or 1 now */
-
- sound.soft.stereo = stereo;
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.stereo = stereo;
- (*sound.mach.init)();
-
- return(stereo);
-}
-
-
-static int sound_set_volume(int volume)
-{
- return(*sound.mach.setVolume)(volume);
-}
-
-
-#ifdef CONFIG_ATARI
-static int sound_set_bass(int bass)
-{
- return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
-}
-
-static int sound_set_gain(int gain)
-{
- return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
-}
-#endif /* CONFIG_ATARI */
-
-#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
-static int sound_set_treble(int treble)
-{
- return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
-}
-#endif /* CONFIG_ATARI || CONFIG_AMIGA */
-
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.trans->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.trans->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.trans->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.trans->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.trans->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.trans->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.trans->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.trans->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-
-#ifdef CONFIG_PPC
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.read_trans->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.read_trans->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.read_trans->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.read_trans->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.read_trans->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.read_trans->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.read_trans->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.read_trans->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-#endif
-
-
-/*
- * /dev/mixer abstraction
- */
-
-
-#define RECLEVEL_VOXWARE_TO_GAIN(v) \
- ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
-
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
- MOD_INC_USE_COUNT;
- mixer.busy = 1;
- return 0;
-}
-
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
- mixer.busy = 0;
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- int data;
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- mixer.modify_counter++;
- if (cmd == OSS_GETVERSION)
- return IOCTL_OUT(arg, SOUND_VERSION);
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_FALCON:
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "FALCON", sizeof(info.id));
- strncpy(info.name, "FALCON", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
- case SOUND_MIXER_READ_RECMASK:
- return IOCTL_OUT(arg, SOUND_MASK_MIC);
- case SOUND_MIXER_READ_STEREODEVS:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg,
- VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
- VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- tt_dmasnd.input_gain =
- RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
- RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
- /* fall thru, return set value */
- case SOUND_MIXER_READ_MIC:
- return IOCTL_OUT(arg,
- RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
- RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
- case SOUND_MIXER_READ_SPEAKER:
- {
- int porta;
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = sound_ym.rd_data_reg_sel;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_WRITE_SPEAKER:
- {
- int porta;
- IOCTL_IN(arg, data);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (data < 50 ? 0x40 : 0);
- sound_ym.wd_data = porta;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- }
- break;
-
- case DMASND_TT:
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "TT", sizeof(info.id));
- strncpy(info.name, "TT", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- return IOCTL_OUT(arg,
- SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
- (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
- case SOUND_MIXER_READ_RECMASK:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_STEREODEVS:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg,
- VOLUME_DB_TO_VOXWARE(sound.volume_left) |
- (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
- case SOUND_MIXER_READ_BASS:
- return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass));
- case SOUND_MIXER_READ_TREBLE:
- return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble));
- case SOUND_MIXER_READ_OGAIN:
- return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain));
- case SOUND_MIXER_READ_SPEAKER:
- {
- int porta;
- if (MACH_IS_TT) {
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = sound_ym.rd_data_reg_sel;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- }
- break;
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_WRITE_BASS:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_bass(data));
- case SOUND_MIXER_WRITE_TREBLE:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_treble(data));
- case SOUND_MIXER_WRITE_OGAIN:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_gain(data));
- case SOUND_MIXER_WRITE_SPEAKER:
- if (MACH_IS_TT) {
- int porta;
- IOCTL_IN(arg, data);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (data < 50 ? 0x40 : 0);
- sound_ym.wd_data = porta;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- }
- break;
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "AMIGA", sizeof(info.id));
- strncpy(info.name, "AMIGA", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
- case SOUND_MIXER_READ_RECMASK:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_STEREODEVS:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg,
- VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
- VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_READ_TREBLE:
- return IOCTL_OUT(arg, sound.treble);
- case SOUND_MIXER_WRITE_TREBLE:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_treble(data));
- }
- break;
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
- case DMASND_AWACS:
- /* Different IOCTLS for burgundy*/
- if (awacs_revision < AWACS_BURGUNDY) {
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "AWACS", sizeof(info.id));
- strncpy(info.name, "AWACS", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info,
- sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_LINE | SOUND_MASK_MIC
- | SOUND_MASK_CD | SOUND_MASK_RECLEV
- | SOUND_MASK_ALTPCM
- | SOUND_MASK_MONITOR;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC
- | SOUND_MASK_CD;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECSRC:
- data = 0;
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- if (awacs_reg[0] & MASK_MUX_CD)
- data |= SOUND_MASK_CD;
- if (awacs_reg[1] & MASK_LOOPTHRU)
- data |= SOUND_MASK_MONITOR;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_CD
- | SOUND_MASK_MONITOR);
- awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
- | MASK_MUX_AUDIN);
- awacs_reg[1] &= ~MASK_LOOPTHRU;
- if (data & SOUND_MASK_LINE)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- if (data & SOUND_MASK_MIC)
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data & SOUND_MASK_CD)
- awacs_reg[0] |= MASK_MUX_CD;
- if (data & SOUND_MASK_MONITOR)
- awacs_reg[1] |= MASK_LOOPTHRU;
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_RECLEV;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_VOLUME:
- data = (awacs_reg[1] & MASK_AMUTE)? 0:
- awacs_get_volume(awacs_reg[2], 6);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_READ_SPEAKER:
- if (awacs_revision == 3
- && sys_ctrler == SYS_CTRLER_CUDA)
- data = awacs_spkr_vol;
- else
- data = (awacs_reg[1] & MASK_CMUTE)? 0:
- awacs_get_volume(awacs_reg[4], 6);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_SPEAKER:
- IOCTL_IN(arg, data);
- if (awacs_revision == 3
- && sys_ctrler == SYS_CTRLER_CUDA)
- awacs_enable_amp(data);
- else
- data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_volume = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- return IOCTL_OUT(arg, beep_volume);
- case SOUND_MIXER_WRITE_LINE:
- IOCTL_IN(arg, data);
- awacs_reg[0] &= ~MASK_MUX_AUDIN;
- if ((data & 0xff) >= 50)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
- /* fall through */
- case SOUND_MIXER_READ_LINE:
- data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- data &= 0xff;
- awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
- if (data >= 25) {
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data >= 75)
- awacs_reg[0] |= MASK_GAINLINE;
- }
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
- /* fall through */
- case SOUND_MIXER_READ_MIC:
- data = (awacs_reg[0] & MASK_MUX_MIC)?
- (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_CD:
- IOCTL_IN(arg, data);
- awacs_reg[0] &= ~MASK_MUX_CD;
- if ((data & 0xff) >= 50)
- awacs_reg[0] |= MASK_MUX_CD;
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
- /* fall through */
- case SOUND_MIXER_READ_CD:
- data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- data = awacs_volume_setter(data, 0, 0, 4);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECLEV:
- data = awacs_get_volume(awacs_reg[0], 4);
- return IOCTL_OUT(arg, data);
- }
- break;
- } else {
- /* We are, we are, we are... Burgundy or better */
- switch(cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "AWACS", sizeof(info.id));
- strncpy(info.name, "AWACS", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info,
- sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_MIC |
- SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC
- | SOUND_MASK_CD;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECSRC:
- data = 0;
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- if (awacs_reg[0] & MASK_MUX_CD)
- data |= SOUND_MASK_CD;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_CD);
- awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
- | MASK_MUX_AUDIN);
- if (data & SOUND_MASK_LINE)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- if (data & SOUND_MASK_MIC)
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data & SOUND_MASK_CD)
- awacs_reg[0] |= MASK_MUX_CD;
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_RECLEV | SOUND_MASK_CD
- | SOUND_MASK_LINE;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
- /* Fall through */
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
- case SOUND_MIXER_WRITE_SPEAKER:
- IOCTL_IN(arg, data);
-
- if (!(data & 0xff)) {
- /* Mute the left speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);
- } else {
- /* Unmute the left speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);
- }
- if (!(data & 0xff00)) {
- /* Mute the right speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);
- } else {
- /* Unmute the right speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);
- }
-
- data = (((data&0xff)*16)/100 > 0xf ? 0xf :
- (((data&0xff)*16)/100)) +
- ((((data>>8)*16)/100 > 0xf ? 0xf :
- ((((data>>8)*16)/100)))<<4);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);
- /* Fall through */
- case SOUND_MIXER_READ_SPEAKER:
- data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
- data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
- return IOCTL_OUT(arg, ~data);
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_volume = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- return IOCTL_OUT(arg, beep_volume);
- case SOUND_MIXER_WRITE_LINE:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
-
- /* fall through */
- case SOUND_MIXER_READ_LINE:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- /* Mic is mono device */
- data = (data << 8) + (data << 24);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
- /* fall through */
- case SOUND_MIXER_READ_MIC:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);
- data <<= 24;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_CD:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
- /* fall through */
- case SOUND_MIXER_READ_CD:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- data = awacs_volume_setter(data, 0, 0, 4);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECLEV:
- data = awacs_get_volume(awacs_reg[0], 4);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_OUTMASK:
- break;
- case SOUND_MIXER_OUTSRC:
- break;
- }
- break;
- }
-#endif
- }
-
- return -EINVAL;
-}
-
-
-static struct file_operations mixer_fops =
-{
- llseek: sound_lseek,
- ioctl: mixer_ioctl,
- open: mixer_open,
- release: mixer_release,
-};
-
-
-static void __init mixer_init(void)
-{
-#ifndef MODULE
- int mixer_unit;
-#endif
- mixer_unit = register_sound_mixer(&mixer_fops, -1);
- if (mixer_unit < 0)
- return;
-
- mixer.busy = 0;
- sound.treble = 0;
- sound.bass = 0;
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- atari_microwire_cmd(MW_LM1992_VOLUME(0));
- sound.volume_left = 0;
- atari_microwire_cmd(MW_LM1992_BALLEFT(0));
- sound.volume_right = 0;
- atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
- atari_microwire_cmd(MW_LM1992_TREBLE(0));
- atari_microwire_cmd(MW_LM1992_BASS(0));
- break;
- case DMASND_FALCON:
- sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
- sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- sound.volume_left = 64;
- sound.volume_right = 64;
- custom.aud[0].audvol = sound.volume_left;
- custom.aud[3].audvol = 1; /* For pseudo 14bit */
- custom.aud[1].audvol = sound.volume_right;
- custom.aud[2].audvol = 1; /* For pseudo 14bit */
- sound.treble = 50;
- break;
-#endif /* CONFIG_AMIGA */
- }
-}
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-static int sq_allocate_buffers(void)
-{
- int i;
-
- if (sound_buffers)
- return 0;
- sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
- if (!sound_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-
-static void sq_release_buffers(void)
-{
- int i;
-
- if (sound_buffers) {
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- }
-}
-
-
-#ifdef CONFIG_PPC
-static int sq_allocate_read_buffers(void)
-{
- int i;
- int j;
-
- if (sound_read_buffers)
- return 0;
- sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_read_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
- GFP_KERNEL);
- if (!sound_read_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_read_buffers[i],
- readbufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- return -ENOMEM;
- }
- /* XXXX debugging code */
- for (j=0; j<readbufSize; j++) {
- sound_read_buffers[i][j] = 0xef;
- }
- }
- return 0;
-}
-
-static void sq_release_read_buffers(void)
-{
- int i;
- volatile struct dbdma_cmd *cp;
-
-
- if (sound_read_buffers) {
- cp = awacs_rx_cmds;
- for (i = 0; i < numReadBufs; i++,cp++) {
- st_le16(&cp->command, DBDMA_STOP);
- }
- /* We should probably wait for the thing to stop before we
- release the memory */
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free (sound_read_buffers[i],
- bufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- }
-}
-#endif
-
-
-static void sq_setup(int numBufs, int bufSize, char **write_buffers)
-{
-#ifdef CONFIG_PPC
- int i;
- volatile struct dbdma_cmd *cp;
-#endif /* CONFIG_PPC */
-
- sq.max_count = numBufs;
- sq.max_active = numBufs;
- sq.block_size = bufSize;
- sq.buffers = write_buffers;
-
- sq.front = sq.count = 0;
- sq.rear = -1;
- sq.syncing = 0;
- sq.active = 0;
-
-#ifdef CONFIG_ATARI
- sq.ignore_int = 0;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- sq.block_size_half = sq.block_size>>1;
- sq.block_size_quarter = sq.block_size_half>>1;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
- cp = awacs_tx_cmds;
- memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
- for (i = 0; i < numBufs; ++i, ++cp) {
- st_le32(&cp->phy_addr, virt_to_bus(write_buffers[i]));
- }
- st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
- st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
-#endif /* CONFIG_PPC */
-}
-
-#ifdef CONFIG_PPC
-static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
-{
- int i;
- volatile struct dbdma_cmd *cp;
-
- read_sq.max_count = numBufs;
- read_sq.max_active = numBufs;
- read_sq.block_size = bufSize;
- read_sq.buffers = read_buffers;
-
- read_sq.front = read_sq.count = 0;
- read_sq.rear = 0;
- read_sq.rear_size = 0;
- read_sq.syncing = 0;
- read_sq.active = 0;
-
- cp = awacs_rx_cmds;
- memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
-
- /* Set dma buffers up in a loop */
- for (i = 0; i < numBufs; i++,cp++) {
- st_le32(&cp->phy_addr, virt_to_bus(read_buffers[i]));
- st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
- st_le16(&cp->req_count, read_sq.block_size);
- st_le16(&cp->xfer_status, 0);
- }
-
- /* The next two lines make the thing loop around.
- */
- st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
- st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
-
- /* Don't start until the first read is done.
- * This will also abort any operations in progress if the DMA
- * happens to be running (and it shouldn't).
- */
- out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
-
-}
-#endif /* CONFIG_PPC */
-
-
-static void sq_play(void)
-{
- (*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
- loff_t *ppos)
-{
- ssize_t uWritten = 0;
- u_char *dest;
- ssize_t uUsed, bUsed, bLeft;
-
- /* ++TeSche: Is something like this necessary?
- * Hey, that's an honest question! Or does any other part of the
- * filesystem already checks this situation? I really don't know.
- */
- if (uLeft == 0)
- return 0;
-
- /* The interrupt doesn't start to play the last, incomplete frame.
- * Thus we can append to it without disabling the interrupts! (Note
- * also that sq.rear isn't affected by the interrupt.)
- */
-
- if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
- dest = sq_block_address(sq.rear);
- bUsed = sq.rear_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- sq.rear_size = bUsed;
- }
-
- do {
- while (sq.count == sq.max_active) {
- sq_play();
- if (NON_BLOCKING(sq.open_mode))
- return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(sq.action_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- return uWritten > 0 ? uWritten : -EINTR;
- }
-
- /* Here, we can avoid disabling the interrupt by first
- * copying and translating the data, and then updating
- * the sq variables. Until this is done, the interrupt
- * won't see the new frame and we can work on it
- * undisturbed.
- */
-
- dest = sq_block_address((sq.rear+1) % sq.max_count);
- bUsed = 0;
- bLeft = sq.block_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- break;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- if (bUsed) {
- sq.rear = (sq.rear+1) % sq.max_count;
- sq.rear_size = bUsed;
- sq.count++;
- }
- } while (bUsed); /* uUsed may have been 0 */
-
- sq_play();
-
- return uUsed < 0? uUsed: uWritten;
-}
-
-
-/***********/
-
-#ifdef CONFIG_PPC
-
-/* Here is how the values are used for reading.
- * The value 'active' simply indicates the DMA is running. This is
- * done so the driver semantics are DMA starts when the first read is
- * posted. The value 'front' indicates the buffer we should next
- * send to the user. The value 'rear' indicates the buffer the DMA is
- * currently filling. When 'front' == 'rear' the buffer "ring" is
- * empty (we always have an empty available). The 'rear_size' is used
- * to track partial offsets into the current buffer. Right now, I just keep
- * the DMA running. If the reader can't keep up, the interrupt tosses
- * the oldest buffer. We could also shut down the DMA in this case.
- */
-static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
- loff_t *ppos)
-{
-
- ssize_t uRead, bLeft, bUsed, uUsed;
-
- if (uLeft == 0)
- return 0;
-
- if (!read_sq.active)
- PMacRecord(); /* Kick off the record process. */
-
- uRead = 0;
-
- /* Move what the user requests, depending upon other options.
- */
- while (uLeft > 0) {
-
- /* When front == rear, the DMA is not done yet.
- */
- while (read_sq.front == read_sq.rear) {
- if (NON_BLOCKING(read_sq.open_mode)) {
- return uRead > 0 ? uRead : -EAGAIN;
- }
- SLEEP(read_sq.action_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- return uRead > 0 ? uRead : -EINTR;
- }
-
- /* The amount we move is either what is left in the
- * current buffer or what the user wants.
- */
- bLeft = read_sq.block_size - read_sq.rear_size;
- bUsed = read_sq.rear_size;
- uUsed = sound_copy_translate_read(dst, uLeft,
- read_sq.buffers[read_sq.front], &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- dst += uUsed;
- uRead += uUsed;
- uLeft -= uUsed;
- read_sq.rear_size += bUsed;
- if (read_sq.rear_size >= read_sq.block_size) {
- read_sq.rear_size = 0;
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
- return uRead;
-}
-#endif
-
-static int sq_open(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- MOD_INC_USE_COUNT;
- if (file->f_mode & FMODE_WRITE) {
- if (sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (sq.busy) {
- SLEEP(sq.open_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- }
- sq.busy = 1; /* Let's play spot-the-race-condition */
-
- if (sq_allocate_buffers()) goto err_out_nobusy;
-
- sq_setup(numBufs, bufSize<<10,sound_buffers);
- sq.open_mode = file->f_mode;
- }
-
-
-#ifdef CONFIG_PPC
- if (file->f_mode & FMODE_READ) {
- if (read_sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (read_sq.busy) {
- SLEEP(read_sq.open_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- rc = 0;
- }
- read_sq.busy = 1;
- if (sq_allocate_read_buffers()) goto err_out_nobusy;
-
- read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
- read_sq.open_mode = file->f_mode;
- }
-#endif
-
-#ifdef CONFIG_ATARI
- sq.ignore_int = 1;
-#endif /* CONFIG_ATARI */
- sound.minDev = MINOR(inode->i_rdev) & 0x0f;
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_init();
- if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
- sound_set_speed(8000);
- sound_set_stereo(0);
- sound_set_format(AFMT_MU_LAW);
- }
-
-#if 0
- if (file->f_mode == FMODE_READ) {
- /* Start dma'ing straight away */
- PMacRecord();
- }
-#endif
-
- return 0;
-
-err_out_nobusy:
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
-#ifdef CONFIG_PPC
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-#endif
-err_out:
- MOD_DEC_USE_COUNT;
- return rc;
-}
-
-
-static void sq_reset(void)
-{
- sound_silence();
- sq.active = 0;
- sq.count = 0;
- sq.front = (sq.rear+1) % sq.max_count;
-}
-
-
-static int sq_fsync(struct file *filp, struct dentry *dentry)
-{
- int rc = 0;
-
- sq.syncing = 1;
- sq_play(); /* there may be an incomplete frame waiting */
-
- while (sq.active) {
- SLEEP(sq.sync_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED) {
- /* While waiting for audio output to drain, an
- * interrupt occurred. Stop audio output immediately
- * and clear the queue. */
- sq_reset();
- rc = -EINTR;
- break;
- }
- }
-
- sq.syncing = 0;
- return rc;
-}
-
-static int sq_release(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- if (sq.busy)
- rc = sq_fsync(file, file->f_dentry);
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_silence();
-
-#ifdef CONFIG_PPC
- sq_release_read_buffers();
-#endif
- sq_release_buffers();
- MOD_DEC_USE_COUNT;
-
- /* There is probably a DOS atack here. They change the mode flag. */
- /* XXX add check here */
-#ifdef CONFIG_PPC
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-#endif
-
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
-
- /* Wake up a process waiting for the queue being released.
- * Note: There may be several processes waiting for a call
- * to open() returning. */
-
- return rc;
-}
-
-
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- u_long fmt;
- int data;
- int size, nbufs;
- audio_buf_info info;
-
- switch (cmd) {
- case SNDCTL_DSP_RESET:
- sq_reset();
- return 0;
- case SNDCTL_DSP_POST:
- case SNDCTL_DSP_SYNC:
- return sq_fsync(file, file->f_dentry);
-
- /* ++TeSche: before changing any of these it's
- * probably wise to wait until sound playing has
- * settled down. */
- case SNDCTL_DSP_SPEED:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_speed(data));
- case SNDCTL_DSP_STEREO:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data));
- case SOUND_PCM_WRITE_CHANNELS:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
- case SNDCTL_DSP_SETFMT:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_format(data));
- case SNDCTL_DSP_GETFMTS:
- fmt = 0;
- if (sound.trans) {
- if (sound.trans->ct_ulaw)
- fmt |= AFMT_MU_LAW;
- if (sound.trans->ct_alaw)
- fmt |= AFMT_A_LAW;
- if (sound.trans->ct_s8)
- fmt |= AFMT_S8;
- if (sound.trans->ct_u8)
- fmt |= AFMT_U8;
- if (sound.trans->ct_s16be)
- fmt |= AFMT_S16_BE;
- if (sound.trans->ct_u16be)
- fmt |= AFMT_U16_BE;
- if (sound.trans->ct_s16le)
- fmt |= AFMT_S16_LE;
- if (sound.trans->ct_u16le)
- fmt |= AFMT_U16_LE;
- }
- return IOCTL_OUT(arg, fmt);
- case SNDCTL_DSP_GETBLKSIZE:
- size = sq.block_size
- * sound.soft.size * (sound.soft.stereo + 1)
- / (sound.hard.size * (sound.hard.stereo + 1));
- return IOCTL_OUT(arg, size);
- case SNDCTL_DSP_SUBDIVIDE:
- break;
- case SNDCTL_DSP_SETFRAGMENT:
- if (sq.count || sq.active || sq.syncing)
- return -EINVAL;
- IOCTL_IN(arg, size);
- nbufs = size >> 16;
- if (nbufs < 2 || nbufs > numBufs)
- nbufs = numBufs;
- size &= 0xffff;
- if (size >= 8 && size <= 29) {
- size = 1 << size;
- size *= sound.hard.size * (sound.hard.stereo + 1);
- size /= sound.soft.size * (sound.soft.stereo + 1);
- if (size > (bufSize << 10))
- size = bufSize << 10;
- } else
- size = bufSize << 10;
- sq_setup(numBufs, size, sound_buffers);
- sq.max_active = nbufs;
- return 0;
- case SNDCTL_DSP_GETOSPACE:
- info.fragments = sq.max_active - sq.count;
- info.fragstotal = sq.max_active;
- info.fragsize = sq.block_size;
- info.bytes = info.fragments * info.fragsize;
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
-
- default:
- return mixer_ioctl(inode, file, cmd, arg);
- }
- return -EINVAL;
-}
-
-
-
-static struct file_operations sq_fops =
-{
- llseek: sound_lseek,
- write: sq_write,
- ioctl: sq_ioctl,
- open: sq_open,
- release: sq_release,
-#ifdef CONFIG_PPC
- read: sq_read, /* sq_read */
-#endif
-};
-
-
-static void __init sq_init(void)
-{
-#ifndef MODULE
- int sq_unit;
-#endif
- sq_unit = register_sound_dsp(&sq_fops, -1);
- if (sq_unit < 0)
- return;
-
- init_waitqueue_head(&sq.action_queue);
- init_waitqueue_head(&sq.open_queue);
- init_waitqueue_head(&sq.sync_queue);
-
-#ifdef CONFIG_PPC
- init_waitqueue_head(&read_sq.action_queue);
- init_waitqueue_head(&read_sq.open_queue);
- init_waitqueue_head(&read_sq.sync_queue);
-#endif
-
- sq.busy = 0;
-#ifdef CONFIG_PPC
- read_sq.busy = 0;
-#endif
-
- /* whatever you like as startup mode for /dev/dsp,
- * (/dev/audio hasn't got a startup mode). note that
- * once changed a new open() will *not* restore these!
- */
- sound.dsp.format = AFMT_U8;
- sound.dsp.stereo = 0;
- sound.dsp.size = 8;
-
- /* set minimum rate possible without expanding */
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- sound.dsp.speed = 6258;
- break;
- case DMASND_FALCON:
- sound.dsp.speed = 8195;
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- sound.dsp.speed = 8000;
- break;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
- case DMASND_AWACS:
- sound.dsp.speed = 8000;
- break;
-#endif /* CONFIG_PPC */
- }
-
- /* before the first open to /dev/dsp this wouldn't be set */
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
-
- sound_silence();
-}
-
-/*
- * /dev/sndstat
- */
-
-
-/* state.buf should not overflow! */
-
-static int state_open(struct inode *inode, struct file *file)
-{
- char *buffer = state.buf, *mach = "";
-#ifdef CONFIG_PPC
- char awacs_buf[64];
-#endif
- int len = 0;
-
- if (state.busy)
- return -EBUSY;
-
- MOD_INC_USE_COUNT;
- state.ptr = 0;
- state.busy = 1;
-
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- case DMASND_FALCON:
- mach = "Atari ";
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- mach = "Amiga ";
- break;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
- case DMASND_AWACS:
- sprintf(awacs_buf, "PowerMac (AWACS rev %d) ", awacs_revision);
- mach = awacs_buf;
- break;
-#endif /* CONFIG_PPC */
- }
- len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
- len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- len += sprintf(buffer+len, " (mu-law)");
- break;
- case AFMT_A_LAW:
- len += sprintf(buffer+len, " (A-law)");
- break;
- case AFMT_U8:
- len += sprintf(buffer+len, " (unsigned 8 bit)");
- break;
- case AFMT_S8:
- len += sprintf(buffer+len, " (signed 8 bit)");
- break;
- case AFMT_S16_BE:
- len += sprintf(buffer+len, " (signed 16 bit big)");
- break;
- case AFMT_U16_BE:
- len += sprintf(buffer+len, " (unsigned 16 bit big)");
- break;
- case AFMT_S16_LE:
- len += sprintf(buffer+len, " (signed 16 bit little)");
- break;
- case AFMT_U16_LE:
- len += sprintf(buffer+len, " (unsigned 16 bit little)");
- break;
- }
- len += sprintf(buffer+len, "\n");
- len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
- sound.soft.speed, sound.hard.speed);
- len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
- sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
- sound.volume_right);
- len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
- sound.bass);
- len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
- sound.treble);
- break;
- case DMASND_FALCON:
- len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
- sound.volume_right);
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
- sound.volume_right);
- break;
-#endif /* CONFIG_AMIGA */
- }
- len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
- " sq.max_active = %d\n",
- sq.block_size, sq.max_count, sq.max_active);
- len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
- sq.rear_size);
- len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
- sq.active, sq.syncing);
- state.len = len;
- return 0;
-}
-
-
-static int state_release(struct inode *inode, struct file *file)
-{
- state.busy = 0;
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-
-static ssize_t state_read(struct file *file, char *buf, size_t count,
- loff_t *ppos)
-{
- int n = state.len - state.ptr;
- if (n > count)
- n = count;
- if (n <= 0)
- return 0;
- if (copy_to_user(buf, &state.buf[state.ptr], n))
- return -EFAULT;
- state.ptr += n;
- return n;
-}
-
-
-static struct file_operations state_fops =
-{
- llseek: sound_lseek,
- read: state_read,
- open: state_open,
- release: state_release,
-};
-
-
-static void __init state_init(void)
-{
-#ifndef MODULE
- int state_unit;
-#endif
- state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
- if (state_unit < 0)
- return;
- state.busy = 0;
-}
-
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
- return -ESPIPE;
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-void __init dmasound_init(void)
-{
- int has_sound = 0;
-#ifdef CONFIG_PPC
- struct device_node *np;
-#endif
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
- switch (m68k_machtype) {
-#ifdef CONFIG_ATARI
- case MACH_ATARI:
- if (ATARIHW_PRESENT(PCM_8BIT)) {
- if (ATARIHW_PRESENT(CODEC))
- sound.mach = machFalcon;
- else if (ATARIHW_PRESENT(MICROWIRE))
- sound.mach = machTT;
- else
- break;
- if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
- has_sound = 1;
- else
- printk("DMA sound driver: Timer A interrupt already in use\n");
- }
- break;
-
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- if (AMIGAHW_PRESENT(AMI_AUDIO)) {
- sound.mach = machAmiga;
- has_sound = 1;
- }
- break;
-#endif /* CONFIG_AMIGA */
- }
-#endif /* __mc68000__||CONFIG_APUS */
-
-#ifdef CONFIG_PPC
- awacs_subframe = 0;
- awacs_revision = 0;
- np = find_devices("awacs");
- if (np == 0) {
- /*
- * powermac G3 models have a node called "davbus"
- * with a child called "sound".
- */
- struct device_node *sound;
- np = find_devices("davbus");
- sound = find_devices("sound");
- if (sound != 0 && sound->parent == np) {
- unsigned int *prop, l, i;
- prop = (unsigned int *)
- get_property(sound, "sub-frame", 0);
- if (prop != 0 && *prop >= 0 && *prop < 16)
- awacs_subframe = *prop;
- if (device_is_compatible(sound, "burgundy"))
- awacs_revision = AWACS_BURGUNDY;
-
- /* look for a property saying what sample rates
- are available */
- for (i = 0; i < 8; ++i)
- awacs_freqs_ok[i] = 0;
- prop = (unsigned int *) get_property
- (sound, "sample-rates", &l);
- if (prop == 0)
- prop = (unsigned int *) get_property
- (sound, "output-frame-rates", &l);
- if (prop != 0) {
- for (l /= sizeof(int); l > 0; --l) {
- /* sometimes the rate is in the
- high-order 16 bits (?) */
- unsigned int r = *prop++;
- if (r >= 0x10000)
- r >>= 16;
- for (i = 0; i < 8; ++i) {
- if (r == awacs_freqs[i]) {
- awacs_freqs_ok[i] = 1;
- break;
- }
- }
- }
- } else {
- /* assume just 44.1k is OK */
- awacs_freqs_ok[0] = 1;
- }
- }
- }
- if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
- int vol;
- sound.mach = machPMac;
- has_sound = 1;
-
- awacs = (volatile struct awacs_regs *)
- ioremap(np->addrs[0].address, 0x80);
- awacs_txdma = (volatile struct dbdma_regs *)
- ioremap(np->addrs[1].address, 0x100);
- awacs_rxdma = (volatile struct dbdma_regs *)
- ioremap(np->addrs[2].address, 0x100);
-
- awacs_irq = np->intrs[0].line;
- awacs_tx_irq = np->intrs[1].line;
- awacs_rx_irq = np->intrs[2].line;
-
- awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
- GFP_KERNEL);
- if (awacs_tx_cmd_space == NULL) {
- printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
- return;
- }
- awacs_node = np;
-#ifdef CONFIG_PMAC_PBOOK
- if (machine_is_compatible("PowerBook1,1")
- || machine_is_compatible("AAPL,PowerBook1998")) {
- feature_set(np, FEATURE_Sound_CLK_enable);
- feature_set(np, FEATURE_Sound_power);
- /* Shorter delay will not work */
- mdelay(1000);
- }
-#endif
- awacs_tx_cmds = (volatile struct dbdma_cmd *)
- DBDMA_ALIGN(awacs_tx_cmd_space);
-
-
- awacs_rx_cmd_space = kmalloc((numReadBufs + 4) * sizeof(struct dbdma_cmd),
- GFP_KERNEL);
- if (awacs_rx_cmd_space == NULL) {
- printk("DMA sound driver: No memory for input");
- }
- awacs_rx_cmds = (volatile struct dbdma_cmd *)
- DBDMA_ALIGN(awacs_rx_cmd_space);
-
-
-
- awacs_reg[0] = MASK_MUX_CD;
- awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
- /* get default volume from nvram */
- vol = (~nvram_read_byte(0x1308) & 7) << 1;
- awacs_reg[2] = vol + (vol << 6);
- awacs_reg[4] = vol + (vol << 6);
- out_le32(&awacs->control, 0x11);
- awacs_write(awacs_reg[0] + MASK_ADDR0);
- awacs_write(awacs_reg[1] + MASK_ADDR1);
- awacs_write(awacs_reg[2] + MASK_ADDR2);
- awacs_write(awacs_reg[4] + MASK_ADDR4);
-
- /* Initialize recent versions of the awacs */
- if (awacs_revision == 0) {
- awacs_revision =
- (in_le32(&awacs->codec_stat) >> 12) & 0xf;
- if (awacs_revision == 3) {
- mdelay(100);
- awacs_write(0x6000);
- mdelay(2);
- awacs_write(awacs_reg[1] + MASK_ADDR1);
- awacs_enable_amp(100 * 0x101);
- }
- }
- if (awacs_revision >= AWACS_BURGUNDY)
- awacs_burgundy_init();
-
- /* Initialize beep stuff */
- beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
- orig_mksound = kd_mksound;
- kd_mksound = awacs_mksound;
- beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
- if (beep_buf == NULL)
- printk(KERN_WARNING "dmasound: no memory for "
- "beep buffer\n");
-#ifdef CONFIG_PMAC_PBOOK
- pmu_register_sleep_notifier(&awacs_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-
- /* Powerbooks have odd ways of enabling inputs such as
- an expansion-bay CD or sound from an internal modem
- or a PC-card modem. */
- if (machine_is_compatible("AAPL,3400/2400")
- || machine_is_compatible("AAPL,3500")) {
- is_pbook_3400 = 1;
- /*
- * Enable CD and PC-card sound inputs.
- * This is done by reading from address
- * f301a000, + 0x10 to enable the expansion-bay
- * CD sound input, + 0x80 to enable the PC-card
- * sound input. The 0x100 enables the SCSI bus
- * terminator power.
- */
- latch_base = (unsigned char *) ioremap
- (0xf301a000, 0x1000);
- in_8(latch_base + 0x190);
- } else if (machine_is_compatible("PowerBook1,1")
- || machine_is_compatible("AAPL,PowerBook1998")) {
- struct device_node* mio;
- macio_base = 0;
- is_pbook_G3 = 1;
- for (mio = np->parent; mio; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0
- && mio->n_addrs > 0) {
- macio_base = (unsigned char *) ioremap
- (mio->addrs[0].address, 0x40);
- break;
- }
- }
- /* enable CD sound input */
- if (macio_base)
- out_8(macio_base + 0x37, 3);
- }
- }
-#endif /* CONFIG_PPC */
-
- if (!has_sound)
- return;
-
- /* Set up sound queue, /dev/audio and /dev/dsp. */
-
- /* Set default settings. */
- sq_init();
-
- /* Set up /dev/sndstat. */
- state_init();
-
- /* Set up /dev/mixer. */
- mixer_init();
-
- if (!sound.mach.irqinit()) {
- printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
- return;
- }
-#ifdef MODULE
- irq_installed = 1;
-#endif
-
- printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
- numBufs, bufSize);
-
- return;
-}
-
-
-static int __init dmasound_setup(char *str)
-{
- int ints[6];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- /* check the bootstrap parameter for "dmasound=" */
-
- switch (ints[0]) {
- case 3:
- if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
- printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
- else
- catchRadius = ints[3];
- /* fall through */
- case 2:
- if (ints[1] < MIN_BUFFERS)
- printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
- else
- numBufs = ints[1];
- if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
- printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
- else
- bufSize = ints[2];
- break;
- case 0:
- break;
- default:
- printk("dmasound_setup: illegal number of arguments\n");
- return 0;
- }
-
- return 1;
-}
-
-__setup("dmasound=", dmasound_setup);
-
-
-#ifdef MODULE
-
-int init_module(void)
-{
- dmasound_init();
- return 0;
-}
-
-
-void cleanup_module(void)
-{
- if (irq_installed) {
- sound_silence();
- sound.mach.irqcleanup();
- }
-
-#ifdef CONFIG_PPC
- sq_release_read_buffers();
-#endif
- sq_release_buffers();
-
- if (mixer_unit >= 0)
- unregister_sound_mixer(mixer_unit);
- if (state_unit >= 0)
- unregister_sound_special(state_unit);
- if (sq_unit >= 0)
- unregister_sound_dsp(sq_unit);
-}
-
-#endif /* MODULE */
diff --git a/drivers/sound/dmasound.h b/drivers/sound/dmasound.h
deleted file mode 100644
index fec3ad84e..000000000
--- a/drivers/sound/dmasound.h
+++ /dev/null
@@ -1,36 +0,0 @@
-
-/* linux/drivers/sound/dmasound.h */
-
-/*
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-
-#define SND_NDEVS 256 /* Number of supported devices */
-#define SND_DEV_CTL 0 /* Control port /dev/mixer */
-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
- synthesizer and MIDI output) */
-#define SND_DEV_MIDIN 2 /* Raw midi access */
-#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6 /* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS SND_DEV_SNDPROC
-
-#define DSP_DEFAULT_SPEED 8000
-
-#define ON 1
-#define OFF 0
-
-#define MAX_AUDIO_DEV 5
-#define MAX_MIXER_DEV 2
-#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 6
-#define MAX_TIMER_DEV 3
diff --git a/drivers/sound/dmasound/.cvsignore b/drivers/sound/dmasound/.cvsignore
new file mode 100644
index 000000000..88fff7fc4
--- /dev/null
+++ b/drivers/sound/dmasound/.cvsignore
@@ -0,0 +1,5 @@
+.depend
+.*.flags
+.defines
+local.h
+configure
diff --git a/drivers/sound/dmasound/Config.in b/drivers/sound/dmasound/Config.in
new file mode 100644
index 000000000..c5f4c3c53
--- /dev/null
+++ b/drivers/sound/dmasound/Config.in
@@ -0,0 +1,27 @@
+# drivers/sound/dmasound/Config.in
+
+if [ "$CONFIG_ATARI" = "y" ]; then
+ dep_tristate ' Atari DMA sound support' CONFIG_DMASOUND_ATARI $CONFIG_SOUND
+fi
+if [ "$CONFIG_ALL_PPC" = "y" ]; then
+ dep_tristate ' PowerMac DMA sound support' CONFIG_DMASOUND_AWACS $CONFIG_SOUND
+fi
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_APUS" = "y" ]; then
+ dep_tristate ' Amiga DMA sound support' CONFIG_DMASOUND_PAULA $CONFIG_SOUND
+fi
+if [ "$CONFIG_Q40" = "y" ]; then
+ dep_tristate ' Q40 sound support' CONFIG_DMASOUND_Q40 $CONFIG_SOUND
+fi
+if [ "$CONFIG_DMASOUND_ATARI" = "y" -o \
+ "$CONFIG_DMASOUND_AWACS" = "y" -o \
+ "$CONFIG_DMASOUND_PAULA" = "y" -o \
+ "$CONFIG_DMASOUND_Q40" = "y" ]; then
+ define_tristate CONFIG_DMASOUND y
+else
+ if [ "$CONFIG_DMASOUND_ATARI" = "m" -o \
+ "$CONFIG_DMASOUND_AWACS" = "m" -o \
+ "$CONFIG_DMASOUND_PAULA" = "m" -o \
+ "$CONFIG_DMASOUND_Q40" = "m" ]; then
+ define_tristate CONFIG_DMASOUND m
+ fi
+fi
diff --git a/drivers/sound/dmasound/Makefile b/drivers/sound/dmasound/Makefile
new file mode 100644
index 000000000..535146de2
--- /dev/null
+++ b/drivers/sound/dmasound/Makefile
@@ -0,0 +1,38 @@
+#
+# Makefile for the DMA sound driver
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET :=
+O_OBJS :=
+OX_OBJS :=
+M_OBJS :=
+MX_OBJS :=
+
+export-objs := dmasound_core.o
+
+obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o
+obj-$(CONFIG_DMASOUND_AWACS) += dmasound_core.o dmasound_awacs.o
+obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o
+obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+
+ifeq ($(CONFIG_DMASOUND),y)
+ O_TARGET = dmasound.o
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/sound/dmasound/dmasound.h b/drivers/sound/dmasound/dmasound.h
new file mode 100644
index 000000000..985785e74
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound.h
@@ -0,0 +1,246 @@
+
+/*
+ * linux/drivers/sound/dmasound.h
+ *
+ *
+ * Minor numbers for the sound driver.
+ *
+ * Unfortunately Creative called the codec chip of SB as a DSP. For this
+ * reason the /dev/dsp is reserved for digitized audio use. There is a
+ * device for true DSP processors but it will be called something else.
+ * In v3.0 it's /dev/sndproc but this could be a temporary solution.
+ */
+
+
+#include <linux/config.h>
+
+
+#define SND_NDEVS 256 /* Number of supported devices */
+#define SND_DEV_CTL 0 /* Control port /dev/mixer */
+#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
+ synthesizer and MIDI output) */
+#define SND_DEV_MIDIN 2 /* Raw midi access */
+#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
+#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
+#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
+#define SND_DEV_STATUS 6 /* /dev/sndstat */
+/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
+#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
+#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS SND_DEV_SNDPROC
+
+#define DSP_DEFAULT_SPEED 8000
+
+#define ON 1
+#define OFF 0
+
+#define MAX_AUDIO_DEV 5
+#define MAX_MIXER_DEV 2
+#define MAX_SYNTH_DEV 3
+#define MAX_MIDI_DEV 6
+#define MAX_TIMER_DEV 3
+
+
+#define MAX_CATCH_RADIUS 10
+#define MIN_BUFFERS 4
+#define MIN_BUFSIZE 4 /* in KB */
+#define MAX_BUFSIZE 128 /* Limit for Amiga in KB */
+
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
+#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
+
+#define IOCTL_IN(arg, ret) \
+ do { int error = get_user(ret, (int *)(arg)); \
+ if (error) return error; \
+ } while (0)
+#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
+
+static inline int ioctl_return(int *addr, int value)
+{
+ return value < 0 ? value : put_user(value, addr);
+}
+
+
+ /*
+ * Configuration
+ */
+
+#undef HAS_8BIT_TABLES
+#undef HAS_14BIT_TABLES
+#undef HAS_16BIT_TABLES
+#undef HAS_RECORD
+
+#if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\
+ defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\
+ defined(CONFIG_DMASOUND_Q40) || defined(CONFIG_DMASOUND_Q40_MODULE)
+#define HAS_8BIT_TABLES
+#endif
+#if defined(CONFIG_DMASOUND_AWACS) || defined(CONFIG_DMASOUND_AWACS_MODULE)
+#define HAS_16BIT_TABLES
+#define HAS_RECORD
+#endif
+
+
+ /*
+ * Initialization
+ */
+
+extern int dmasound_init(void);
+extern void dmasound_deinit(void);
+
+
+ /*
+ * Machine definitions
+ */
+
+typedef struct {
+ const char *name;
+ const char *name2;
+ void (*open)(void);
+ void (*release)(void);
+ void *(*dma_alloc)(unsigned int, int);
+ void (*dma_free)(void *, unsigned int);
+ int (*irqinit)(void);
+#ifdef MODULE
+ void (*irqcleanup)(void);
+#endif /* MODULE */
+ void (*init)(void);
+ void (*silence)(void);
+ int (*setFormat)(int);
+ int (*setVolume)(int);
+ int (*setBass)(int);
+ int (*setTreble)(int);
+ int (*setGain)(int);
+ void (*play)(void);
+ void (*record)(void); /* optional */
+ void (*mixer_init)(void); /* optional */
+ int (*mixer_ioctl)(u_int, u_long); /* optional */
+ void (*write_sq_setup)(void); /* optional */
+ void (*read_sq_setup)(void); /* optional */
+ void (*sq_open)(void); /* optional */
+ int (*state_info)(char *); /* optional */
+ void (*abort_read)(void); /* optional */
+ int min_dsp_speed;
+} MACHINE;
+
+
+ /*
+ * Low level stuff
+ */
+
+typedef struct {
+ int format; /* AFMT_* */
+ int stereo; /* 0 = mono, 1 = stereo */
+ int size; /* 8/16 bit*/
+ int speed; /* speed */
+} SETTINGS;
+
+typedef struct {
+ ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+} TRANS;
+
+struct sound_settings {
+ MACHINE mach; /* machine dependent things */
+ SETTINGS hard; /* hardware settings */
+ SETTINGS soft; /* software settings */
+ SETTINGS dsp; /* /dev/dsp default settings */
+ TRANS *trans_write; /* supported translations */
+#ifdef HAS_RECORD
+ TRANS *trans_read; /* supported translations */
+#endif
+ int volume_left; /* volume (range is machine dependent) */
+ int volume_right;
+ int bass; /* tone (range is machine dependent) */
+ int treble;
+ int gain;
+ int minDev; /* minor device number currently open */
+};
+
+extern struct sound_settings dmasound;
+
+extern char dmasound_ulaw2dma8[];
+extern char dmasound_alaw2dma8[];
+extern short dmasound_ulaw2dma16[];
+extern short dmasound_alaw2dma16[];
+
+
+ /*
+ * Mid level stuff
+ */
+
+static inline int dmasound_set_volume(int volume)
+{
+ return dmasound.mach.setVolume(volume);
+}
+
+static inline int dmasound_set_bass(int bass)
+{
+ return dmasound.mach.setBass ? dmasound.mach.setBass(bass) : 50;
+}
+
+static inline int dmasound_set_treble(int treble)
+{
+ return dmasound.mach.setTreble ? dmasound.mach.setTreble(treble) : 50;
+}
+
+static inline int dmasound_set_gain(int gain)
+{
+ return dmasound.mach.setGain ? dmasound.mach.setGain(gain) : 100;
+}
+
+
+ /*
+ * Sound queue stuff, the heart of the driver
+ */
+
+struct sound_queue {
+ /* buffers allocated for this queue */
+ int numBufs;
+ int bufSize; /* in bytes */
+ char **buffers;
+
+ /* current parameters */
+ int max_count;
+ int block_size; /* in bytes */
+ int max_active;
+
+ /* it shouldn't be necessary to declare any of these volatile */
+ int front, rear, count;
+ int rear_size;
+ /*
+ * The use of the playing field depends on the hardware
+ *
+ * Atari, PMac: The number of frames that are loaded/playing
+ *
+ * Amiga: Bit 0 is set: a frame is loaded
+ * Bit 1 is set: a frame is playing
+ */
+ int active;
+ wait_queue_head_t action_queue, open_queue, sync_queue;
+ int open_mode;
+ int busy, syncing;
+};
+
+#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ)
+#define WAKE_UP(queue) (wake_up_interruptible(&queue))
+
+extern struct sound_queue dmasound_write_sq;
+extern struct sound_queue dmasound_read_sq;
+
+#define write_sq dmasound_write_sq
+#define read_sq dmasound_read_sq
+
+extern int dmasound_catchRadius;
+
+#define catchRadius dmasound_catchRadius
+
diff --git a/drivers/sound/dmasound/dmasound_atari.c b/drivers/sound/dmasound/dmasound_atari.c
new file mode 100644
index 000000000..ca6f07cbb
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_atari.c
@@ -0,0 +1,1560 @@
+
+/*
+ * linux/drivers/sound/dmasound_atari.c
+ *
+ * Atari DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/soundcard.h>
+#include <linux/mm.h>
+
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/atariints.h>
+#include <asm/atari_stram.h>
+
+#include "dmasound.h"
+
+
+extern void atari_microwire_cmd(int cmd);
+
+
+static int is_falcon;
+static int write_sq_ignore_int = 0; /* ++TeSche: used for Falcon */
+
+static int expand_bal; /* Balance factor for expanding (not volume!) */
+static int expand_data; /* Data for expanding */
+
+
+/*** Translations ************************************************************/
+
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void AtaOpen(void);
+static void AtaRelease(void);
+static void *AtaAlloc(unsigned int size, int flags);
+static void AtaFree(void *, unsigned int size);
+static int AtaIrqInit(void);
+#ifdef MODULE
+static void AtaIrqCleanUp(void);
+#endif /* MODULE */
+static int AtaSetBass(int bass);
+static int AtaSetTreble(int treble);
+static void TTSilence(void);
+static void TTInit(void);
+static int TTSetFormat(int format);
+static int TTSetVolume(int volume);
+static int TTSetGain(int gain);
+static void FalconSilence(void);
+static void FalconInit(void);
+static int FalconSetFormat(int format);
+static int FalconSetVolume(int volume);
+static void AtaPlayNextFrame(int index);
+static void AtaPlay(void);
+static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp);
+
+/*** Mid level stuff *********************************************************/
+
+static void TTMixerInit(void);
+static void FalconMixerInit(void);
+static int AtaMixerIoctl(u_int cmd, u_long arg);
+static int TTMixerIoctl(u_int cmd, u_long arg);
+static int FalconMixerIoctl(u_int cmd, u_long arg);
+static void AtaWriteSqSetup(void);
+static void AtaSqOpen(void);
+static int TTStateInfo(char *buffer);
+static int FalconStateInfo(char *buffer);
+
+
+/*** Translations ************************************************************/
+
+
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
+ : dmasound_alaw2dma8;
+ ssize_t count, used;
+ u_char *p = &frame[*frameUsed];
+
+ count = min(userCount, frameLeft);
+ if (dmasound.soft.stereo)
+ count &= ~1;
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = table[data];
+ count--;
+ }
+ *frameUsed += used;
+ return used;
+}
+
+
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ void *p = &frame[*frameUsed];
+
+ count = min(userCount, frameLeft);
+ if (dmasound.soft.stereo)
+ count &= ~1;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ *frameUsed += used;
+ return used;
+}
+
+
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft);
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = data ^ 0x80;
+ count--;
+ }
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *p++ = data ^ 0x8080;
+ count--;
+ }
+ }
+ *frameUsed += used;
+ return used;
+}
+
+
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ void *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~3;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count*4;
+ while (count > 0) {
+ u_long data;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ *p++ = data ^ 0x80008000;
+ count--;
+ }
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ count = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count*4;
+ while (count > 0) {
+ u_long data;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data);
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ count = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ *p++ = data;
+ *p++ = data;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count;
+ while (count > 0) {
+ u_long data;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data) ^ 0x80008000;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
+ : dmasound_alaw2dma8;
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ u_char data = expand_data;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 2) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c] << 8;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data |= table[c];
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ u_char data = expand_data;
+ while (frameLeft) {
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 2) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ u_char data = expand_data;
+ while (frameLeft) {
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ data ^= 0x80;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 2) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8080;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x80008000;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data);
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data) ^ 0x80008000;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static TRANS transTTNormal = {
+ ct_ulaw: ata_ct_law,
+ ct_alaw: ata_ct_law,
+ ct_s8: ata_ct_s8,
+ ct_u8: ata_ct_u8,
+};
+
+static TRANS transTTExpanding = {
+ ct_ulaw: ata_ctx_law,
+ ct_alaw: ata_ctx_law,
+ ct_s8: ata_ctx_s8,
+ ct_u8: ata_ctx_u8,
+};
+
+static TRANS transFalconNormal = {
+ ct_ulaw: ata_ct_law,
+ ct_alaw: ata_ct_law,
+ ct_s8: ata_ct_s8,
+ ct_u8: ata_ct_u8,
+ ct_s16be: ata_ct_s16be,
+ ct_u16be: ata_ct_u16be,
+ ct_s16le: ata_ct_s16le,
+ ct_u16le: ata_ct_u16le
+};
+
+static TRANS transFalconExpanding = {
+ ct_ulaw: ata_ctx_law,
+ ct_alaw: ata_ctx_law,
+ ct_s8: ata_ctx_s8,
+ ct_u8: ata_ctx_u8,
+ ct_s16be: ata_ctx_s16be,
+ ct_u16be: ata_ctx_u16be,
+ ct_s16le: ata_ctx_s16le,
+ ct_u16le: ata_ctx_u16le,
+};
+
+
+/*** Low level stuff *********************************************************/
+
+
+
+/*
+ * Atari (TT/Falcon)
+ */
+
+static void AtaOpen(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void AtaRelease(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static void *AtaAlloc(unsigned int size, int flags)
+{
+ return atari_stram_alloc( size, NULL, "dmasound" );
+}
+
+static void AtaFree(void *obj, unsigned int size)
+{
+ atari_stram_free( obj );
+}
+
+static int __init AtaIrqInit(void)
+{
+ /* Set up timer A. Timer A
+ will receive a signal upon end of playing from the sound
+ hardware. Furthermore Timer A is able to count events
+ and will cause an interrupt after a programmed number
+ of events. So all we need to keep the music playing is
+ to provide the sound hardware with new data upon
+ an interrupt from timer A. */
+ mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
+ mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
+ mfp.tim_ct_a = 8; /* Turn on event counting. */
+ /* Register interrupt handler. */
+ request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
+ AtaInterrupt);
+ mfp.int_en_a |= 0x20; /* Turn interrupt on. */
+ mfp.int_mk_a |= 0x20;
+ return 1;
+}
+
+#ifdef MODULE
+static void AtaIrqCleanUp(void)
+{
+ mfp.tim_ct_a = 0; /* stop timer */
+ mfp.int_en_a &= ~0x20; /* turn interrupt off */
+ free_irq(IRQ_MFP_TIMA, AtaInterrupt);
+}
+#endif /* MODULE */
+
+
+#define TONE_VOXWARE_TO_DB(v) \
+ (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
+#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
+
+
+static int AtaSetBass(int bass)
+{
+ dmasound.bass = TONE_VOXWARE_TO_DB(bass);
+ atari_microwire_cmd(MW_LM1992_BASS(dmasound.bass));
+ return TONE_DB_TO_VOXWARE(dmasound.bass);
+}
+
+
+static int AtaSetTreble(int treble)
+{
+ dmasound.treble = TONE_VOXWARE_TO_DB(treble);
+ atari_microwire_cmd(MW_LM1992_TREBLE(dmasound.treble));
+ return TONE_DB_TO_VOXWARE(dmasound.treble);
+}
+
+
+
+/*
+ * TT
+ */
+
+
+static void TTSilence(void)
+{
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
+}
+
+
+static void TTInit(void)
+{
+ int mode, i, idx;
+ const int freq[4] = {50066, 25033, 12517, 6258};
+
+ /* search a frequency that fits into the allowed error range */
+
+ idx = -1;
+ for (i = 0; i < arraysize(freq); i++)
+ /* this isn't as much useful for a TT than for a Falcon, but
+ * then it doesn't hurt very much to implement it for a TT too.
+ */
+ if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+ idx = i;
+ if (idx > -1) {
+ dmasound.soft.speed = freq[idx];
+ dmasound.trans_write = &transTTNormal;
+ } else
+ dmasound.trans_write = &transTTExpanding;
+
+ TTSilence();
+ dmasound.hard = dmasound.soft;
+
+ if (dmasound.hard.speed > 50066) {
+ /* we would need to squeeze the sound, but we won't do that */
+ dmasound.hard.speed = 50066;
+ mode = DMASND_MODE_50KHZ;
+ dmasound.trans_write = &transTTNormal;
+ } else if (dmasound.hard.speed > 25033) {
+ dmasound.hard.speed = 50066;
+ mode = DMASND_MODE_50KHZ;
+ } else if (dmasound.hard.speed > 12517) {
+ dmasound.hard.speed = 25033;
+ mode = DMASND_MODE_25KHZ;
+ } else if (dmasound.hard.speed > 6258) {
+ dmasound.hard.speed = 12517;
+ mode = DMASND_MODE_12KHZ;
+ } else {
+ dmasound.hard.speed = 6258;
+ mode = DMASND_MODE_6KHZ;
+ }
+
+ tt_dmasnd.mode = (dmasound.hard.stereo ?
+ DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+ DMASND_MODE_8BIT | mode;
+
+ expand_bal = -dmasound.soft.speed;
+}
+
+
+static int TTSetFormat(int format)
+{
+ /* TT sound DMA supports only 8bit modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_S8:
+ case AFMT_U8:
+ break;
+ default:
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = 8;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = 8;
+ }
+ TTInit();
+
+ return format;
+}
+
+
+#define VOLUME_VOXWARE_TO_DB(v) \
+ (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
+#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
+
+
+static int TTSetVolume(int volume)
+{
+ dmasound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+ atari_microwire_cmd(MW_LM1992_BALLEFT(dmasound.volume_left));
+ dmasound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+ atari_microwire_cmd(MW_LM1992_BALRIGHT(dmasound.volume_right));
+ return VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
+ (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8);
+}
+
+
+#define GAIN_VOXWARE_TO_DB(v) \
+ (((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
+#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)
+
+static int TTSetGain(int gain)
+{
+ dmasound.gain = GAIN_VOXWARE_TO_DB(gain);
+ atari_microwire_cmd(MW_LM1992_VOLUME(dmasound.gain));
+ return GAIN_DB_TO_VOXWARE(dmasound.gain);
+}
+
+
+
+/*
+ * Falcon
+ */
+
+
+static void FalconSilence(void)
+{
+ /* stop playback, set sample rate 50kHz for PSG sound */
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+ tt_dmasnd.int_div = 0; /* STE compatible divider */
+ tt_dmasnd.int_ctrl = 0x0;
+ tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+ tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+ tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+ tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
+}
+
+
+static void FalconInit(void)
+{
+ int divider, i, idx;
+ const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+
+ /* search a frequency that fits into the allowed error range */
+
+ idx = -1;
+ for (i = 0; i < arraysize(freq); i++)
+ /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+ * be playable without expanding, but that now a kernel runtime
+ * option
+ */
+ if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+ idx = i;
+ if (idx > -1) {
+ dmasound.soft.speed = freq[idx];
+ dmasound.trans_write = &transFalconNormal;
+ } else
+ dmasound.trans_write = &transFalconExpanding;
+
+ FalconSilence();
+ dmasound.hard = dmasound.soft;
+
+ if (dmasound.hard.size == 16) {
+ /* the Falcon can play 16bit samples only in stereo */
+ dmasound.hard.stereo = 1;
+ }
+
+ if (dmasound.hard.speed > 49170) {
+ /* we would need to squeeze the sound, but we won't do that */
+ dmasound.hard.speed = 49170;
+ divider = 1;
+ dmasound.trans_write = &transFalconNormal;
+ } else if (dmasound.hard.speed > 32780) {
+ dmasound.hard.speed = 49170;
+ divider = 1;
+ } else if (dmasound.hard.speed > 24585) {
+ dmasound.hard.speed = 32780;
+ divider = 2;
+ } else if (dmasound.hard.speed > 19668) {
+ dmasound.hard.speed = 24585;
+ divider = 3;
+ } else if (dmasound.hard.speed > 16390) {
+ dmasound.hard.speed = 19668;
+ divider = 4;
+ } else if (dmasound.hard.speed > 12292) {
+ dmasound.hard.speed = 16390;
+ divider = 5;
+ } else if (dmasound.hard.speed > 9834) {
+ dmasound.hard.speed = 12292;
+ divider = 7;
+ } else if (dmasound.hard.speed > 8195) {
+ dmasound.hard.speed = 9834;
+ divider = 9;
+ } else {
+ dmasound.hard.speed = 8195;
+ divider = 11;
+ }
+ tt_dmasnd.int_div = divider;
+
+ /* Setup Falcon sound DMA for playback */
+ tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+ tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+ tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+ tt_dmasnd.cbar_dst = 0x0000;
+ tt_dmasnd.rec_track_select = 0;
+ tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+ tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+ tt_dmasnd.mode = (dmasound.hard.stereo ?
+ DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+ ((dmasound.hard.size == 8) ?
+ DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+ DMASND_MODE_6KHZ;
+
+ expand_bal = -dmasound.soft.speed;
+}
+
+
+static int FalconSetFormat(int format)
+{
+ int size;
+ /* Falcon sound DMA supports 8bit and 16bit modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ size = 8;
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = size;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = dmasound.soft.size;
+ }
+
+ FalconInit();
+
+ return format;
+}
+
+
+/* This is for the Falcon output *attenuation* in 1.5dB steps,
+ * i.e. output level from 0 to -22.5dB in -1.5dB steps.
+ */
+#define VOLUME_VOXWARE_TO_ATT(v) \
+ ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
+#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
+
+
+static int FalconSetVolume(int volume)
+{
+ dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+ dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+ tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4;
+ return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
+ VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8;
+}
+
+
+static void AtaPlayNextFrame(int index)
+{
+ char *start, *end;
+
+ /* used by AtaPlay() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = write_sq.buffers[write_sq.front];
+ end = start+((write_sq.count == index) ? write_sq.rear_size
+ : write_sq.block_size);
+ /* end might not be a legal virtual address. */
+ DMASNDSetEnd(virt_to_phys(end - 1) + 1);
+ DMASNDSetBase(virt_to_phys(start));
+ /* Since only an even number of samples per frame can
+ be played, we might lose one byte here. (TO DO) */
+ write_sq.front = (write_sq.front+1) % write_sq.max_count;
+ write_sq.active++;
+ tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+}
+
+
+static void AtaPlay(void)
+{
+ /* ++TeSche: Note that write_sq.active is no longer just a flag but
+ * holds the number of frames the DMA is currently programmed for
+ * instead, may be 0, 1 (currently being played) or 2 (pre-programmed).
+ *
+ * Changes done to write_sq.count and write_sq.active are a bit more
+ * subtle again so now I must admit I also prefer disabling the irq
+ * here rather than considering all possible situations. But the point
+ * is that disabling the irq doesn't have any bad influence on this
+ * version of the driver as we benefit from having pre-programmed the
+ * DMA wherever possible: There's no need to reload the DMA at the
+ * exact time of an interrupt but only at some time while the
+ * pre-programmed frame is playing!
+ */
+ atari_disable_irq(IRQ_MFP_TIMA);
+
+ if (write_sq.active == 2 || /* DMA is 'full' */
+ write_sq.count <= 0) { /* nothing to do */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+
+ if (write_sq.active == 0) {
+ /* looks like there's nothing 'in' the DMA yet, so try
+ * to put two frames into it (at least one is available).
+ */
+ if (write_sq.count == 1 &&
+ write_sq.rear_size < write_sq.block_size &&
+ !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ AtaPlayNextFrame(1);
+ if (write_sq.count == 1) {
+ /* no more frames */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ if (write_sq.count == 2 &&
+ write_sq.rear_size < write_sq.block_size &&
+ !write_sq.syncing) {
+ /* hmmm, there were two frames, but the second
+ * one is not yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ AtaPlayNextFrame(2);
+ } else {
+ /* there's already a frame being played so we may only stuff
+ * one new into the DMA, but even if this may be the last
+ * frame existing the previous one is still on write_sq.count.
+ */
+ if (write_sq.count == 2 &&
+ write_sq.rear_size < write_sq.block_size &&
+ !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ AtaPlayNextFrame(2);
+ }
+ atari_enable_irq(IRQ_MFP_TIMA);
+}
+
+
+static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+#if 0
+ /* ++TeSche: if you should want to test this... */
+ static int cnt = 0;
+ if (write_sq.active == 2)
+ if (++cnt == 10) {
+ /* simulate losing an interrupt */
+ cnt = 0;
+ return;
+ }
+#endif
+
+ if (write_sq_ignore_int && is_falcon) {
+ /* ++TeSche: Falcon only: ignore first irq because it comes
+ * immediately after starting a frame. after that, irqs come
+ * (almost) like on the TT.
+ */
+ write_sq_ignore_int = 0;
+ return;
+ }
+
+ if (!write_sq.active) {
+ /* playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(write_sq.sync_queue);
+ return;
+ }
+
+ /* Probably ;) one frame is finished. Well, in fact it may be that a
+ * pre-programmed one is also finished because there has been a long
+ * delay in interrupt delivery and we've completely lost one, but
+ * there's no way to detect such a situation. In such a case the last
+ * frame will be played more than once and the situation will recover
+ * as soon as the irq gets through.
+ */
+ write_sq.count--;
+ write_sq.active--;
+
+ if (!write_sq.active) {
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ write_sq_ignore_int = 1;
+ }
+
+ WAKE_UP(write_sq.action_queue);
+ /* At least one block of the queue is free now
+ so wake up a writing process blocked because
+ of a full queue. */
+
+ if ((write_sq.active != 1) || (write_sq.count != 1))
+ /* We must be a bit carefully here: write_sq.count indicates the
+ * number of buffers used and not the number of frames to be
+ * played. If write_sq.count==1 and write_sq.active==1 that
+ * means the only remaining frame was already programmed
+ * earlier (and is currently running) so we mustn't call
+ * AtaPlay() here, otherwise we'll play one frame too much.
+ */
+ AtaPlay();
+
+ if (!write_sq.active) WAKE_UP(write_sq.sync_queue);
+ /* We are not playing after AtaPlay(), so there
+ is nothing to play any more. Wake up a process
+ waiting for audio output to drain. */
+}
+
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+#define RECLEVEL_VOXWARE_TO_GAIN(v) \
+ ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
+#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
+
+
+static void __init TTMixerInit(void)
+{
+ atari_microwire_cmd(MW_LM1992_VOLUME(0));
+ dmasound.volume_left = 0;
+ atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+ dmasound.volume_right = 0;
+ atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+ atari_microwire_cmd(MW_LM1992_TREBLE(0));
+ atari_microwire_cmd(MW_LM1992_BASS(0));
+}
+
+static void __init FalconMixerInit(void)
+{
+ dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+ dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+}
+
+static int AtaMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_SPEAKER:
+ if (is_falcon || MACH_IS_TT) {
+ int porta;
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = sound_ym.rd_data_reg_sel;
+ sti();
+ return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+ }
+ break;
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_volume(data));
+ case SOUND_MIXER_WRITE_SPEAKER:
+ if (is_falcon || MACH_IS_TT) {
+ int porta;
+ IOCTL_IN(arg, data);
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+ (data < 50 ? 0x40 : 0);
+ sound_ym.wd_data = porta;
+ sti();
+ return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+ }
+ }
+ return -EINVAL;
+}
+
+
+static int TTMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_RECMASK:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_READ_DEVMASK:
+ return IOCTL_OUT(arg,
+ SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+ (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
+ case SOUND_MIXER_READ_STEREODEVS:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg,
+ VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
+ (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8));
+ case SOUND_MIXER_READ_BASS:
+ return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass));
+ case SOUND_MIXER_READ_TREBLE:
+ return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble));
+ case SOUND_MIXER_READ_OGAIN:
+ return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain));
+ case SOUND_MIXER_WRITE_BASS:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_bass(data));
+ case SOUND_MIXER_WRITE_TREBLE:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_treble(data));
+ case SOUND_MIXER_WRITE_OGAIN:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_gain(data));
+ }
+ return AtaMixerIoctl(cmd, arg);
+}
+
+static int FalconMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_RECMASK:
+ return IOCTL_OUT(arg, SOUND_MASK_MIC);
+ case SOUND_MIXER_READ_DEVMASK:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
+ case SOUND_MIXER_READ_STEREODEVS:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg,
+ VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
+ VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8);
+ case SOUND_MIXER_READ_CAPS:
+ return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
+ case SOUND_MIXER_WRITE_MIC:
+ IOCTL_IN(arg, data);
+ tt_dmasnd.input_gain =
+ RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
+ RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
+ /* fall thru, return set value */
+ case SOUND_MIXER_READ_MIC:
+ return IOCTL_OUT(arg,
+ RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+ RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
+ }
+ return AtaMixerIoctl(cmd, arg);
+}
+
+static void AtaWriteSqSetup(void)
+{
+ write_sq_ignore_int = 0;
+}
+
+static void AtaSqOpen(void)
+{
+ write_sq_ignore_int = 1;
+}
+
+static int TTStateInfo(char *buffer)
+{
+ int len = 0;
+ len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+ dmasound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+ dmasound.volume_right);
+ len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+ dmasound.bass);
+ len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+ dmasound.treble);
+ return len;
+}
+
+static int FalconStateInfo(char *buffer)
+{
+ int len = 0;
+ len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+ dmasound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+ dmasound.volume_right);
+ return len;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machTT = {
+ name: "Atari",
+ name2: "TT",
+ open: AtaOpen,
+ release: AtaRelease,
+ dma_alloc: AtaAlloc,
+ dma_free: AtaFree,
+ irqinit: AtaIrqInit,
+#ifdef MODULE
+ irqcleanup: AtaIrqCleanUp,
+#endif /* MODULE */
+ init: TTInit,
+ silence: TTSilence,
+ setFormat: TTSetFormat,
+ setVolume: TTSetVolume,
+ setBass: AtaSetBass,
+ setTreble: AtaSetTreble,
+ setGain: TTSetGain,
+ play: AtaPlay,
+ mixer_init: TTMixerInit,
+ mixer_ioctl: TTMixerIoctl,
+ write_sq_setup: AtaWriteSqSetup,
+ sq_open: AtaSqOpen,
+ state_info: TTStateInfo,
+ min_dsp_speed: 6258,
+};
+
+static MACHINE machFalcon = {
+ name: "Atari",
+ name2: "FALCON",
+ dma_alloc: AtaAlloc,
+ dma_free: AtaFree,
+ irqinit: AtaIrqInit,
+#ifdef MODULE
+ irqcleanup: AtaIrqCleanUp,
+#endif /* MODULE */
+ init: FalconInit,
+ silence: FalconSilence,
+ setFormat: FalconSetFormat,
+ setVolume: FalconSetVolume,
+ setBass: AtaSetBass,
+ setTreble: AtaSetTreble,
+ play: AtaPlay,
+ mixer_init: FalconMixerInit,
+ mixer_ioctl: FalconMixerIoctl,
+ write_sq_setup: AtaWriteSqSetup,
+ sq_open: AtaSqOpen,
+ state_info: FalconStateInfo,
+ min_dsp_speed: 8195,
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+static int __init dmasound_atari_init(void)
+{
+ if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) {
+ if (ATARIHW_PRESENT(CODEC)) {
+ dmasound.mach = machFalcon;
+ is_falcon = 1;
+ } else if (ATARIHW_PRESENT(MICROWIRE)) {
+ dmasound.mach = machTT;
+ is_falcon = 0;
+ } else
+ return -ENODEV;
+ if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+ return dmasound_init();
+ else {
+ printk("DMA sound driver: Timer A interrupt already in use\n");
+ return -EBUSY;
+ }
+ }
+ return -ENODEV;
+}
+
+static void __exit dmasound_atari_cleanup(void)
+{
+ dmasound_deinit();
+}
+
+module_init(dmasound_atari_init);
+module_exit(dmasound_atari_cleanup);
diff --git a/drivers/sound/dmasound/dmasound_awacs.c b/drivers/sound/dmasound/dmasound_awacs.c
new file mode 100644
index 000000000..55669c65c
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_awacs.c
@@ -0,0 +1,2113 @@
+
+/*
+ * linux/drivers/sound/dmasound_awacs.c
+ *
+ * PowerMac DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/adb.h>
+#include <linux/nvram.h>
+#include <linux/vt_kern.h>
+#include <linux/cuda.h>
+
+#include <asm/uaccess.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+
+#include "awacs_defs.h"
+#include "dmasound.h"
+
+
+/*
+ * Interrupt numbers and addresses, obtained from the device tree.
+ */
+static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
+static volatile struct awacs_regs *awacs;
+static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
+static int awacs_rate_index;
+static int awacs_subframe;
+static int awacs_spkr_vol;
+static struct device_node* awacs_node;
+
+static char awacs_name[64];
+static int awacs_revision;
+#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
+
+/*
+ * Space for the DBDMA command blocks.
+ */
+static void *awacs_tx_cmd_space;
+static volatile struct dbdma_cmd *awacs_tx_cmds;
+
+static void *awacs_rx_cmd_space;
+static volatile struct dbdma_cmd *awacs_rx_cmds;
+
+/*
+ * Cached values of AWACS registers (we can't read them).
+ * Except on the burgundy. XXX
+ */
+int awacs_reg[5];
+
+#define HAS_16BIT_TABLES
+#undef HAS_8BIT_TABLES
+
+/*
+ * Stuff for outputting a beep. The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+ 0, 40, 79, 117, 153, 187, 218, 245,
+ 269, 288, 304, 316, 323, 327, 327, 324,
+ 318, 310, 299, 288, 275, 262, 249, 236,
+ 224, 213, 204, 196, 190, 186, 183, 182,
+ 182, 183, 186, 189, 192, 196, 200, 203,
+ 206, 208, 209, 209, 209, 207, 204, 201,
+ 197, 193, 188, 183, 179, 174, 170, 166,
+ 163, 161, 160, 159, 159, 160, 161, 162,
+ 164, 166, 168, 169, 171, 171, 171, 170,
+ 169, 167, 163, 159, 155, 150, 144, 139,
+ 133, 128, 122, 117, 113, 110, 107, 105,
+ 103, 103, 103, 103, 104, 104, 105, 105,
+ 105, 103, 101, 97, 92, 86, 78, 68,
+ 58, 45, 32, 18, 3, -11, -26, -41,
+ -55, -68, -79, -88, -95, -100, -102, -102,
+ -99, -93, -85, -75, -62, -48, -33, -16,
+ 0, 16, 33, 48, 62, 75, 85, 93,
+ 99, 102, 102, 100, 95, 88, 79, 68,
+ 55, 41, 26, 11, -3, -18, -32, -45,
+ -58, -68, -78, -86, -92, -97, -101, -103,
+ -105, -105, -105, -104, -104, -103, -103, -103,
+ -103, -105, -107, -110, -113, -117, -122, -128,
+ -133, -139, -144, -150, -155, -159, -163, -167,
+ -169, -170, -171, -171, -171, -169, -168, -166,
+ -164, -162, -161, -160, -159, -159, -160, -161,
+ -163, -166, -170, -174, -179, -183, -188, -193,
+ -197, -201, -204, -207, -209, -209, -209, -208,
+ -206, -203, -200, -196, -192, -189, -186, -183,
+ -182, -182, -183, -186, -190, -196, -204, -213,
+ -224, -236, -249, -262, -275, -288, -299, -310,
+ -318, -324, -327, -327, -323, -316, -304, -288,
+ -269, -245, -218, -187, -153, -117, -79, -40,
+};
+
+#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
+#define BEEP_BUFLEN 512
+#define BEEP_VOLUME 15 /* 0 - 100 */
+
+static int beep_volume = BEEP_VOLUME;
+static int beep_playing = 0;
+static int awacs_beep_state = 0;
+static short *beep_buf;
+static volatile struct dbdma_cmd *beep_dbdma_cmd;
+static void (*orig_mksound)(unsigned int, unsigned int);
+static int is_pbook_3400;
+static unsigned char *latch_base;
+static int is_pbook_G3;
+static unsigned char *macio_base;
+
+/* Burgundy functions */
+static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
+static unsigned awacs_burgundy_rcw(unsigned addr);
+static void awacs_burgundy_write_volume(unsigned address, int volume);
+static int awacs_burgundy_read_volume(unsigned address);
+static void awacs_burgundy_write_mvolume(unsigned address, int volume);
+static int awacs_burgundy_read_mvolume(unsigned address);
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Stuff for restoring after a sleep.
+ */
+static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier awacs_sleep_notifier = {
+ awacs_sleep_notify, SLEEP_LEVEL_SOUND,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+static int expand_bal; /* Balance factor for expanding (not volume!) */
+static int expand_data; /* Data for expanding */
+
+
+/*** Translations ************************************************************/
+
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void PMacOpen(void);
+static void PMacRelease(void);
+static void *PMacAlloc(unsigned int size, int flags);
+static void PMacFree(void *ptr, unsigned int size);
+static int PMacIrqInit(void);
+#ifdef MODULE
+static void PMacIrqCleanup(void);
+#endif
+static void PMacSilence(void);
+static void PMacInit(void);
+static int PMacSetFormat(int format);
+static int PMacSetVolume(int volume);
+static void PMacPlay(void);
+static void PMacRecord(void);
+static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
+static void awacs_write(int val);
+static int awacs_get_volume(int reg, int lshift);
+static int awacs_volume_setter(int volume, int n, int mute, int lshift);
+static void awacs_mksound(unsigned int hz, unsigned int ticks);
+static void awacs_nosound(unsigned long xx);
+
+
+/*** Mid level stuff **********************************************************/
+
+
+static int PMacMixerIoctl(u_int cmd, u_long arg);
+static void PMacWriteSqSetup(void);
+static void PMacReadSqSetup(void);
+static void PMacAbortRead(void);
+
+
+/*** Translations ************************************************************/
+
+
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ short *table = dmasound.soft.format == AFMT_MU_LAW
+ ? dmasound_ulaw2dma16 : dmasound_alaw2dma16;
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data];
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data];
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data << 8;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data << 8;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = (data ^ 0x80) << 8;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = (data ^ 0x80) << 8;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ if (!stereo) {
+ short *up = (short *) userPtr;
+ while (count > 0) {
+ short data;
+ if (get_user(data, up++))
+ return -EFAULT;
+ *fp++ = data;
+ *fp++ = data;
+ count--;
+ }
+ } else {
+ if (copy_from_user(fp, userPtr, count * 4))
+ return -EFAULT;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+ short *up = (short *) userPtr;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ int data;
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ *fp++ = data;
+ if (stereo) {
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ }
+ *fp++ = data;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned short *table = (unsigned short *)
+ (dmasound.soft.format == AFMT_MU_LAW
+ ? dmasound_ulaw2dma16 : dmasound_alaw2dma16);
+ unsigned int data = expand_data;
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+ int stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + table[c];
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = c << 8;
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + (c << 8);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (c ^ 0x80) << 8;
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + ((c ^ 0x80) << 8);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ unsigned short *up = (unsigned short *) userPtr;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ unsigned short c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(data, up++))
+ return -EFAULT;
+ if (stereo) {
+ if (get_user(c, up++))
+ return -EFAULT;
+ data = (data << 16) + c;
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 4: utotal * 2;
+}
+
+
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ unsigned short *up = (unsigned short *) userPtr;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ unsigned short c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ if (stereo) {
+ if (get_user(c, up++))
+ return -EFAULT;
+ data = (data << 16) + (c ^ mask);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 4: utotal * 2;
+}
+
+static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+
+ val = *p++;
+ data = val >> 8;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ if (stereo) {
+ val = *p;
+ data = val >> 8;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ }
+ p++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+
+ val = *p++;
+ data = (val >> 8) ^ 0x80;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ if (stereo) {
+ val = *p;
+ data = (val >> 8) ^ 0x80;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ }
+ p++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ if (!stereo) {
+ short *up = (short *) userPtr;
+ while (count > 0) {
+ short data;
+ data = *fp;
+ if (put_user(data, up++))
+ return -EFAULT;
+ fp+=2;
+ count--;
+ }
+ } else {
+ if (copy_to_user((u_char *)userPtr, fp, count * 4))
+ return -EFAULT;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+ short *up = (short *) userPtr;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ int data;
+
+ data = *fp++;
+ data ^= mask;
+ if (put_user(data, up++))
+ return -EFAULT;
+ if (stereo) {
+ data = *fp;
+ data ^= mask;
+ if (put_user(data, up++))
+ return -EFAULT;
+ }
+ fp++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+
+static TRANS transAwacsNormal = {
+ ct_ulaw: pmac_ct_law,
+ ct_alaw: pmac_ct_law,
+ ct_s8: pmac_ct_s8,
+ ct_u8: pmac_ct_u8,
+ ct_s16be: pmac_ct_s16,
+ ct_u16be: pmac_ct_u16,
+ ct_s16le: pmac_ct_s16,
+ ct_u16le: pmac_ct_u16,
+};
+
+static TRANS transAwacsExpand = {
+ ct_ulaw: pmac_ctx_law,
+ ct_alaw: pmac_ctx_law,
+ ct_s8: pmac_ctx_s8,
+ ct_u8: pmac_ctx_u8,
+ ct_s16be: pmac_ctx_s16,
+ ct_u16be: pmac_ctx_u16,
+ ct_s16le: pmac_ctx_s16,
+ ct_u16le: pmac_ctx_u16,
+};
+
+static TRANS transAwacsNormalRead = {
+ ct_s8: pmac_ct_s8_read,
+ ct_u8: pmac_ct_u8_read,
+ ct_s16be: pmac_ct_s16_read,
+ ct_u16be: pmac_ct_u16_read,
+ ct_s16le: pmac_ct_s16_read,
+ ct_u16le: pmac_ct_u16_read,
+};
+
+/*** Low level stuff *********************************************************/
+
+
+
+/*
+ * PCI PowerMac, with AWACS and DBDMA.
+ */
+
+static void PMacOpen(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void PMacRelease(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static void *PMacAlloc(unsigned int size, int flags)
+{
+ return kmalloc(size, flags);
+}
+
+static void PMacFree(void *ptr, unsigned int size)
+{
+ kfree(ptr);
+}
+
+static int __init PMacIrqInit(void)
+{
+ if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
+ || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
+ || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
+ return 0;
+ return 1;
+}
+
+#ifdef MODULE
+static void PMacIrqCleanup(void)
+{
+ /* turn off output dma */
+ out_le32(&awacs_txdma->control, RUN<<16);
+ /* disable interrupts from awacs interface */
+ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+#ifdef CONFIG_PMAC_PBOOK
+ if (is_pbook_G3) {
+ feature_clear(awacs_node, FEATURE_Sound_power);
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ }
+#endif
+ free_irq(awacs_irq, 0);
+ free_irq(awacs_tx_irq, 0);
+ free_irq(awacs_rx_irq, 0);
+ kfree(awacs_tx_cmd_space);
+ if (awacs_rx_cmd_space)
+ kfree(awacs_rx_cmd_space);
+ if (beep_buf)
+ kfree(beep_buf);
+ kd_mksound = orig_mksound;
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
+#endif
+}
+#endif /* MODULE */
+
+static void PMacSilence(void)
+{
+ /* turn off output dma */
+ out_le32(&awacs_txdma->control, RUN<<16);
+}
+
+static int awacs_freqs[8] = {
+ 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
+};
+static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static void PMacInit(void)
+{
+ int i, tolerance;
+
+ switch (dmasound.soft.format) {
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ dmasound.hard.format = AFMT_S16_LE;
+ break;
+ default:
+ dmasound.hard.format = AFMT_S16_BE;
+ break;
+ }
+ dmasound.hard.stereo = 1;
+ dmasound.hard.size = 16;
+
+ /*
+ * If we have a sample rate which is within catchRadius percent
+ * of the requested value, we don't have to expand the samples.
+ * Otherwise choose the next higher rate.
+ * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
+ */
+ i = 8;
+ do {
+ tolerance = catchRadius * awacs_freqs[--i] / 100;
+ if (awacs_freqs_ok[i]
+ && dmasound.soft.speed <= awacs_freqs[i] + tolerance)
+ break;
+ } while (i > 0);
+ if (dmasound.soft.speed >= awacs_freqs[i] - tolerance)
+ dmasound.trans_write = &transAwacsNormal;
+ else
+ dmasound.trans_write = &transAwacsExpand;
+ dmasound.trans_read = &transAwacsNormalRead;
+ dmasound.hard.speed = awacs_freqs[i];
+ awacs_rate_index = i;
+
+ /* XXX disable error interrupt on burgundy for now */
+ out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
+ | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
+ awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+
+ /* We really want to execute a DMA stop command, after the AWACS
+ * is initialized.
+ * For reasons I don't understand, it stops the hissing noise
+ * common to many PowerBook G3 systems (like mine :-).
+ */
+ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+ st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+ out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+
+ expand_bal = -dmasound.soft.speed;
+}
+
+static int PMacSetFormat(int format)
+{
+ int size;
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
+ format);
+ size = 8;
+ format = AFMT_U8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = size;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = size;
+ }
+
+ PMacInit();
+
+ return format;
+}
+
+#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))
+#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))
+
+static int awacs_get_volume(int reg, int lshift)
+{
+ int volume;
+
+ volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
+ volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
+ return volume;
+}
+
+static int awacs_volume_setter(int volume, int n, int mute, int lshift)
+{
+ int r1, rn;
+
+ if (mute && volume == 0) {
+ r1 = awacs_reg[1] | mute;
+ } else {
+ r1 = awacs_reg[1] & ~mute;
+ rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
+ rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
+ rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
+ awacs_reg[n] = rn;
+ awacs_write((n << 12) | rn);
+ volume = awacs_get_volume(rn, lshift);
+ }
+ if (r1 != awacs_reg[1]) {
+ awacs_reg[1] = r1;
+ awacs_write(r1 | MASK_ADDR1);
+ }
+ return volume;
+}
+
+static int PMacSetVolume(int volume)
+{
+ return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
+}
+
+static void PMacPlay(void)
+{
+ volatile struct dbdma_cmd *cp;
+ int i, count;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (awacs_beep_state) {
+ /* sound takes precedence over beeps */
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (awacs_rate_index << 8));
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(write_sq.front+write_sq.active) % write_sq.max_count])));
+
+ beep_playing = 0;
+ awacs_beep_state = 0;
+ }
+ i = write_sq.front + write_sq.active;
+ if (i >= write_sq.max_count)
+ i -= write_sq.max_count;
+ while (write_sq.active < 2 && write_sq.active < write_sq.count) {
+ count = (write_sq.count == write_sq.active + 1)?write_sq.rear_size:write_sq.block_size;
+ if (count < write_sq.block_size && !write_sq.syncing)
+ /* last block not yet filled, and we're not syncing. */
+ break;
+ cp = &awacs_tx_cmds[i];
+ st_le16(&cp->req_count, count);
+ st_le16(&cp->xfer_status, 0);
+ if (++i >= write_sq.max_count)
+ i = 0;
+ out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
+ out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+ if (write_sq.active == 0)
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+ out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+ ++write_sq.active;
+ }
+ restore_flags(flags);
+}
+
+
+static void PMacRecord(void)
+{
+ unsigned long flags;
+
+ if (read_sq.active)
+ return;
+
+ save_flags(flags); cli();
+
+ /* This is all we have to do......Just start it up.
+ */
+ out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+ read_sq.active = 1;
+
+ restore_flags(flags);
+}
+
+
+static void
+pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ int i = write_sq.front;
+ int stat;
+ volatile struct dbdma_cmd *cp;
+
+ while (write_sq.active > 0) {
+ cp = &awacs_tx_cmds[i];
+ stat = ld_le16(&cp->xfer_status);
+ if ((stat & ACTIVE) == 0)
+ break; /* this frame is still going */
+ --write_sq.count;
+ --write_sq.active;
+ if (++i >= write_sq.max_count)
+ i = 0;
+ }
+ if (i != write_sq.front)
+ WAKE_UP(write_sq.action_queue);
+ write_sq.front = i;
+
+ PMacPlay();
+
+ if (!write_sq.active)
+ WAKE_UP(write_sq.sync_queue);
+}
+
+
+static void
+pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+
+ /* For some reason on my PowerBook G3, I get one interrupt
+ * when the interrupt vector is installed (like something is
+ * pending). This happens before the dbdma is initialize by
+ * us, so I just check the command pointer and if it is zero,
+ * just blow it off.
+ */
+ if (in_le32(&awacs_rxdma->cmdptr) == 0)
+ return;
+
+ /* We also want to blow 'em off when shutting down.
+ */
+ if (read_sq.active == 0)
+ return;
+
+ /* Check multiple buffers in case we were held off from
+ * interrupt processing for a long time. Geeze, I really hope
+ * this doesn't happen.
+ */
+ while (awacs_rx_cmds[read_sq.rear].xfer_status) {
+
+ /* Clear status and move on to next buffer.
+ */
+ awacs_rx_cmds[read_sq.rear].xfer_status = 0;
+ read_sq.rear++;
+
+ /* Wrap the buffer ring.
+ */
+ if (read_sq.rear >= read_sq.max_active)
+ read_sq.rear = 0;
+
+ /* If we have caught up to the front buffer, bump it.
+ * This will cause weird (but not fatal) results if the
+ * read loop is currently using this buffer. The user is
+ * behind in this case anyway, so weird things are going
+ * to happen.
+ */
+ if (read_sq.rear == read_sq.front) {
+ read_sq.front++;
+ if (read_sq.front >= read_sq.max_active)
+ read_sq.front = 0;
+ }
+ }
+
+ WAKE_UP(read_sq.action_queue);
+}
+
+
+static void
+pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ int ctrl = in_le32(&awacs->control);
+
+ if (ctrl & MASK_PORTCHG) {
+ /* do something when headphone is plugged/unplugged? */
+ }
+ if (ctrl & MASK_CNTLERR) {
+ int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
+ if (err != 0 && awacs_revision < AWACS_BURGUNDY)
+ printk(KERN_ERR "AWACS: error %x\n", err);
+ }
+ /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
+ out_le32(&awacs->control, ctrl);
+}
+
+static void
+awacs_write(int val)
+{
+ if (awacs_revision >= AWACS_BURGUNDY)
+ return;
+ while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+ ; /* XXX should have timeout */
+ out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
+}
+
+static void awacs_nosound(unsigned long xx)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (beep_playing) {
+ st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (awacs_rate_index << 8));
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+ beep_playing = 0;
+ }
+ restore_flags(flags);
+}
+
+static struct timer_list beep_timer = {
+ NULL, NULL, 0, 0, awacs_nosound
+};
+
+static void awacs_mksound(unsigned int hz, unsigned int ticks)
+{
+ unsigned long flags;
+ int beep_speed = 0;
+ int srate;
+ int period, ncycles, nsamples;
+ int i, j, f;
+ short *p;
+ static int beep_hz_cache;
+ static int beep_nsamples_cache;
+ static int beep_volume_cache;
+
+ for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
+ if (awacs_freqs_ok[i])
+ beep_speed = i;
+ srate = awacs_freqs[beep_speed];
+
+ if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
+#if 1
+ /* this is a hack for broken X server code */
+ hz = 750;
+ ticks = 12;
+#else
+ /* cancel beep currently playing */
+ awacs_nosound(0);
+ return;
+#endif
+ }
+ save_flags(flags); cli();
+ del_timer(&beep_timer);
+ if (ticks) {
+ beep_timer.expires = jiffies + ticks;
+ add_timer(&beep_timer);
+ }
+ if (beep_playing || write_sq.active || beep_buf == NULL) {
+ restore_flags(flags);
+ return; /* too hard, sorry :-( */
+ }
+ beep_playing = 1;
+ st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
+ restore_flags(flags);
+
+ if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
+ nsamples = beep_nsamples_cache;
+ } else {
+ period = srate * 256 / hz; /* fixed point */
+ ncycles = BEEP_BUFLEN * 256 / period;
+ nsamples = (period * ncycles) >> 8;
+ f = ncycles * 65536 / nsamples;
+ j = 0;
+ p = beep_buf;
+ for (i = 0; i < nsamples; ++i, p += 2) {
+ p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
+ j = (j + f) & 0xffff;
+ }
+ beep_hz_cache = hz;
+ beep_volume_cache = beep_volume;
+ beep_nsamples_cache = nsamples;
+ }
+
+ st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
+ st_le16(&beep_dbdma_cmd->xfer_status, 0);
+ st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
+ st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+ awacs_beep_state = 1;
+
+ save_flags(flags); cli();
+ if (beep_playing) { /* i.e. haven't been terminated already */
+ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (beep_speed << 8));
+ out_le32(&awacs->byteswap, 0);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+ out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+ }
+ restore_flags(flags);
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save state when going to sleep, restore it afterwards.
+ */
+static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+ switch (when) {
+ case PBOOK_SLEEP_NOW:
+ /* XXX we should stop any dma in progress when going to sleep
+ and restart it when we wake. */
+ PMacSilence();
+ disable_irq(awacs_irq);
+ disable_irq(awacs_tx_irq);
+ if (is_pbook_G3) {
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_clear(awacs_node, FEATURE_Sound_power);
+ }
+ break;
+ case PBOOK_WAKE:
+ /* There is still a problem on wake. Sound seems to work fine
+ if I launch mpg123 and resumes fine if mpg123 was playing,
+ but the console beep is dead until I do something with the
+ mixer. Probably yet another timing issue */
+ if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+ || !feature_test(awacs_node, FEATURE_Sound_power)) {
+ /* these aren't present on the 3400 AFAIK -- paulus */
+ feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_set(awacs_node, FEATURE_Sound_power);
+ mdelay(1000);
+ }
+ out_le32(&awacs->control, MASK_IEPC
+ | (awacs_rate_index << 8) | 0x11
+ | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ awacs_write(awacs_reg[2] | MASK_ADDR2);
+ awacs_write(awacs_reg[4] | MASK_ADDR4);
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+ enable_irq(awacs_irq);
+ enable_irq(awacs_tx_irq);
+ if (awacs_revision == 3) {
+ mdelay(100);
+ awacs_write(0x6000);
+ mdelay(2);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ }
+ /* enable CD sound input */
+ if (macio_base && is_pbook_G3) {
+ out_8(macio_base + 0x37, 3);
+ } else if (is_pbook_3400) {
+ feature_set(awacs_node, FEATURE_IOBUS_enable);
+ udelay(10);
+ in_8(latch_base + 0x190);
+ }
+ /* Resume pending sounds. */
+ PMacPlay();
+ }
+ return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+
+/* All the burgundy functions: */
+
+/* Waits for busy flag to clear */
+inline static void
+awacs_burgundy_busy_wait(void)
+{
+ while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+ ;
+}
+
+inline static void
+awacs_burgundy_extend_wait(void)
+{
+ while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND))
+ ;
+ while (in_le32(&awacs->codec_stat) & MASK_EXTEND)
+ ;
+}
+
+static void
+awacs_burgundy_wcw(unsigned addr, unsigned val)
+{
+ out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
+ awacs_burgundy_busy_wait();
+ out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
+ awacs_burgundy_busy_wait();
+ out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
+ awacs_burgundy_busy_wait();
+ out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
+ awacs_burgundy_busy_wait();
+}
+
+static unsigned
+awacs_burgundy_rcw(unsigned addr)
+{
+ unsigned val = 0;
+ unsigned long flags;
+
+ /* should have timeouts here */
+ save_flags(flags); cli();
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100000);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100100);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8;
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100200);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16;
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100300);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
+
+ restore_flags(flags);
+
+ return val;
+}
+
+
+static void
+awacs_burgundy_wcb(unsigned addr, unsigned val)
+{
+ out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
+ awacs_burgundy_busy_wait();
+}
+
+static unsigned
+awacs_burgundy_rcb(unsigned addr)
+{
+ unsigned val = 0;
+ unsigned long flags;
+
+ /* should have timeouts here */
+ save_flags(flags); cli();
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100000);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
+
+ restore_flags(flags);
+
+ return val;
+}
+
+static int
+awacs_burgundy_check(void)
+{
+ /* Checks to see the chip is alive and kicking */
+ int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE;
+
+ return error == 0xf0000;
+}
+
+static int
+awacs_burgundy_init(void)
+{
+ if (awacs_burgundy_check()) {
+ printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n");
+ return 1;
+ }
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES,
+ DEF_BURGUNDY_OUTPUTENABLES);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ DEF_BURGUNDY_MORE_OUTPUTENABLES);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
+ DEF_BURGUNDY_OUTPUTSELECTS);
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21,
+ DEF_BURGUNDY_INPSEL21);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3,
+ DEF_BURGUNDY_INPSEL3);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD,
+ DEF_BURGUNDY_GAINCD);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE,
+ DEF_BURGUNDY_GAINLINE);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC,
+ DEF_BURGUNDY_GAINMIC);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM,
+ DEF_BURGUNDY_GAINMODEM);
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER,
+ DEF_BURGUNDY_ATTENSPEAKER);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT,
+ DEF_BURGUNDY_ATTENLINEOUT);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP,
+ DEF_BURGUNDY_ATTENHP);
+
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME,
+ DEF_BURGUNDY_MASTER_VOLUME);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD,
+ DEF_BURGUNDY_VOLCD);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE,
+ DEF_BURGUNDY_VOLLINE);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC,
+ DEF_BURGUNDY_VOLMIC);
+ return 0;
+}
+
+static void
+awacs_burgundy_write_volume(unsigned address, int volume)
+{
+ int hardvolume,lvolume,rvolume;
+
+ lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0;
+ rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0;
+
+ hardvolume = lvolume + (rvolume << 16);
+
+ awacs_burgundy_wcw(address, hardvolume);
+}
+
+static int
+awacs_burgundy_read_volume(unsigned address)
+{
+ int softvolume,wvolume;
+
+ wvolume = awacs_burgundy_rcw(address);
+
+ softvolume = (wvolume & 0xff) - 155;
+ softvolume += (((wvolume >> 16) & 0xff) - 155)<<8;
+
+ return softvolume > 0 ? softvolume : 0;
+}
+
+
+
+
+static int
+awacs_burgundy_read_mvolume(unsigned address)
+{
+ int lvolume,rvolume,wvolume;
+
+ wvolume = awacs_burgundy_rcw(address);
+
+ wvolume &= 0xffff;
+
+ rvolume = (wvolume & 0xff) - 155;
+ lvolume = ((wvolume & 0xff00)>>8) - 155;
+
+ return lvolume + (rvolume << 8);
+}
+
+
+static void
+awacs_burgundy_write_mvolume(unsigned address, int volume)
+{
+ int lvolume,rvolume,hardvolume;
+
+ lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0;
+ rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0;
+
+ hardvolume = lvolume + (rvolume << 8);
+ hardvolume += (hardvolume << 16);
+
+ awacs_burgundy_wcw(address, hardvolume);
+}
+
+/* End burgundy functions */
+
+
+
+
+
+/* Turn on sound output, needed on G3 desktop powermacs */
+static void
+awacs_enable_amp(int spkr_vol)
+{
+ struct adb_request req;
+
+ awacs_spkr_vol = spkr_vol;
+ if (sys_ctrler != SYS_CTRLER_CUDA)
+ return;
+
+ /* turn on headphones */
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 4, 0);
+ while (!req.complete) cuda_poll();
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 6, 0);
+ while (!req.complete) cuda_poll();
+
+ /* turn on speaker */
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
+ while (!req.complete) cuda_poll();
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
+ while (!req.complete) cuda_poll();
+
+ cuda_request(&req, NULL, 5, CUDA_PACKET,
+ CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
+ while (!req.complete) cuda_poll();
+}
+
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+static int PMacMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ /* Different IOCTLS for burgundy*/
+ if (awacs_revision < AWACS_BURGUNDY) {
+ switch (cmd) {
+ case SOUND_MIXER_READ_DEVMASK:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD | SOUND_MASK_RECLEV
+ | SOUND_MASK_ALTPCM
+ | SOUND_MASK_MONITOR;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECMASK:
+ data = SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECSRC:
+ data = 0;
+ if (awacs_reg[0] & MASK_MUX_AUDIN)
+ data |= SOUND_MASK_LINE;
+ if (awacs_reg[0] & MASK_MUX_MIC)
+ data |= SOUND_MASK_MIC;
+ if (awacs_reg[0] & MASK_MUX_CD)
+ data |= SOUND_MASK_CD;
+ if (awacs_reg[1] & MASK_LOOPTHRU)
+ data |= SOUND_MASK_MONITOR;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECSRC:
+ IOCTL_IN(arg, data);
+ data &= (SOUND_MASK_LINE
+ | SOUND_MASK_MIC | SOUND_MASK_CD
+ | SOUND_MASK_MONITOR);
+ awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+ | MASK_MUX_AUDIN);
+ awacs_reg[1] &= ~MASK_LOOPTHRU;
+ if (data & SOUND_MASK_LINE)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ if (data & SOUND_MASK_MIC)
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data & SOUND_MASK_CD)
+ awacs_reg[0] |= MASK_MUX_CD;
+ if (data & SOUND_MASK_MONITOR)
+ awacs_reg[1] |= MASK_LOOPTHRU;
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_STEREODEVS:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_RECLEV;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_CAPS:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_READ_VOLUME:
+ data = (awacs_reg[1] & MASK_AMUTE)? 0:
+ awacs_get_volume(awacs_reg[2], 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_volume(data));
+ case SOUND_MIXER_READ_SPEAKER:
+ if (awacs_revision == 3
+ && sys_ctrler == SYS_CTRLER_CUDA)
+ data = awacs_spkr_vol;
+ else
+ data = (awacs_reg[1] & MASK_CMUTE)? 0:
+ awacs_get_volume(awacs_reg[4], 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_SPEAKER:
+ IOCTL_IN(arg, data);
+ if (awacs_revision == 3
+ && sys_ctrler == SYS_CTRLER_CUDA)
+ awacs_enable_amp(data);
+ else
+ data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
+ IOCTL_IN(arg, data);
+ beep_volume = data & 0xff;
+ /* fall through */
+ case SOUND_MIXER_READ_ALTPCM:
+ return IOCTL_OUT(arg, beep_volume);
+ case SOUND_MIXER_WRITE_LINE:
+ IOCTL_IN(arg, data);
+ awacs_reg[0] &= ~MASK_MUX_AUDIN;
+ if ((data & 0xff) >= 50)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_LINE:
+ data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_MIC:
+ IOCTL_IN(arg, data);
+ data &= 0xff;
+ awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
+ if (data >= 25) {
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data >= 75)
+ awacs_reg[0] |= MASK_GAINLINE;
+ }
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_MIC:
+ data = (awacs_reg[0] & MASK_MUX_MIC)?
+ (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_CD:
+ IOCTL_IN(arg, data);
+ awacs_reg[0] &= ~MASK_MUX_CD;
+ if ((data & 0xff) >= 50)
+ awacs_reg[0] |= MASK_MUX_CD;
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_CD:
+ data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECLEV:
+ IOCTL_IN(arg, data);
+ data = awacs_volume_setter(data, 0, 0, 4);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECLEV:
+ data = awacs_get_volume(awacs_reg[0], 4);
+ return IOCTL_OUT(arg, data);
+ }
+ } else {
+ /* We are, we are, we are... Burgundy or better */
+ switch(cmd) {
+ case SOUND_MIXER_READ_DEVMASK:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
+ SOUND_MASK_LINE | SOUND_MASK_MIC |
+ SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECMASK:
+ data = SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECSRC:
+ data = 0;
+ if (awacs_reg[0] & MASK_MUX_AUDIN)
+ data |= SOUND_MASK_LINE;
+ if (awacs_reg[0] & MASK_MUX_MIC)
+ data |= SOUND_MASK_MIC;
+ if (awacs_reg[0] & MASK_MUX_CD)
+ data |= SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECSRC:
+ IOCTL_IN(arg, data);
+ data &= (SOUND_MASK_LINE
+ | SOUND_MASK_MIC | SOUND_MASK_CD);
+ awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+ | MASK_MUX_AUDIN);
+ if (data & SOUND_MASK_LINE)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ if (data & SOUND_MASK_MIC)
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data & SOUND_MASK_CD)
+ awacs_reg[0] |= MASK_MUX_CD;
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_STEREODEVS:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_RECLEV | SOUND_MASK_CD
+ | SOUND_MASK_LINE;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_CAPS:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
+ /* Fall through */
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
+ case SOUND_MIXER_WRITE_SPEAKER:
+ IOCTL_IN(arg, data);
+
+ if (!(data & 0xff)) {
+ /* Mute the left speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);
+ } else {
+ /* Unmute the left speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);
+ }
+ if (!(data & 0xff00)) {
+ /* Mute the right speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);
+ } else {
+ /* Unmute the right speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);
+ }
+
+ data = (((data&0xff)*16)/100 > 0xf ? 0xf :
+ (((data&0xff)*16)/100)) +
+ ((((data>>8)*16)/100 > 0xf ? 0xf :
+ ((((data>>8)*16)/100)))<<4);
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);
+ /* Fall through */
+ case SOUND_MIXER_READ_SPEAKER:
+ data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
+ data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
+ return IOCTL_OUT(arg, ~data);
+ case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
+ IOCTL_IN(arg, data);
+ beep_volume = data & 0xff;
+ /* fall through */
+ case SOUND_MIXER_READ_ALTPCM:
+ return IOCTL_OUT(arg, beep_volume);
+ case SOUND_MIXER_WRITE_LINE:
+ IOCTL_IN(arg, data);
+ awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
+
+ /* fall through */
+ case SOUND_MIXER_READ_LINE:
+ data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_MIC:
+ IOCTL_IN(arg, data);
+ /* Mic is mono device */
+ data = (data << 8) + (data << 24);
+ awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
+ /* fall through */
+ case SOUND_MIXER_READ_MIC:
+ data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);
+ data <<= 24;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_CD:
+ IOCTL_IN(arg, data);
+ awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
+ /* fall through */
+ case SOUND_MIXER_READ_CD:
+ data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECLEV:
+ IOCTL_IN(arg, data);
+ data = awacs_volume_setter(data, 0, 0, 4);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECLEV:
+ data = awacs_get_volume(awacs_reg[0], 4);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_OUTMASK:
+ break;
+ case SOUND_MIXER_OUTSRC:
+ break;
+ }
+ }
+ return -EINVAL;
+}
+
+
+static void PMacWriteSqSetup(void)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+ cp = awacs_tx_cmds;
+ memset((void *)cp, 0, (write_sq.numBufs+1) * sizeof(struct dbdma_cmd));
+ for (i = 0; i < write_sq.numBufs; ++i, ++cp) {
+ st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i]));
+ }
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
+}
+
+static void PMacReadSqSetup(void)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+ cp = awacs_rx_cmds;
+ memset((void *)cp, 0, (read_sq.numBufs+1) * sizeof(struct dbdma_cmd));
+
+ /* Set dma buffers up in a loop */
+ for (i = 0; i < read_sq.numBufs; i++,cp++) {
+ st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i]));
+ st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
+ st_le16(&cp->req_count, read_sq.block_size);
+ st_le16(&cp->xfer_status, 0);
+ }
+
+ /* The next two lines make the thing loop around.
+ */
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
+
+ /* Don't start until the first read is done.
+ * This will also abort any operations in progress if the DMA
+ * happens to be running (and it shouldn't).
+ */
+ out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
+
+}
+
+static void PMacAbortRead(void)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+ cp = awacs_rx_cmds;
+ for (i = 0; i < read_sq.numBufs; i++,cp++)
+ st_le16(&cp->command, DBDMA_STOP);
+ /*
+ * We should probably wait for the thing to stop before we
+ * release the memory
+ */
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machPMac = {
+ name: awacs_name,
+ name2: "AWACS",
+ open: PMacOpen,
+ release: PMacRelease,
+ dma_alloc: PMacAlloc,
+ dma_free: PMacFree,
+ irqinit: PMacIrqInit,
+#ifdef MODULE
+ irqcleanup: PMacIrqCleanup,
+#endif /* MODULE */
+ init: PMacInit,
+ silence: PMacSilence,
+ setFormat: PMacSetFormat,
+ setVolume: PMacSetVolume,
+ play: PMacPlay,
+ record: PMacRecord,
+ mixer_ioctl: PMacMixerIoctl,
+ write_sq_setup: PMacWriteSqSetup,
+ read_sq_setup: PMacReadSqSetup,
+ abort_read: PMacAbortRead,
+ min_dsp_speed: 8000
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_awacs_init(void)
+{
+ struct device_node *np;
+
+ if (_machine != _MACH_Pmac)
+ return -ENODEV;
+
+ awacs_subframe = 0;
+ awacs_revision = 0;
+ np = find_devices("awacs");
+ if (np == 0) {
+ /*
+ * powermac G3 models have a node called "davbus"
+ * with a child called "sound".
+ */
+ struct device_node *sound;
+ np = find_devices("davbus");
+ sound = find_devices("sound");
+ if (sound != 0 && sound->parent == np) {
+ unsigned int *prop, l, i;
+ prop = (unsigned int *)
+ get_property(sound, "sub-frame", 0);
+ if (prop != 0 && *prop >= 0 && *prop < 16)
+ awacs_subframe = *prop;
+ if (device_is_compatible(sound, "burgundy"))
+ awacs_revision = AWACS_BURGUNDY;
+
+ /* look for a property saying what sample rates
+ are available */
+ for (i = 0; i < 8; ++i)
+ awacs_freqs_ok[i] = 0;
+ prop = (unsigned int *) get_property
+ (sound, "sample-rates", &l);
+ if (prop == 0)
+ prop = (unsigned int *) get_property
+ (sound, "output-frame-rates", &l);
+ if (prop != 0) {
+ for (l /= sizeof(int); l > 0; --l) {
+ /* sometimes the rate is in the
+ high-order 16 bits (?) */
+ unsigned int r = *prop++;
+ if (r >= 0x10000)
+ r >>= 16;
+ for (i = 0; i < 8; ++i) {
+ if (r == awacs_freqs[i]) {
+ awacs_freqs_ok[i] = 1;
+ break;
+ }
+ }
+ }
+ } else {
+ /* assume just 44.1k is OK */
+ awacs_freqs_ok[0] = 1;
+ }
+ }
+ }
+ if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
+ int vol;
+ dmasound.mach = machPMac;
+
+ awacs = (volatile struct awacs_regs *)
+ ioremap(np->addrs[0].address, 0x80);
+ awacs_txdma = (volatile struct dbdma_regs *)
+ ioremap(np->addrs[1].address, 0x100);
+ awacs_rxdma = (volatile struct dbdma_regs *)
+ ioremap(np->addrs[2].address, 0x100);
+
+ awacs_irq = np->intrs[0].line;
+ awacs_tx_irq = np->intrs[1].line;
+ awacs_rx_irq = np->intrs[2].line;
+
+ awacs_tx_cmd_space = kmalloc((write_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
+ GFP_KERNEL);
+ if (awacs_tx_cmd_space == NULL) {
+ printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
+ return -ENOMEM;
+ }
+ awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+ if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ feature_set(np, FEATURE_Sound_CLK_enable);
+ feature_set(np, FEATURE_Sound_power);
+ /* Shorter delay will not work */
+ mdelay(1000);
+ }
+#endif
+ awacs_tx_cmds = (volatile struct dbdma_cmd *)
+ DBDMA_ALIGN(awacs_tx_cmd_space);
+
+
+ awacs_rx_cmd_space = kmalloc((read_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
+ GFP_KERNEL);
+ if (awacs_rx_cmd_space == NULL) {
+ printk("DMA sound driver: No memory for input");
+ }
+ awacs_rx_cmds = (volatile struct dbdma_cmd *)
+ DBDMA_ALIGN(awacs_rx_cmd_space);
+
+
+
+ awacs_reg[0] = MASK_MUX_CD;
+ awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+ /* get default volume from nvram */
+ vol = (~nvram_read_byte(0x1308) & 7) << 1;
+ awacs_reg[2] = vol + (vol << 6);
+ awacs_reg[4] = vol + (vol << 6);
+ out_le32(&awacs->control, 0x11);
+ awacs_write(awacs_reg[0] + MASK_ADDR0);
+ awacs_write(awacs_reg[1] + MASK_ADDR1);
+ awacs_write(awacs_reg[2] + MASK_ADDR2);
+ awacs_write(awacs_reg[4] + MASK_ADDR4);
+
+ /* Initialize recent versions of the awacs */
+ if (awacs_revision == 0) {
+ awacs_revision =
+ (in_le32(&awacs->codec_stat) >> 12) & 0xf;
+ if (awacs_revision == 3) {
+ mdelay(100);
+ awacs_write(0x6000);
+ mdelay(2);
+ awacs_write(awacs_reg[1] + MASK_ADDR1);
+ awacs_enable_amp(100 * 0x101);
+ }
+ }
+ if (awacs_revision >= AWACS_BURGUNDY)
+ awacs_burgundy_init();
+
+ /* Initialize beep stuff */
+ beep_dbdma_cmd = awacs_tx_cmds + (write_sq.numBufs + 1);
+ orig_mksound = kd_mksound;
+ kd_mksound = awacs_mksound;
+ beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+ if (beep_buf == NULL)
+ printk(KERN_WARNING "dmasound: no memory for "
+ "beep buffer\n");
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&awacs_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+ /* Powerbooks have odd ways of enabling inputs such as
+ an expansion-bay CD or sound from an internal modem
+ or a PC-card modem. */
+ if (machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500")) {
+ is_pbook_3400 = 1;
+ /*
+ * Enable CD and PC-card sound inputs.
+ * This is done by reading from address
+ * f301a000, + 0x10 to enable the expansion-bay
+ * CD sound input, + 0x80 to enable the PC-card
+ * sound input. The 0x100 enables the SCSI bus
+ * terminator power.
+ */
+ latch_base = (unsigned char *) ioremap
+ (0xf301a000, 0x1000);
+ in_8(latch_base + 0x190);
+ } else if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ struct device_node* mio;
+ macio_base = 0;
+ is_pbook_G3 = 1;
+ for (mio = np->parent; mio; mio = mio->parent) {
+ if (strcmp(mio->name, "mac-io") == 0
+ && mio->n_addrs > 0) {
+ macio_base = (unsigned char *) ioremap
+ (mio->addrs[0].address, 0x40);
+ break;
+ }
+ }
+ /* enable CD sound input */
+ if (macio_base)
+ out_8(macio_base + 0x37, 3);
+ }
+ sprintf(awacs_name, "PowerMac (AWACS rev %d) ",
+ awacs_revision);
+ return dmasound_init();
+ }
+ return -ENODEV;
+}
+
+static void __exit dmasound_awacs_cleanup(void)
+{
+ dmasound_deinit();
+}
+
+module_init(dmasound_awacs_init);
+module_exit(dmasound_awacs_cleanup);
diff --git a/drivers/sound/dmasound/dmasound_core.c b/drivers/sound/dmasound/dmasound_core.c
new file mode 100644
index 000000000..594ee925c
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_core.c
@@ -0,0 +1,1313 @@
+
+/*
+ * linux/drivers/sound/dmasound.c
+ *
+ *
+ * OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for
+ * Linux/m68k
+ * Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
+ *
+ * (c) 1995 by Michael Schlueter & Michael Marte
+ *
+ * Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
+ * interface and the u-law to signed byte conversion.
+ *
+ * Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
+ * /dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
+ * to thank:
+ * - Michael Schlueter for initial ideas and documentation on the MFP and
+ * the DMA sound hardware.
+ * - Therapy? for their CD 'Troublegum' which really made me rock.
+ *
+ * /dev/sndstat is based on code by Hannu Savolainen, the author of the
+ * VoxWare family of drivers.
+ *
+ * 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.
+ *
+ * History:
+ *
+ * 1995/8/25 First release
+ *
+ * 1995/9/02 Roman Hodek:
+ * - Fixed atari_stram_alloc() call, the timer
+ * programming and several race conditions
+ * 1995/9/14 Roman Hodek:
+ * - After some discussion with Michael Schlueter,
+ * revised the interrupt disabling
+ * - Slightly speeded up U8->S8 translation by using
+ * long operations where possible
+ * - Added 4:3 interpolation for /dev/audio
+ *
+ * 1995/9/20 Torsten Scherer:
+ * - Fixed a bug in sq_write and changed /dev/audio
+ * converting to play at 12517Hz instead of 6258Hz.
+ *
+ * 1995/9/23 Torsten Scherer:
+ * - Changed sq_interrupt() and sq_play() to pre-program
+ * the DMA for another frame while there's still one
+ * running. This allows the IRQ response to be
+ * arbitrarily delayed and playing will still continue.
+ *
+ * 1995/10/14 Guenther Kelleter, Torsten Scherer:
+ * - Better support for Falcon audio (the Falcon doesn't
+ * raise an IRQ at the end of a frame, but at the
+ * beginning instead!). uses 'if (codec_dma)' in lots
+ * of places to simply switch between Falcon and TT
+ * code.
+ *
+ * 1995/11/06 Torsten Scherer:
+ * - Started introducing a hardware abstraction scheme
+ * (may perhaps also serve for Amigas?)
+ * - Can now play samples at almost all frequencies by
+ * means of a more generalized expand routine
+ * - Takes a good deal of care to cut data only at
+ * sample sizes
+ * - Buffer size is now a kernel runtime option
+ * - Implemented fsync() & several minor improvements
+ * Guenther Kelleter:
+ * - Useful hints and bug fixes
+ * - Cross-checked it for Falcons
+ *
+ * 1996/3/9 Geert Uytterhoeven:
+ * - Support added for Amiga, A-law, 16-bit little
+ * endian.
+ * - Unification to drivers/sound/dmasound.c.
+ *
+ * 1996/4/6 Martin Mitchell:
+ * - Updated to 1.3 kernel.
+ *
+ * 1996/6/13 Topi Kanerva:
+ * - Fixed things that were broken (mainly the amiga
+ * 14-bit routines)
+ * - /dev/sndstat shows now the real hardware frequency
+ * - The lowpass filter is disabled by default now
+ *
+ * 1996/9/25 Geert Uytterhoeven:
+ * - Modularization
+ *
+ * 1998/6/10 Andreas Schwab:
+ * - Converted to use sound_core
+ *
+ * 1999/12/28 Richard Zidlicky:
+ * - Added support for Q40
+ *
+ * 2000/2/27 Geert Uytterhoeven:
+ * - Clean up and split the code into 4 parts:
+ * o dmasound_core: machine-independent code
+ * o dmasound_atari: Atari TT and Falcon support
+ * o dmasound_awacs: Apple PowerMac support
+ * o dmasound_paula: Amiga support
+ *
+ * 2000/3/25 Geert Uytterhoeven:
+ * - Integration of dmasound_q40
+ * - Small clean ups
+ */
+
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/sound.h>
+#include <linux/init.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+
+#include "dmasound.h"
+
+
+ /*
+ * Declarations
+ */
+
+int dmasound_catchRadius = 0;
+static unsigned int numWriteBufs = 4;
+static unsigned int writeBufSize = 32; /* in KB! */
+#ifdef HAS_RECORD
+static unsigned int numReadBufs = 4;
+static unsigned int readBufSize = 32; /* in KB! */
+#endif
+
+MODULE_PARM(dmasound_catchRadius, "i");
+MODULE_PARM(numWriteBufs, "i");
+MODULE_PARM(writeBufSize, "i");
+MODULE_PARM(numReadBufs, "i");
+MODULE_PARM(readBufSize, "i");
+
+#ifdef MODULE
+static int sq_unit = -1;
+static int mixer_unit = -1;
+static int state_unit = -1;
+static int irq_installed = 0;
+#endif /* MODULE */
+
+
+ /*
+ * Conversion tables
+ */
+
+#ifdef HAS_8BIT_TABLES
+/* 8 bit mu-law */
+
+char dmasound_ulaw2dma8[] = {
+ -126, -122, -118, -114, -110, -106, -102, -98,
+ -94, -90, -86, -82, -78, -74, -70, -66,
+ -63, -61, -59, -57, -55, -53, -51, -49,
+ -47, -45, -43, -41, -39, -37, -35, -33,
+ -31, -30, -29, -28, -27, -26, -25, -24,
+ -23, -22, -21, -20, -19, -18, -17, -16,
+ -16, -15, -15, -14, -14, -13, -13, -12,
+ -12, -11, -11, -10, -10, -9, -9, -8,
+ -8, -8, -7, -7, -7, -7, -6, -6,
+ -6, -6, -5, -5, -5, -5, -4, -4,
+ -4, -4, -4, -4, -3, -3, -3, -3,
+ -3, -3, -3, -3, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 0,
+ 125, 121, 117, 113, 109, 105, 101, 97,
+ 93, 89, 85, 81, 77, 73, 69, 65,
+ 62, 60, 58, 56, 54, 52, 50, 48,
+ 46, 44, 42, 40, 38, 36, 34, 32,
+ 30, 29, 28, 27, 26, 25, 24, 23,
+ 22, 21, 20, 19, 18, 17, 16, 15,
+ 15, 14, 14, 13, 13, 12, 12, 11,
+ 11, 10, 10, 9, 9, 8, 8, 7,
+ 7, 7, 6, 6, 6, 6, 5, 5,
+ 5, 5, 4, 4, 4, 4, 3, 3,
+ 3, 3, 3, 3, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* 8 bit A-law */
+
+char dmasound_alaw2dma8[] = {
+ -22, -21, -24, -23, -18, -17, -20, -19,
+ -30, -29, -32, -31, -26, -25, -28, -27,
+ -11, -11, -12, -12, -9, -9, -10, -10,
+ -15, -15, -16, -16, -13, -13, -14, -14,
+ -86, -82, -94, -90, -70, -66, -78, -74,
+ -118, -114, -126, -122, -102, -98, -110, -106,
+ -43, -41, -47, -45, -35, -33, -39, -37,
+ -59, -57, -63, -61, -51, -49, -55, -53,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -6, -6, -6, -6, -5, -5, -5, -5,
+ -8, -8, -8, -8, -7, -7, -7, -7,
+ -3, -3, -3, -3, -3, -3, -3, -3,
+ -4, -4, -4, -4, -4, -4, -4, -4,
+ 21, 20, 23, 22, 17, 16, 19, 18,
+ 29, 28, 31, 30, 25, 24, 27, 26,
+ 10, 10, 11, 11, 8, 8, 9, 9,
+ 14, 14, 15, 15, 12, 12, 13, 13,
+ 86, 82, 94, 90, 70, 66, 78, 74,
+ 118, 114, 126, 122, 102, 98, 110, 106,
+ 43, 41, 47, 45, 35, 33, 39, 37,
+ 59, 57, 63, 61, 51, 49, 55, 53,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 4, 4, 4, 4,
+ 7, 7, 7, 7, 6, 6, 6, 6,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3
+};
+#endif /* HAS_8BIT_TABLES */
+
+#ifdef HAS_16BIT_TABLES
+
+/* 16 bit mu-law */
+
+short dmasound_ulaw2dma16[] = {
+ -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+ -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+ -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+ -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
+ -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+ -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+ -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+ -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+ -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+ -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
+ -876, -844, -812, -780, -748, -716, -684, -652,
+ -620, -588, -556, -524, -492, -460, -428, -396,
+ -372, -356, -340, -324, -308, -292, -276, -260,
+ -244, -228, -212, -196, -180, -164, -148, -132,
+ -120, -112, -104, -96, -88, -80, -72, -64,
+ -56, -48, -40, -32, -24, -16, -8, 0,
+ 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+ 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+ 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+ 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
+ 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
+ 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
+ 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
+ 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
+ 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
+ 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
+ 876, 844, 812, 780, 748, 716, 684, 652,
+ 620, 588, 556, 524, 492, 460, 428, 396,
+ 372, 356, 340, 324, 308, 292, 276, 260,
+ 244, 228, 212, 196, 180, 164, 148, 132,
+ 120, 112, 104, 96, 88, 80, 72, 64,
+ 56, 48, 40, 32, 24, 16, 8, 0,
+};
+
+/* 16 bit A-law */
+
+short dmasound_alaw2dma16[] = {
+ -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+ -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+ -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+ -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+ -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+ -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+ -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
+ -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+ -344, -328, -376, -360, -280, -264, -312, -296,
+ -472, -456, -504, -488, -408, -392, -440, -424,
+ -88, -72, -120, -104, -24, -8, -56, -40,
+ -216, -200, -248, -232, -152, -136, -184, -168,
+ -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+ -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+ -688, -656, -752, -720, -560, -528, -624, -592,
+ -944, -912, -1008, -976, -816, -784, -880, -848,
+ 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
+ 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
+ 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
+ 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
+ 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+ 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+ 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
+ 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+ 344, 328, 376, 360, 280, 264, 312, 296,
+ 472, 456, 504, 488, 408, 392, 440, 424,
+ 88, 72, 120, 104, 24, 8, 56, 40,
+ 216, 200, 248, 232, 152, 136, 184, 168,
+ 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
+ 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
+ 688, 656, 752, 720, 560, 528, 624, 592,
+ 944, 912, 1008, 976, 816, 784, 880, 848,
+};
+#endif /* HAS_16BIT_TABLES */
+
+
+#ifdef HAS_14BIT_TABLES
+
+ /*
+ * Unused for now. Where are the MSB parts anyway??
+ */
+
+/* 14 bit mu-law (LSB) */
+
+char dmasound_ulaw2dma14l[] = {
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 49, 17, 49, 17, 49, 17, 49, 17,
+ 49, 17, 49, 17, 49, 17, 49, 17,
+ 41, 57, 9, 25, 41, 57, 9, 25,
+ 41, 57, 9, 25, 41, 57, 9, 25,
+ 37, 45, 53, 61, 5, 13, 21, 29,
+ 37, 45, 53, 61, 5, 13, 21, 29,
+ 35, 39, 43, 47, 51, 55, 59, 63,
+ 3, 7, 11, 15, 19, 23, 27, 31,
+ 34, 36, 38, 40, 42, 44, 46, 48,
+ 50, 52, 54, 56, 58, 60, 62, 0,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 15, 47, 15, 47, 15, 47, 15, 47,
+ 15, 47, 15, 47, 15, 47, 15, 47,
+ 23, 7, 55, 39, 23, 7, 55, 39,
+ 23, 7, 55, 39, 23, 7, 55, 39,
+ 27, 19, 11, 3, 59, 51, 43, 35,
+ 27, 19, 11, 3, 59, 51, 43, 35,
+ 29, 25, 21, 17, 13, 9, 5, 1,
+ 61, 57, 53, 49, 45, 41, 37, 33,
+ 30, 28, 26, 24, 22, 20, 18, 16,
+ 14, 12, 10, 8, 6, 4, 2, 0
+};
+
+/* 14 bit A-law (LSB) */
+
+char dmasound_alaw2dma14l[] = {
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 16, 48, 16, 48, 16, 48, 16, 48,
+ 16, 48, 16, 48, 16, 48, 16, 48,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 42, 46, 34, 38, 58, 62, 50, 54,
+ 10, 14, 2, 6, 26, 30, 18, 22,
+ 42, 46, 34, 38, 58, 62, 50, 54,
+ 10, 14, 2, 6, 26, 30, 18, 22,
+ 40, 56, 8, 24, 40, 56, 8, 24,
+ 40, 56, 8, 24, 40, 56, 8, 24,
+ 20, 28, 4, 12, 52, 60, 36, 44,
+ 20, 28, 4, 12, 52, 60, 36, 44,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 48, 16, 48, 16, 48, 16, 48, 16,
+ 48, 16, 48, 16, 48, 16, 48, 16,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 22, 18, 30, 26, 6, 2, 14, 10,
+ 54, 50, 62, 58, 38, 34, 46, 42,
+ 22, 18, 30, 26, 6, 2, 14, 10,
+ 54, 50, 62, 58, 38, 34, 46, 42,
+ 24, 8, 56, 40, 24, 8, 56, 40,
+ 24, 8, 56, 40, 24, 8, 56, 40,
+ 44, 36, 60, 52, 12, 4, 28, 20,
+ 44, 36, 60, 52, 12, 4, 28, 20
+};
+#endif /* HAS_14BIT_TABLES */
+
+
+ /*
+ * Common stuff
+ */
+
+static long long sound_lseek(struct file *file, long long offset, int orig)
+{
+ return -ESPIPE;
+}
+
+
+ /*
+ * Mid level stuff
+ */
+
+struct sound_settings dmasound;
+
+static inline void sound_silence(void)
+{
+ /* update hardware settings one more */
+ dmasound.mach.init();
+
+ dmasound.mach.silence();
+}
+
+static inline void sound_init(void)
+{
+ dmasound.mach.init();
+}
+
+static inline int sound_set_format(int format)
+{
+ return dmasound.mach.setFormat(format);
+}
+
+static int sound_set_speed(int speed)
+{
+ if (speed < 0)
+ return dmasound.soft.speed;
+
+ dmasound.soft.speed = speed;
+ dmasound.mach.init();
+ if (dmasound.minDev == SND_DEV_DSP)
+ dmasound.dsp.speed = dmasound.soft.speed;
+
+ return dmasound.soft.speed;
+}
+
+static int sound_set_stereo(int stereo)
+{
+ if (stereo < 0)
+ return dmasound.soft.stereo;
+
+ stereo = !!stereo; /* should be 0 or 1 now */
+
+ dmasound.soft.stereo = stereo;
+ if (dmasound.minDev == SND_DEV_DSP)
+ dmasound.dsp.stereo = stereo;
+ dmasound.mach.init();
+
+ return stereo;
+}
+
+static ssize_t sound_copy_translate(TRANS *trans, const u_char *userPtr,
+ size_t userCount, u_char frame[],
+ ssize_t *frameUsed, ssize_t frameLeft)
+{
+ ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+
+ switch (dmasound.soft.format) {
+ case AFMT_MU_LAW:
+ ct_func = trans->ct_ulaw;
+ break;
+ case AFMT_A_LAW:
+ ct_func = trans->ct_alaw;
+ break;
+ case AFMT_S8:
+ ct_func = trans->ct_s8;
+ break;
+ case AFMT_U8:
+ ct_func = trans->ct_u8;
+ break;
+ case AFMT_S16_BE:
+ ct_func = trans->ct_s16be;
+ break;
+ case AFMT_U16_BE:
+ ct_func = trans->ct_u16be;
+ break;
+ case AFMT_S16_LE:
+ ct_func = trans->ct_s16le;
+ break;
+ case AFMT_U16_LE:
+ ct_func = trans->ct_u16le;
+ break;
+ default:
+ return 0;
+ }
+ return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
+}
+
+
+ /*
+ * /dev/mixer abstraction
+ */
+
+static struct {
+ int busy;
+ int modify_counter;
+} mixer;
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+ MOD_INC_USE_COUNT;
+ dmasound.mach.open();
+ mixer.busy = 1;
+ return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+ mixer.busy = 0;
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg)
+{
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+ mixer.modify_counter++;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return IOCTL_OUT(arg, SOUND_VERSION);
+ case SOUND_MIXER_INFO:
+ {
+ mixer_info info;
+ strncpy(info.id, dmasound.mach.name2, sizeof(info.id));
+ strncpy(info.name, dmasound.mach.name2, sizeof(info.name));
+ info.name[sizeof(info.name)-1] = 0;
+ info.modify_counter = mixer.modify_counter;
+ copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
+ return 0;
+ }
+ }
+ if (dmasound.mach.mixer_ioctl)
+ return dmasound.mach.mixer_ioctl(cmd, arg);
+ return -EINVAL;
+}
+
+static struct file_operations mixer_fops =
+{
+ llseek: sound_lseek,
+ ioctl: mixer_ioctl,
+ open: mixer_open,
+ release: mixer_release,
+};
+
+static void __init mixer_init(void)
+{
+#ifndef MODULE
+ int mixer_unit;
+#endif
+ mixer_unit = register_sound_mixer(&mixer_fops, -1);
+ if (mixer_unit < 0)
+ return;
+
+ mixer.busy = 0;
+ dmasound.treble = 0;
+ dmasound.bass = 0;
+ if (dmasound.mach.mixer_init)
+ dmasound.mach.mixer_init();
+}
+
+
+ /*
+ * Sound queue stuff, the heart of the driver
+ */
+
+struct sound_queue dmasound_write_sq;
+#ifdef HAS_RECORD
+struct sound_queue dmasound_read_sq;
+#endif
+
+static int sq_allocate_buffers(struct sound_queue *sq, int num, int size)
+{
+ int i;
+
+ if (sq->buffers)
+ return 0;
+ sq->numBufs = num;
+ sq->bufSize = size;
+ sq->buffers = kmalloc (num * sizeof(char *), GFP_KERNEL);
+ if (!sq->buffers)
+ return -ENOMEM;
+ for (i = 0; i < num; i++) {
+ sq->buffers[i] = dmasound.mach.dma_alloc(size, GFP_KERNEL);
+ if (!sq->buffers[i]) {
+ while (i--)
+ dmasound.mach.dma_free(sq->buffers[i], size);
+ kfree(sq->buffers);
+ sq->buffers = 0;
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static void sq_release_buffers(struct sound_queue *sq)
+{
+ int i;
+
+ if (sq->buffers) {
+ if (sq != &write_sq && dmasound.mach.abort_read)
+ dmasound.mach.abort_read();
+ for (i = 0; i < sq->numBufs; i++)
+ dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);
+ kfree(sq->buffers);
+ sq->buffers = NULL;
+ }
+}
+
+static void sq_setup(struct sound_queue *sq, int max_count, int max_active,
+ int block_size)
+{
+ void (*setup_func)(void);
+
+ sq->max_count = max_count;
+ sq->max_active = max_active;
+ sq->block_size = block_size;
+
+ sq->front = sq->count = sq->rear_size = 0;
+ sq->syncing = 0;
+ sq->active = 0;
+
+ if (sq == &write_sq) {
+ sq->rear = -1;
+ setup_func = dmasound.mach.write_sq_setup;
+ } else {
+ sq->rear = 0;
+ setup_func = dmasound.mach.read_sq_setup;
+ }
+ if (setup_func)
+ setup_func();
+}
+
+static inline void sq_play(void)
+{
+ dmasound.mach.play();
+}
+
+static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
+ loff_t *ppos)
+{
+ ssize_t uWritten = 0;
+ u_char *dest;
+ ssize_t uUsed, bUsed, bLeft;
+
+ /* ++TeSche: Is something like this necessary?
+ * Hey, that's an honest question! Or does any other part of the
+ * filesystem already checks this situation? I really don't know.
+ */
+ if (uLeft == 0)
+ return 0;
+
+ /* The interrupt doesn't start to play the last, incomplete frame.
+ * Thus we can append to it without disabling the interrupts! (Note
+ * also that write_sq.rear isn't affected by the interrupt.)
+ */
+
+ if (write_sq.count > 0 &&
+ (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
+ dest = write_sq.buffers[write_sq.rear];
+ bUsed = write_sq.rear_size;
+ uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
+ dest, &bUsed, bLeft);
+ if (uUsed <= 0)
+ return uUsed;
+ src += uUsed;
+ uWritten += uUsed;
+ uLeft -= uUsed;
+ write_sq.rear_size = bUsed;
+ }
+
+ do {
+ while (write_sq.count == write_sq.max_active) {
+ sq_play();
+ if (write_sq.open_mode & O_NONBLOCK)
+ return uWritten > 0 ? uWritten : -EAGAIN;
+ SLEEP(write_sq.action_queue);
+ if (signal_pending(current))
+ return uWritten > 0 ? uWritten : -EINTR;
+ }
+
+ /* Here, we can avoid disabling the interrupt by first
+ * copying and translating the data, and then updating
+ * the write_sq variables. Until this is done, the interrupt
+ * won't see the new frame and we can work on it
+ * undisturbed.
+ */
+
+ dest = write_sq.buffers[(write_sq.rear+1) % write_sq.max_count];
+ bUsed = 0;
+ bLeft = write_sq.block_size;
+ uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
+ dest, &bUsed, bLeft);
+ if (uUsed <= 0)
+ break;
+ src += uUsed;
+ uWritten += uUsed;
+ uLeft -= uUsed;
+ if (bUsed) {
+ write_sq.rear = (write_sq.rear+1) % write_sq.max_count;
+ write_sq.rear_size = bUsed;
+ write_sq.count++;
+ }
+ } while (bUsed); /* uUsed may have been 0 */
+
+ sq_play();
+
+ return uUsed < 0? uUsed: uWritten;
+}
+
+#ifdef HAS_RECORD
+ /*
+ * Here is how the values are used for reading.
+ * The value 'active' simply indicates the DMA is running. This is done
+ * so the driver semantics are DMA starts when the first read is posted.
+ * The value 'front' indicates the buffer we should next send to the user.
+ * The value 'rear' indicates the buffer the DMA is currently filling.
+ * When 'front' == 'rear' the buffer "ring" is empty (we always have an
+ * empty available). The 'rear_size' is used to track partial offsets
+ * into the current buffer. Right now, I just keep the DMA running. If
+ * the reader can't keep up, the interrupt tosses the oldest buffer. We
+ * could also shut down the DMA in this case.
+ */
+
+static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
+ loff_t *ppos)
+{
+
+ ssize_t uRead, bLeft, bUsed, uUsed;
+
+ if (uLeft == 0)
+ return 0;
+
+ if (!read_sq.active && dmasound.mach.record)
+ dmasound.mach.record(); /* Kick off the record process. */
+
+ uRead = 0;
+
+ /* Move what the user requests, depending upon other options.
+ */
+ while (uLeft > 0) {
+
+ /* When front == rear, the DMA is not done yet.
+ */
+ while (read_sq.front == read_sq.rear) {
+ if (read_sq.open_mode & O_NONBLOCK) {
+ return uRead > 0 ? uRead : -EAGAIN;
+ }
+ SLEEP(read_sq.action_queue);
+ if (signal_pending(current))
+ return uRead > 0 ? uRead : -EINTR;
+ }
+
+ /* The amount we move is either what is left in the
+ * current buffer or what the user wants.
+ */
+ bLeft = read_sq.block_size - read_sq.rear_size;
+ bUsed = read_sq.rear_size;
+ uUsed = sound_copy_translate(dmasound.trans_read, dst, uLeft,
+ read_sq.buffers[read_sq.front],
+ &bUsed, bLeft);
+ if (uUsed <= 0)
+ return uUsed;
+ dst += uUsed;
+ uRead += uUsed;
+ uLeft -= uUsed;
+ read_sq.rear_size += bUsed;
+ if (read_sq.rear_size >= read_sq.block_size) {
+ read_sq.rear_size = 0;
+ read_sq.front++;
+ if (read_sq.front >= read_sq.max_active)
+ read_sq.front = 0;
+ }
+ }
+ return uRead;
+}
+#endif /* HAS_RECORD */
+
+static inline void sq_init_waitqueue(struct sound_queue *sq)
+{
+ init_waitqueue_head(&sq->action_queue);
+ init_waitqueue_head(&sq->open_queue);
+ init_waitqueue_head(&sq->sync_queue);
+ sq->busy = 0;
+}
+
+static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
+ mode_t mode)
+{
+ if (file->f_mode & mode) {
+ sq->busy = 0;
+ WAKE_UP(sq->open_queue);
+ }
+}
+
+static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
+ int numbufs, int bufsize)
+{
+ int rc = 0;
+
+ if (file->f_mode & mode) {
+ if (sq->busy) {
+ rc = -EBUSY;
+ if (file->f_flags & O_NONBLOCK)
+ return rc;
+ rc = -EINTR;
+ while (sq->busy) {
+ SLEEP(sq->open_queue);
+ if (signal_pending(current))
+ return rc;
+ }
+ rc = 0;
+ }
+ sq->busy = 1; /* Let's play spot-the-race-condition */
+
+ if (sq_allocate_buffers(sq, numbufs, bufsize)) {
+ sq_wake_up(sq, file, mode);
+ return rc;
+ }
+
+ sq_setup(sq, numbufs, numbufs, bufsize);
+ sq->open_mode = file->f_mode;
+ }
+ return rc;
+}
+
+#define write_sq_init_waitqueue() sq_init_waitqueue(&write_sq)
+#define write_sq_wake_up(file) sq_wake_up(&write_sq, file, FMODE_WRITE)
+#define write_sq_release_buffers() sq_release_buffers(&write_sq)
+#define write_sq_open(file) \
+ sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize << 10)
+
+#ifdef HAS_RECORD
+#define read_sq_init_waitqueue() sq_init_waitqueue(&read_sq)
+#define read_sq_wake_up(file) sq_wake_up(&read_sq, file, FMODE_READ)
+#define read_sq_release_buffers() sq_release_buffers(&read_sq)
+#define read_sq_open(file) \
+ sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize << 10)
+#else /* !HAS_RECORD */
+#define read_sq_init_waitqueue() do {} while (0)
+#define read_sq_wake_up(file) do {} while (0)
+#define read_sq_release_buffers() do {} while (0)
+#define read_sq_open(file) (0)
+#endif /* !HAS_RECORD */
+
+static int sq_open(struct inode *inode, struct file *file)
+{
+ int rc;
+
+ MOD_INC_USE_COUNT;
+ dmasound.mach.open();
+ if ((rc = write_sq_open(file)) || (rc = read_sq_open(file))) {
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+ return rc;
+ }
+
+ if (dmasound.mach.sq_open)
+ dmasound.mach.sq_open();
+ dmasound.minDev = MINOR(inode->i_rdev) & 0x0f;
+ dmasound.soft = dmasound.dsp;
+ dmasound.hard = dmasound.dsp;
+ sound_init();
+ if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+ sound_set_speed(8000);
+ sound_set_stereo(0);
+ sound_set_format(AFMT_MU_LAW);
+ }
+
+#if 0
+ if (file->f_mode == FMODE_READ && dmasound.mach.record) {
+ /* Start dma'ing straight away */
+ dmasound.mach.record();
+ }
+#endif
+
+ return 0;
+}
+
+static void sq_reset(void)
+{
+ sound_silence();
+ write_sq.active = 0;
+ write_sq.count = 0;
+ write_sq.front = (write_sq.rear+1) % write_sq.max_count;
+}
+
+static int sq_fsync(struct file *filp, struct dentry *dentry)
+{
+ int rc = 0;
+
+ write_sq.syncing = 1;
+ sq_play(); /* there may be an incomplete frame waiting */
+
+ while (write_sq.active) {
+ SLEEP(write_sq.sync_queue);
+ if (signal_pending(current)) {
+ /* While waiting for audio output to drain, an
+ * interrupt occurred. Stop audio output immediately
+ * and clear the queue. */
+ sq_reset();
+ rc = -EINTR;
+ break;
+ }
+ }
+
+ write_sq.syncing = 0;
+ return rc;
+}
+
+static int sq_release(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+
+ if (write_sq.busy)
+ rc = sq_fsync(file, file->f_dentry);
+ dmasound.soft = dmasound.dsp;
+ dmasound.hard = dmasound.dsp;
+ sound_silence();
+
+ write_sq_release_buffers();
+ read_sq_release_buffers();
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+
+ /* There is probably a DOS atack here. They change the mode flag. */
+ /* XXX add check here */
+ read_sq_wake_up(file);
+ write_sq_wake_up(file);
+
+ /* Wake up a process waiting for the queue being released.
+ * Note: There may be several processes waiting for a call
+ * to open() returning. */
+
+ return rc;
+}
+
+static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg)
+{
+ u_long fmt;
+ int data;
+ int size, nbufs;
+ audio_buf_info info;
+
+ switch (cmd) {
+ case SNDCTL_DSP_RESET:
+ sq_reset();
+ return 0;
+ case SNDCTL_DSP_POST:
+ case SNDCTL_DSP_SYNC:
+ return sq_fsync(file, file->f_dentry);
+
+ /* ++TeSche: before changing any of these it's
+ * probably wise to wait until sound playing has
+ * settled down. */
+ case SNDCTL_DSP_SPEED:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_speed(data));
+ case SNDCTL_DSP_STEREO:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_stereo(data));
+ case SOUND_PCM_WRITE_CHANNELS:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
+ case SNDCTL_DSP_SETFMT:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_format(data));
+ case SNDCTL_DSP_GETFMTS:
+ fmt = 0;
+ if (dmasound.trans_write) {
+ if (dmasound.trans_write->ct_ulaw)
+ fmt |= AFMT_MU_LAW;
+ if (dmasound.trans_write->ct_alaw)
+ fmt |= AFMT_A_LAW;
+ if (dmasound.trans_write->ct_s8)
+ fmt |= AFMT_S8;
+ if (dmasound.trans_write->ct_u8)
+ fmt |= AFMT_U8;
+ if (dmasound.trans_write->ct_s16be)
+ fmt |= AFMT_S16_BE;
+ if (dmasound.trans_write->ct_u16be)
+ fmt |= AFMT_U16_BE;
+ if (dmasound.trans_write->ct_s16le)
+ fmt |= AFMT_S16_LE;
+ if (dmasound.trans_write->ct_u16le)
+ fmt |= AFMT_U16_LE;
+ }
+ return IOCTL_OUT(arg, fmt);
+ case SNDCTL_DSP_GETBLKSIZE:
+ size = write_sq.block_size
+ * dmasound.soft.size * (dmasound.soft.stereo + 1)
+ / (dmasound.hard.size * (dmasound.hard.stereo + 1));
+ return IOCTL_OUT(arg, size);
+ case SNDCTL_DSP_SUBDIVIDE:
+ break;
+ case SNDCTL_DSP_SETFRAGMENT:
+ if (write_sq.count || write_sq.active || write_sq.syncing)
+ return -EINVAL;
+ IOCTL_IN(arg, size);
+ nbufs = size >> 16;
+ if (nbufs < 2 || nbufs > write_sq.numBufs)
+ nbufs = write_sq.numBufs;
+ size &= 0xffff;
+ if (size >= 8 && size <= 29) {
+ size = 1 << size;
+ size *= dmasound.hard.size * (dmasound.hard.stereo + 1);
+ size /= dmasound.soft.size * (dmasound.soft.stereo + 1);
+ if (size > write_sq.bufSize)
+ size = write_sq.bufSize;
+ } else
+ size = write_sq.bufSize;
+ sq_setup(&write_sq, write_sq.numBufs, nbufs, size);
+ return 0;
+ case SNDCTL_DSP_GETOSPACE:
+ info.fragments = write_sq.max_active - write_sq.count;
+ info.fragstotal = write_sq.max_active;
+ info.fragsize = write_sq.block_size;
+ info.bytes = info.fragments * info.fragsize;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+
+ default:
+ return mixer_ioctl(inode, file, cmd, arg);
+ }
+ return -EINVAL;
+}
+
+static struct file_operations sq_fops =
+{
+ llseek: sound_lseek,
+ write: sq_write,
+ ioctl: sq_ioctl,
+ open: sq_open,
+ release: sq_release,
+#ifdef HAS_RECORD
+ read: sq_read,
+#endif
+};
+
+static void __init sq_init(void)
+{
+#ifndef MODULE
+ int sq_unit;
+#endif
+ sq_unit = register_sound_dsp(&sq_fops, -1);
+ if (sq_unit < 0)
+ return;
+
+ write_sq_init_waitqueue();
+ read_sq_init_waitqueue();
+
+ /* whatever you like as startup mode for /dev/dsp,
+ * (/dev/audio hasn't got a startup mode). note that
+ * once changed a new open() will *not* restore these!
+ */
+ dmasound.dsp.format = AFMT_U8;
+ dmasound.dsp.stereo = 0;
+ dmasound.dsp.size = 8;
+
+ /* set minimum rate possible without expanding */
+ dmasound.dsp.speed = dmasound.mach.min_dsp_speed;
+
+ /* before the first open to /dev/dsp this wouldn't be set */
+ dmasound.soft = dmasound.dsp;
+ dmasound.hard = dmasound.dsp;
+
+ sound_silence();
+}
+
+
+ /*
+ * /dev/sndstat
+ */
+
+static struct {
+ int busy;
+ char buf[512]; /* state.buf should not overflow! */
+ int len, ptr;
+} state;
+
+static int state_open(struct inode *inode, struct file *file)
+{
+ char *buffer = state.buf;
+ int len = 0;
+
+ if (state.busy)
+ return -EBUSY;
+
+ MOD_INC_USE_COUNT;
+ dmasound.mach.open();
+ state.ptr = 0;
+ state.busy = 1;
+
+ len += sprintf(buffer+len, "%sDMA sound driver:\n", dmasound.mach.name);
+
+ len += sprintf(buffer+len, "\tsound.format = 0x%x",
+ dmasound.soft.format);
+ switch (dmasound.soft.format) {
+ case AFMT_MU_LAW:
+ len += sprintf(buffer+len, " (mu-law)");
+ break;
+ case AFMT_A_LAW:
+ len += sprintf(buffer+len, " (A-law)");
+ break;
+ case AFMT_U8:
+ len += sprintf(buffer+len, " (unsigned 8 bit)");
+ break;
+ case AFMT_S8:
+ len += sprintf(buffer+len, " (signed 8 bit)");
+ break;
+ case AFMT_S16_BE:
+ len += sprintf(buffer+len, " (signed 16 bit big)");
+ break;
+ case AFMT_U16_BE:
+ len += sprintf(buffer+len, " (unsigned 16 bit big)");
+ break;
+ case AFMT_S16_LE:
+ len += sprintf(buffer+len, " (signed 16 bit little)");
+ break;
+ case AFMT_U16_LE:
+ len += sprintf(buffer+len, " (unsigned 16 bit little)");
+ break;
+ }
+ len += sprintf(buffer+len, "\n");
+ len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+ dmasound.soft.speed, dmasound.hard.speed);
+ len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+ dmasound.soft.stereo,
+ dmasound.soft.stereo ? "stereo" : "mono");
+ if (dmasound.mach.state_info)
+ len += dmasound.mach.state_info(buffer);
+ len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
+ " sq.max_active = %d\n",
+ write_sq.block_size, write_sq.max_count,
+ write_sq.max_active);
+ len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n",
+ write_sq.count, write_sq.rear_size);
+ len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
+ write_sq.active, write_sq.syncing);
+ state.len = len;
+ return 0;
+}
+
+static int state_release(struct inode *inode, struct file *file)
+{
+ state.busy = 0;
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static ssize_t state_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ int n = state.len - state.ptr;
+ if (n > count)
+ n = count;
+ if (n <= 0)
+ return 0;
+ if (copy_to_user(buf, &state.buf[state.ptr], n))
+ return -EFAULT;
+ state.ptr += n;
+ return n;
+}
+
+static struct file_operations state_fops =
+{
+ llseek: sound_lseek,
+ read: state_read,
+ open: state_open,
+ release: state_release,
+};
+
+static void __init state_init(void)
+{
+#ifndef MODULE
+ int state_unit;
+#endif
+ state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
+ if (state_unit < 0)
+ return;
+ state.busy = 0;
+}
+
+
+ /*
+ * Config & Setup
+ *
+ * This function is called by _one_ chipset-specific driver
+ */
+
+int __init dmasound_init(void)
+{
+ if (irq_installed)
+ return -EBUSY;
+
+ /* Set up sound queue, /dev/audio and /dev/dsp. */
+
+ /* Set default settings. */
+ sq_init();
+
+ /* Set up /dev/sndstat. */
+ state_init();
+
+ /* Set up /dev/mixer. */
+ mixer_init();
+
+ if (!dmasound.mach.irqinit()) {
+ printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
+ return -ENODEV;
+ }
+#ifdef MODULE
+ irq_installed = 1;
+#endif
+
+ printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
+ numWriteBufs, writeBufSize);
+
+ return 0;
+}
+
+#ifdef MODULE
+
+void dmasound_deinit(void)
+{
+ if (irq_installed) {
+ sound_silence();
+ dmasound.mach.irqcleanup();
+ }
+
+ write_sq_release_buffers();
+ read_sq_release_buffers();
+
+ if (mixer_unit >= 0)
+ unregister_sound_mixer(mixer_unit);
+ if (state_unit >= 0)
+ unregister_sound_special(state_unit);
+ if (sq_unit >= 0)
+ unregister_sound_dsp(sq_unit);
+}
+
+#else /* !MODULE */
+
+static int __init dmasound_setup(char *str)
+{
+ int ints[6];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+
+ /* check the bootstrap parameter for "dmasound=" */
+
+ switch (ints[0]) {
+ case 3:
+ if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+ printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+ else
+ catchRadius = ints[3];
+ /* fall through */
+ case 2:
+ if (ints[1] < MIN_BUFFERS)
+ printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs);
+ else
+ numWriteBufs = ints[1];
+ if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+ printk("dmasound_setup: illegal buffer size, using default = %dK\n", writeBufSize);
+ else
+ writeBufSize = ints[2];
+ break;
+ case 0:
+ break;
+ default:
+ printk("dmasound_setup: illegal number of arguments\n");
+ return 0;
+ }
+ return 1;
+}
+
+__setup("dmasound=", dmasound_setup);
+
+#endif /* !MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(dmasound);
+EXPORT_SYMBOL(dmasound_init);
+#ifdef MODULE
+EXPORT_SYMBOL(dmasound_deinit);
+#endif
+EXPORT_SYMBOL(dmasound_write_sq);
+#ifdef HAS_RECORD
+EXPORT_SYMBOL(dmasound_read_sq);
+#endif
+EXPORT_SYMBOL(dmasound_catchRadius);
+#ifdef HAS_8BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma8);
+EXPORT_SYMBOL(dmasound_alaw2dma8);
+#endif
+#ifdef HAS_16BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma16);
+EXPORT_SYMBOL(dmasound_alaw2dma16);
+#endif
+#ifdef HAS_14BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma14l);
+EXPORT_SYMBOL(dmasound_ulaw2dma14h);
+EXPORT_SYMBOL(dmasound_alaw2dma14l);
+EXPORT_SYMBOL(dmasound_alaw2dma14h);
+#endif
+
diff --git a/drivers/sound/dmasound/dmasound_paula.c b/drivers/sound/dmasound/dmasound_paula.c
new file mode 100644
index 000000000..97e9e6cf8
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_paula.c
@@ -0,0 +1,690 @@
+
+/*
+ * linux/drivers/sound/dmasound_paula.c
+ *
+ * Amiga DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+#include "dmasound.h"
+
+
+ /*
+ * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+ * (Imported from arch/m68k/amiga/amisound.c)
+ *
+ * FIXME: if amifb is not used, there should be a method to change htotal
+ */
+
+extern volatile u_short amiga_audio_min_period;
+
+
+ /*
+ * amiga_mksound() should be able to restore the period after beeping
+ * (Imported from arch/m68k/amiga/amisound.c)
+ */
+
+extern u_short amiga_audio_period;
+
+
+ /*
+ * Audio DMA masks
+ */
+
+#define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
+#define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
+#define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
+
+
+ /*
+ * Helper pointers for 16(14)-bit sound
+ */
+
+static int write_sq_block_size_half, write_sq_block_size_quarter;
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void AmiOpen(void);
+static void AmiRelease(void);
+static void *AmiAlloc(unsigned int size, int flags);
+static void AmiFree(void *obj, unsigned int size);
+static int AmiIrqInit(void);
+#ifdef MODULE
+static void AmiIrqCleanUp(void);
+#endif
+static void AmiSilence(void);
+static void AmiInit(void);
+static int AmiSetFormat(int format);
+static int AmiSetVolume(int volume);
+static int AmiSetTreble(int treble);
+static void AmiPlayNextFrame(int index);
+static void AmiPlay(void);
+static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);
+
+
+/*** Mid level stuff *********************************************************/
+
+static void AmiMixerInit(void);
+static int AmiMixerIoctl(u_int cmd, u_long arg);
+static void AmiWriteSqSetup(void);
+static int AmiStateInfo(char *buffer);
+
+
+/*** Translations ************************************************************/
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+
+ /*
+ * Native format
+ */
+
+static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ void *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~1;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ } else {
+ u_char *left = &frame[*frameUsed>>1];
+ u_char *right = left+write_sq_block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(*left++, userPtr++)
+ || get_user(*right++, userPtr++))
+ return -EFAULT;
+ count--;
+ }
+ }
+ *frameUsed += used;
+ return used;
+}
+
+
+ /*
+ * Copy and convert 8 bit data
+ */
+
+#define GENERATE_AMI_CT8(funcname, convsample) \
+static ssize_t funcname(const u_char *userPtr, size_t userCount, \
+ u_char frame[], ssize_t *frameUsed, \
+ ssize_t frameLeft) \
+{ \
+ ssize_t count, used; \
+ \
+ if (!dmasound.soft.stereo) { \
+ u_char *p = &frame[*frameUsed]; \
+ count = min(userCount, frameLeft) & ~1; \
+ used = count; \
+ while (count > 0) { \
+ u_char data; \
+ if (get_user(data, userPtr++)) \
+ return -EFAULT; \
+ *p++ = convsample(data); \
+ count--; \
+ } \
+ } else { \
+ u_char *left = &frame[*frameUsed>>1]; \
+ u_char *right = left+write_sq_block_size_half; \
+ count = min(userCount, frameLeft)>>1 & ~1; \
+ used = count*2; \
+ while (count > 0) { \
+ u_char data; \
+ if (get_user(data, userPtr++)) \
+ return -EFAULT; \
+ *left++ = convsample(data); \
+ if (get_user(data, userPtr++)) \
+ return -EFAULT; \
+ *right++ = convsample(data); \
+ count--; \
+ } \
+ } \
+ *frameUsed += used; \
+ return used; \
+}
+
+#define AMI_CT_ULAW(x) (dmasound_ulaw2dma8[(x)])
+#define AMI_CT_ALAW(x) (dmasound_alaw2dma8[(x)])
+#define AMI_CT_U8(x) ((x) ^ 0x80)
+
+GENERATE_AMI_CT8(ami_ct_ulaw, AMI_CT_ULAW)
+GENERATE_AMI_CT8(ami_ct_alaw, AMI_CT_ALAW)
+GENERATE_AMI_CT8(ami_ct_u8, AMI_CT_U8)
+
+
+ /*
+ * Copy and convert 16 bit data
+ */
+
+#define GENERATE_AMI_CT_16(funcname, convsample) \
+static ssize_t funcname(const u_char *userPtr, size_t userCount, \
+ u_char frame[], ssize_t *frameUsed, \
+ ssize_t frameLeft) \
+{ \
+ ssize_t count, used; \
+ u_short data; \
+ \
+ if (!dmasound.soft.stereo) { \
+ u_char *high = &frame[*frameUsed>>1]; \
+ u_char *low = high+write_sq_block_size_half; \
+ count = min(userCount, frameLeft)>>1 & ~1; \
+ used = count*2; \
+ while (count > 0) { \
+ if (get_user(data, ((u_short *)userPtr)++)) \
+ return -EFAULT; \
+ data = convsample(data); \
+ *high++ = data>>8; \
+ *low++ = (data>>2) & 0x3f; \
+ count--; \
+ } \
+ } else { \
+ u_char *lefth = &frame[*frameUsed>>2]; \
+ u_char *leftl = lefth+write_sq_block_size_quarter; \
+ u_char *righth = lefth+write_sq_block_size_half; \
+ u_char *rightl = righth+write_sq_block_size_quarter; \
+ count = min(userCount, frameLeft)>>2 & ~1; \
+ used = count*4; \
+ while (count > 0) { \
+ if (get_user(data, ((u_short *)userPtr)++)) \
+ return -EFAULT; \
+ data = convsample(data); \
+ *lefth++ = data>>8; \
+ *leftl++ = (data>>2) & 0x3f; \
+ if (get_user(data, ((u_short *)userPtr)++)) \
+ return -EFAULT; \
+ data = convsample(data); \
+ *righth++ = data>>8; \
+ *rightl++ = (data>>2) & 0x3f; \
+ count--; \
+ } \
+ } \
+ *frameUsed += used; \
+ return used; \
+}
+
+#define AMI_CT_S16BE(x) (x)
+#define AMI_CT_U16BE(x) ((x) ^ 0x8000)
+#define AMI_CT_S16LE(x) (le2be16((x)))
+#define AMI_CT_U16LE(x) (le2be16((x)) ^ 0x8000)
+
+GENERATE_AMI_CT_16(ami_ct_s16be, AMI_CT_S16BE)
+GENERATE_AMI_CT_16(ami_ct_u16be, AMI_CT_U16BE)
+GENERATE_AMI_CT_16(ami_ct_s16le, AMI_CT_S16LE)
+GENERATE_AMI_CT_16(ami_ct_u16le, AMI_CT_U16LE)
+
+
+static TRANS transAmiga = {
+ ct_ulaw: ami_ct_ulaw,
+ ct_alaw: ami_ct_alaw,
+ ct_s8: ami_ct_s8,
+ ct_u8: ami_ct_u8,
+ ct_s16be: ami_ct_s16be,
+ ct_u16be: ami_ct_u16be,
+ ct_s16le: ami_ct_s16le,
+ ct_u16le: ami_ct_u16le,
+};
+
+/*** Low level stuff *********************************************************/
+
+
+static void AmiOpen(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void AmiRelease(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static inline void StopDMA(void)
+{
+ custom.aud[0].audvol = custom.aud[1].audvol = 0;
+ custom.aud[2].audvol = custom.aud[3].audvol = 0;
+ custom.dmacon = AMI_AUDIO_OFF;
+}
+
+static void *AmiAlloc(unsigned int size, int flags)
+{
+ return amiga_chip_alloc((long)size, "dmasound [Paula]");
+}
+
+static void AmiFree(void *obj, unsigned int size)
+{
+ amiga_chip_free (obj);
+}
+
+static int __init AmiIrqInit(void)
+{
+ /* turn off DMA for audio channels */
+ StopDMA();
+
+ /* Register interrupt handler. */
+ if (request_irq(IRQ_AMIGA_AUD0, AmiInterrupt, 0, "DMA sound",
+ AmiInterrupt))
+ return 0;
+ return 1;
+}
+
+#ifdef MODULE
+static void AmiIrqCleanUp(void)
+{
+ /* turn off DMA for audio channels */
+ StopDMA();
+ /* release the interrupt */
+ free_irq(IRQ_AMIGA_AUD0, AmiInterrupt);
+}
+#endif /* MODULE */
+
+static void AmiSilence(void)
+{
+ /* turn off DMA for audio channels */
+ StopDMA();
+}
+
+
+static void AmiInit(void)
+{
+ int period, i;
+
+ AmiSilence();
+
+ if (dmasound.soft.speed)
+ period = amiga_colorclock/dmasound.soft.speed-1;
+ else
+ period = amiga_audio_min_period;
+ dmasound.hard = dmasound.soft;
+ dmasound.trans_write = &transAmiga;
+
+ if (period < amiga_audio_min_period) {
+ /* we would need to squeeze the sound, but we won't do that */
+ period = amiga_audio_min_period;
+ } else if (period > 65535) {
+ period = 65535;
+ }
+ dmasound.hard.speed = amiga_colorclock/(period+1);
+
+ for (i = 0; i < 4; i++)
+ custom.aud[i].audper = period;
+ amiga_audio_period = period;
+
+ AmiSetTreble(50); /* recommended for newer amiga models */
+}
+
+
+static int AmiSetFormat(int format)
+{
+ int size;
+
+ /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ size = 8;
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = size;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = dmasound.soft.size;
+ }
+ AmiInit();
+
+ return format;
+}
+
+
+#define VOLUME_VOXWARE_TO_AMI(v) \
+ (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
+#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
+
+static int AmiSetVolume(int volume)
+{
+ dmasound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+ custom.aud[0].audvol = dmasound.volume_left;
+ dmasound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+ custom.aud[1].audvol = dmasound.volume_right;
+ if (dmasound.hard.size == 16) {
+ if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
+ custom.aud[2].audvol = 1;
+ custom.aud[3].audvol = 1;
+ } else {
+ custom.aud[2].audvol = 0;
+ custom.aud[3].audvol = 0;
+ }
+ }
+ return VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
+ (VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
+}
+
+static int AmiSetTreble(int treble)
+{
+ dmasound.treble = treble;
+ if (treble < 50)
+ ciaa.pra &= ~0x02;
+ else
+ ciaa.pra |= 0x02;
+ return treble;
+}
+
+
+#define AMI_PLAY_LOADED 1
+#define AMI_PLAY_PLAYING 2
+#define AMI_PLAY_MASK 3
+
+
+static void AmiPlayNextFrame(int index)
+{
+ u_char *start, *ch0, *ch1, *ch2, *ch3;
+ u_long size;
+
+ /* used by AmiPlay() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = write_sq.buffers[write_sq.front];
+ size = (write_sq.count == index ? write_sq.rear_size
+ : write_sq.block_size)>>1;
+
+ if (dmasound.hard.stereo) {
+ ch0 = start;
+ ch1 = start+write_sq_block_size_half;
+ size >>= 1;
+ } else {
+ ch0 = start;
+ ch1 = start;
+ }
+
+ custom.aud[0].audvol = dmasound.volume_left;
+ custom.aud[1].audvol = dmasound.volume_right;
+ if (dmasound.hard.size == 8) {
+ custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+ custom.aud[0].audlen = size;
+ custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+ custom.aud[1].audlen = size;
+ custom.dmacon = AMI_AUDIO_8;
+ } else {
+ size >>= 1;
+ custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+ custom.aud[0].audlen = size;
+ custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+ custom.aud[1].audlen = size;
+ if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
+ /* We can play pseudo 14-bit only with the maximum volume */
+ ch3 = ch0+write_sq_block_size_quarter;
+ ch2 = ch1+write_sq_block_size_quarter;
+ custom.aud[2].audvol = 1; /* we are being affected by the beeps */
+ custom.aud[3].audvol = 1; /* restoring volume here helps a bit */
+ custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+ custom.aud[2].audlen = size;
+ custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+ custom.aud[3].audlen = size;
+ custom.dmacon = AMI_AUDIO_14;
+ } else {
+ custom.aud[2].audvol = 0;
+ custom.aud[3].audvol = 0;
+ custom.dmacon = AMI_AUDIO_8;
+ }
+ }
+ write_sq.front = (write_sq.front+1) % write_sq.max_count;
+ write_sq.active |= AMI_PLAY_LOADED;
+}
+
+
+static void AmiPlay(void)
+{
+ int minframes = 1;
+
+ custom.intena = IF_AUD0;
+
+ if (write_sq.active & AMI_PLAY_LOADED) {
+ /* There's already a frame loaded */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
+
+ if (write_sq.active & AMI_PLAY_PLAYING)
+ /* Increase threshold: frame 1 is already being played */
+ minframes = 2;
+
+ if (write_sq.count < minframes) {
+ /* Nothing to do */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
+
+ if (write_sq.count <= minframes &&
+ write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
+
+ AmiPlayNextFrame(minframes);
+
+ custom.intena = IF_SETCLR | IF_AUD0;
+}
+
+
+static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ int minframes = 1;
+
+ custom.intena = IF_AUD0;
+
+ if (!write_sq.active) {
+ /* Playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(write_sq.sync_queue);
+ return;
+ }
+
+ if (write_sq.active & AMI_PLAY_PLAYING) {
+ /* We've just finished a frame */
+ write_sq.count--;
+ WAKE_UP(write_sq.action_queue);
+ }
+
+ if (write_sq.active & AMI_PLAY_LOADED)
+ /* Increase threshold: frame 1 is already being played */
+ minframes = 2;
+
+ /* Shift the flags */
+ write_sq.active = (write_sq.active<<1) & AMI_PLAY_MASK;
+
+ if (!write_sq.active)
+ /* No frame is playing, disable audio DMA */
+ StopDMA();
+
+ custom.intena = IF_SETCLR | IF_AUD0;
+
+ if (write_sq.count >= minframes)
+ /* Try to play the next frame */
+ AmiPlay();
+
+ if (!write_sq.active)
+ /* Nothing to play anymore.
+ Wake up a process waiting for audio output to drain. */
+ WAKE_UP(write_sq.sync_queue);
+}
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+static void __init AmiMixerInit(void)
+{
+ dmasound.volume_left = 64;
+ dmasound.volume_right = 64;
+ custom.aud[0].audvol = dmasound.volume_left;
+ custom.aud[3].audvol = 1; /* For pseudo 14bit */
+ custom.aud[1].audvol = dmasound.volume_right;
+ custom.aud[2].audvol = 1; /* For pseudo 14bit */
+ dmasound.treble = 50;
+}
+
+static int AmiMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_DEVMASK:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
+ case SOUND_MIXER_READ_RECMASK:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_READ_STEREODEVS:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg,
+ VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
+ VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_volume(data));
+ case SOUND_MIXER_READ_TREBLE:
+ return IOCTL_OUT(arg, dmasound.treble);
+ case SOUND_MIXER_WRITE_TREBLE:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_treble(data));
+ }
+ return -EINVAL;
+}
+
+
+static void AmiWriteSqSetup(void)
+{
+ write_sq_block_size_half = write_sq.block_size>>1;
+ write_sq_block_size_quarter = write_sq_block_size_half>>1;
+}
+
+
+static int AmiStateInfo(char *buffer)
+{
+ int len = 0;
+ len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+ dmasound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+ dmasound.volume_right);
+ return len;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machAmiga = {
+ name: "Amiga",
+ name2: "AMIGA",
+ open: AmiOpen,
+ release: AmiRelease,
+ dma_alloc: AmiAlloc,
+ dma_free: AmiFree,
+ irqinit: AmiIrqInit,
+#ifdef MODULE
+ irqcleanup: AmiIrqCleanUp,
+#endif /* MODULE */
+ init: AmiInit,
+ silence: AmiSilence,
+ setFormat: AmiSetFormat,
+ setVolume: AmiSetVolume,
+ setTreble: AmiSetTreble,
+ play: AmiPlay,
+ mixer_init: AmiMixerInit,
+ mixer_ioctl: AmiMixerIoctl,
+ write_sq_setup: AmiWriteSqSetup,
+ state_info: AmiStateInfo,
+ min_dsp_speed: 8000
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_paula_init(void)
+{
+ int err;
+
+ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) {
+ if (!request_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40,
+ "dmasound [Paula]"))
+ return -EBUSY;
+ dmasound.mach = machAmiga;
+ err = dmasound_init();
+ if (err)
+ release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
+ return err;
+ } else
+ return -ENODEV;
+}
+
+static void __exit dmasound_paula_cleanup(void)
+{
+ dmasound_deinit();
+ release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
+}
+
+module_init(dmasound_paula_init);
+module_exit(dmasound_paula_cleanup);
diff --git a/drivers/sound/dmasound/dmasound_q40.c b/drivers/sound/dmasound/dmasound_q40.c
new file mode 100644
index 000000000..1c4d43d94
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_q40.c
@@ -0,0 +1,587 @@
+
+/*
+ * linux/drivers/sound/dmasound_q40.c
+ *
+ * Q40 DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+#include <asm/q40_master.h>
+
+#include "dmasound.h"
+
+
+static int expand_bal; /* Balance factor for expanding (not volume!) */
+static int expand_data; /* Data for expanding */
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void Q40Open(void);
+static void Q40Release(void);
+static void *Q40Alloc(unsigned int size, int flags);
+static void Q40Free(void *, unsigned int);
+static int Q40IrqInit(void);
+#ifdef MODULE
+static void Q40IrqCleanUp(void);
+#endif
+static void Q40Silence(void);
+static void Q40Init(void);
+static int Q40SetFormat(int format);
+static int Q40SetVolume(int volume);
+static void Q40PlayNextFrame(int index);
+static void Q40Play(void);
+static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static void Q40Interrupt(void);
+
+
+/*** Mid level stuff *********************************************************/
+
+
+#if 1
+/* userCount, frameUsed, frameLeft == byte counts */
+static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+
+ used = count = min(userCount, frameLeft);
+ if (copy_from_user(p,userPtr,count))
+ return -EFAULT;
+ while (count > 0) {
+ *p = table[*p]+128;
+ p++;
+ count--;
+ }
+ *frameUsed += used ;
+ return used;
+}
+#else
+static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ u_char val;
+ int stereo = sound.soft.stereo;
+
+
+ frameLeft >>= 1;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data]+128;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data]+128;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 2;
+ return stereo? used * 2: used;
+}
+#endif
+
+#if 1
+static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+
+ used = count = min(userCount, frameLeft);
+ if (copy_from_user(p,userPtr,count))
+ return -EFAULT;
+ while (count > 0) {
+ *p = *p + 128;
+ p++;
+ count--;
+ }
+ *frameUsed += used;
+ return used;
+}
+#else
+static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ u_char val;
+ int stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 1;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data + 128;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data + 128;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 2;
+ return stereo? used * 2: used;
+}
+#endif
+
+#if 1
+static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+
+ used = count = min(userCount, frameLeft);
+ if (copy_from_user(p,userPtr,count))
+ return -EFAULT;
+ *frameUsed += used;
+ return used;
+}
+#else
+static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ u_char val;
+ int stereo = dmasound.soft.stereo;
+
+
+ frameLeft >>= 1;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 2;
+ return stereo? used * 2: used;
+}
+#endif
+
+/* a bit too complicated to optimise right now ..*/
+static ssize_t q40_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned char *table = (unsigned char *)
+ (dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
+ unsigned int data = expand_data;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ data += 0x80;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft);
+ utotal -= userCount;
+ return utotal;
+}
+
+
+static ssize_t q40_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ u_char *p = (u_char *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+
+
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = c ;
+ data += 0x80;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft);
+ utotal -= userCount;
+ return utotal;
+}
+
+
+static ssize_t q40_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ u_char *p = (u_char *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = c ;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) ;
+ utotal -= userCount;
+ return utotal;
+}
+
+
+static TRANS transQ40Normal = {
+ q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL
+};
+
+static TRANS transQ40Expanding = {
+ q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL
+};
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void Q40Open(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void Q40Release(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+
+static void *Q40Alloc(unsigned int size, int flags)
+{
+ return kmalloc(size, flags); /* change to vmalloc */
+}
+
+static void Q40Free(void *ptr, unsigned int size)
+{
+ kfree(ptr);
+}
+
+static int __init Q40IrqInit(void)
+{
+ /* Register interrupt handler. */
+ request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+ "DMA sound", Q40Interrupt);
+
+ return(1);
+}
+
+
+#ifdef MODULE
+static void Q40IrqCleanUp(void)
+{
+ master_outb(0,SAMPLE_ENABLE_REG);
+ free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
+}
+#endif /* MODULE */
+
+
+static void Q40Silence(void)
+{
+ master_outb(0,SAMPLE_ENABLE_REG);
+ *DAC_LEFT=*DAC_RIGHT=0;
+}
+
+static char *q40_pp=NULL;
+static unsigned int q40_sc=0;
+
+static void Q40PlayNextFrame(int index)
+{
+ u_char *start;
+ u_long size;
+ u_char speed;
+
+ /* used by Q40Play() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = write_sq.buffers[write_sq.front];
+ size = (write_sq.count == index ? write_sq.rear_size : write_sq.block_size);
+
+ q40_pp=start;
+ q40_sc=size;
+
+ write_sq.front = (write_sq.front+1) % write_sq.max_count;
+ write_sq.active++;
+
+ speed=(dmasound.hard.speed==10000 ? 0 : 1);
+
+ master_outb( 0,SAMPLE_ENABLE_REG);
+ free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
+ if (dmasound.soft.stereo)
+ request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+ "Q40 sound", Q40Interrupt);
+ else
+ request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
+ "Q40 sound", Q40Interrupt);
+
+ master_outb( speed, SAMPLE_RATE_REG);
+ master_outb( 1,SAMPLE_CLEAR_REG);
+ master_outb( 1,SAMPLE_ENABLE_REG);
+}
+
+static void Q40Play(void)
+{
+ unsigned long flags;
+
+ if (write_sq.active || write_sq.count<=0 ) {
+ /* There's already a frame loaded */
+ return;
+ }
+
+ /* nothing in the queue */
+ if (write_sq.count <= 1 && write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ return;
+ }
+ save_flags(flags); cli();
+ Q40PlayNextFrame(1);
+ restore_flags(flags);
+}
+
+static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ if (q40_sc>1){
+ *DAC_LEFT=*q40_pp++;
+ *DAC_RIGHT=*q40_pp++;
+ q40_sc -=2;
+ master_outb(1,SAMPLE_CLEAR_REG);
+ }else Q40Interrupt();
+}
+static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ if (q40_sc>0){
+ *DAC_LEFT=*q40_pp;
+ *DAC_RIGHT=*q40_pp++;
+ q40_sc --;
+ master_outb(1,SAMPLE_CLEAR_REG);
+ }else Q40Interrupt();
+}
+static void Q40Interrupt(void)
+{
+ if (!write_sq.active) {
+ /* playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(write_sq.sync_queue);
+ master_outb(0,SAMPLE_ENABLE_REG); /* better safe */
+ goto exit;
+ } else write_sq.active=0;
+ write_sq.count--;
+ Q40Play();
+
+ if (q40_sc<2)
+ { /* there was nothing to play, disable irq */
+ master_outb(0,SAMPLE_ENABLE_REG);
+ *DAC_LEFT=*DAC_RIGHT=0;
+ }
+ WAKE_UP(write_sq.action_queue);
+
+ exit:
+ master_outb(1,SAMPLE_CLEAR_REG);
+}
+
+
+static void Q40Init(void)
+{
+ int i, idx;
+ const int freq[] = {10000, 20000};
+
+ /* search a frequency that fits into the allowed error range */
+
+ idx = -1;
+ for (i = 0; i < 2; i++)
+ if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) <= catchRadius)
+ idx = i;
+
+ dmasound.hard = dmasound.soft;
+ /*sound.hard.stereo=1;*/ /* no longer true */
+ dmasound.hard.size=8;
+
+ if (idx > -1) {
+ dmasound.soft.speed = freq[idx];
+ dmasound.trans_write = &transQ40Normal;
+ } else
+ dmasound.trans_write = &transQ40Expanding;
+
+ Q40Silence();
+
+ if (dmasound.hard.speed > 20000) {
+ /* we would need to squeeze the sound, but we won't do that */
+ dmasound.hard.speed = 20000;
+ dmasound.trans_write = &transQ40Normal;
+ } else if (dmasound.hard.speed > 10000) {
+ dmasound.hard.speed = 20000;
+ } else {
+ dmasound.hard.speed = 10000;
+ }
+ expand_bal = -dmasound.soft.speed;
+}
+
+
+static int Q40SetFormat(int format)
+{
+ /* Q40 sound supports only 8bit modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return(dmasound.soft.format);
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_S8:
+ case AFMT_U8:
+ break;
+ default:
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = 8;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = 8;
+ }
+ Q40Init();
+
+ return(format);
+}
+
+static int Q40SetVolume(int volume)
+{
+ return 0;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machQ40 = {
+ name: "Q40",
+ name2: "Q40",
+ open: Q40Open,
+ release: Q40Release,
+ dma_alloc: Q40Alloc,
+ dma_free: Q40Free,
+ irqinit: Q40IrqInit,
+#ifdef MODULE
+ irqcleanup: Q40IrqCleanUp,
+#endif /* MODULE */
+ init: Q40Init,
+ silence: Q40Silence,
+ setFormat: Q40SetFormat,
+ setVolume: Q40SetVolume,
+ play: Q40Play
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_q40_init(void)
+{
+ if (MACH_IS_Q40) {
+ dmasound.mach = machQ40;
+ return dmasound_init();
+ } else
+ return -ENODEV;
+}
+
+static void __exit dmasound_q40_cleanup(void)
+{
+ dmasound_deinit();
+}
+
+module_init(dmasound_q40_init);
+module_exit(dmasound_q40_cleanup);
diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c
index bf605dbca..5ba9236a3 100644
--- a/drivers/sound/mad16.c
+++ b/drivers/sound/mad16.c
@@ -791,7 +791,7 @@ static int __init probe_mad16_mpu(struct address_info *hw_config)
mad_write(MC3_PORT, tmp | 0x04);
hw_config->driver_use_1 = SB_MIDI_ONLY;
- return sb_dsp_detect(hw_config, 0, 0);
+ return sb_dsp_detect(hw_config, 0, 0, NULL);
#else
/* assuming all later Mozart cards are identified as
* either 82C928 or Mozart. If so, following code attempts
diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h
index 6e24d6e89..f0afbe177 100644
--- a/drivers/sound/sb.h
+++ b/drivers/sound/sb.h
@@ -70,6 +70,13 @@ struct mixer_def {
typedef struct mixer_def mixer_tab[32][2];
typedef struct mixer_def mixer_ent;
+struct sb_module_options
+{
+ int esstype; /* ESS chip type */
+ int acer; /* Do acer notebook init? */
+ int sm_games; /* Logitech soundman games? */
+};
+
typedef struct sb_devc {
int dev;
@@ -128,7 +135,10 @@ typedef struct sb_devc {
int input_opened;
int midi_broken;
void (*midi_input_intr) (int dev, unsigned char data);
- void *midi_irq_cookie; /* IRQ cookie for the midi */
+ void *midi_irq_cookie; /* IRQ cookie for the midi */
+
+ struct sb_module_options sbmo; /* Module options */
+
} sb_devc;
/*
@@ -147,7 +157,7 @@ int sb_dsp_get_byte(sb_devc * devc);
int sb_dsp_reset (sb_devc *devc);
void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value);
unsigned int sb_getmixer (sb_devc *devc, unsigned int port);
-int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio);
+int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo);
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);
@@ -163,7 +173,6 @@ int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right);
int sb_audio_open(int dev, int mode);
void sb_audio_close(int dev);
-extern int acer;
extern sb_devc *last_sb;
/* From sb_common.c */
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index 557a971a4..513e6aa24 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -32,6 +32,10 @@
* 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.
+ * Alessandro Zummo <azummo@ita.flashnet.it>
+ *
+ * 26-03-2000 Fixed acer, esstype and sm_games module options.
+ * Alessandro Zummo <azummo@ita.flashnet.it>
*
*/
@@ -51,6 +55,22 @@ static int sbmpu = 0;
extern void *smw_free;
+/*
+ * 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
+ * to the 8bit channel.
+ */
+
+static int __initdata mpu_io = 0;
+static int __initdata io = -1;
+static int __initdata irq = -1;
+static int __initdata dma = -1;
+static int __initdata dma16 = -1; /* Set this for modules that need it */
+static int __initdata type = 0; /* Can set this to a specific card type */
+static int __initdata esstype = 0; /* ESS chip type */
+static int __initdata acer = 0; /* Do acer notebook init? */
+static int __initdata sm_games = 0; /* Logitech soundman games? */
+
static void __init attach_sb_card(struct address_info *hw_config)
{
if(!sb_dsp_init(hw_config))
@@ -60,6 +80,8 @@ static void __init attach_sb_card(struct address_info *hw_config)
static int __init probe_sb(struct address_info *hw_config)
{
+ struct sb_module_options sbmo;
+
if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1)
{
printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
@@ -127,14 +149,21 @@ iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n",
}
#endif
- /* This is useless since is done by sb_dsp_detect - azummo */
+ /* This is useless since it is done by sb_dsp_detect - azummo */
if (check_region(hw_config->io_base, 16))
{
printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base);
return 0;
}
- return sb_dsp_detect(hw_config, 0, 0);
+
+ /* Setup extra module options */
+
+ sbmo.acer = acer;
+ sbmo.sm_games = sm_games;
+ sbmo.esstype = esstype;
+
+ return sb_dsp_detect(hw_config, 0, 0, &sbmo);
}
static void __exit unload_sb(struct address_info *hw_config)
@@ -143,25 +172,11 @@ static void __exit unload_sb(struct address_info *hw_config)
sb_dsp_unload(hw_config, sbmpu);
}
-extern int esstype; /* ESS chip type */
-
static struct address_info cfg;
static struct address_info cfg_mpu;
struct pci_dev *sb_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
- * to the 8bit channel.
- */
-
-static int __initdata mpu_io = 0;
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1; /* Set this for modules that need it */
-static int __initdata type = 0; /* Can set this to a specific card type */
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index 80c282a5d..ad9808049 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -53,14 +53,6 @@ static unsigned char jazz_dma_bits[] = {
0, 1, 0, 2, 0, 3, 0, 4
};
-/* Do acer notebook init? */
-int acer = 0;
-
-/* soundman games? */
-int sm_games = 0;
-
-extern int esstype;
-
void *smw_free = NULL;
/*
@@ -503,12 +495,16 @@ static void relocate_ess1688(sb_devc * devc)
#endif
}
-int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio)
+int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo)
{
sb_devc sb_info;
sb_devc *devc = &sb_info;
memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */
+
+ /* Copy module options in place */
+ if(sbmo) memcpy(&devc->sbmo, sbmo, sizeof(struct sb_module_options));
+
sb_info.my_mididev = -1;
sb_info.my_mixerdev = -1;
sb_info.dev = -1;
@@ -553,7 +549,7 @@ int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio)
printk("Yamaha PCI mode.\n");
}
- if (acer)
+ if (devc->sbmo.acer)
{
cli();
inb(devc->base + 0x09);
@@ -1295,10 +1291,6 @@ void unload_sbmpu(struct address_info *hw_config)
unload_uart401(hw_config);
}
-MODULE_PARM(acer, "i");
-MODULE_PARM(sm_games, "i");
-MODULE_PARM(esstype, "i");
-
EXPORT_SYMBOL(sb_dsp_init);
EXPORT_SYMBOL(sb_dsp_detect);
EXPORT_SYMBOL(sb_dsp_unload);
diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c
index b6c9f0aee..dfb59016b 100644
--- a/drivers/sound/sb_ess.c
+++ b/drivers/sound/sb_ess.c
@@ -196,8 +196,6 @@
#define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */
#define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */
-int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */
-
#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */
#define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */
#define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */
@@ -1066,7 +1064,7 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
char *chip = NULL;
int submodel = -1;
- switch (esstype) {
+ switch (devc->sbmo.esstype) {
case ESSTYPE_DETECT:
case ESSTYPE_LIKE20:
break;
@@ -1098,12 +1096,12 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
submodel = SUBMDL_ES1888;
break;
default:
- printk (KERN_ERR "Invalid esstype=%d specified\n", esstype);
+ printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype);
return 0;
};
if (submodel != -1) {
devc->submodel = submodel;
- sprintf (modelname, "ES%d", esstype);
+ sprintf (modelname, "ES%d", devc->sbmo.esstype);
chip = modelname;
};
if (chip == NULL && (ess_minor & 0x0f) < 8) {
@@ -1116,7 +1114,7 @@ FKS_test (devc);
* If Nothing detected yet, and we want 2.0 behaviour...
* Then let's assume it's ES1688.
*/
- if (chip == NULL && esstype == ESSTYPE_LIKE20) {
+ if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) {
chip = "ES1688";
};
@@ -1185,11 +1183,11 @@ FKS_test (devc);
printk ( KERN_INFO "ESS chip %s %s%s\n"
, chip
- , ( esstype == ESSTYPE_DETECT || esstype == ESSTYPE_LIKE20
+ , ( devc->sbmo.esstype == ESSTYPE_DETECT || devc->sbmo.esstype == ESSTYPE_LIKE20
? "detected"
: "specified"
)
- , ( esstype == ESSTYPE_LIKE20
+ , ( devc->sbmo.esstype == ESSTYPE_LIKE20
? " (kernel 2.0 compatible)"
: ""
)
diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c
index a955db7e3..5a5487b16 100644
--- a/drivers/sound/sb_mixer.c
+++ b/drivers/sound/sb_mixer.c
@@ -642,11 +642,10 @@ static void sb_mixer_reset(sb_devc * devc)
{
char name[32];
int i;
- extern int sm_games;
sprintf(name, "SB_%d", devc->sbmixnum);
- if (sm_games)
+ if (devc->sbmo.sm_games)
devc->levels = load_mixer_volumes(name, smg_default_levels, 1);
else
devc->levels = load_mixer_volumes(name, sb_default_levels, 1);
diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h
index 8d450ca66..ffa0c1caf 100644
--- a/drivers/sound/sound_calls.h
+++ b/drivers/sound/sound_calls.h
@@ -89,10 +89,3 @@ void sound_timer_syncinterval(unsigned int new_usecs);
/* From midi_synth.c */
void do_midi_msg (int synthno, unsigned char *msg, int mlen);
-
-#ifdef FIXED_LOWLEVEL_SOUND
-/* From aedsp16.c */
-int InitAEDSP16_SBPRO(struct address_info *hw_config);
-int InitAEDSP16_MSS(struct address_info *hw_config);
-int InitAEDSP16_MPU401(struct address_info *hw_config);
-#endif
diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c
index 217bdb605..c0d6dd06a 100644
--- a/drivers/sound/sound_core.c
+++ b/drivers/sound/sound_core.c
@@ -218,7 +218,7 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
static struct sound_unit *chains[16];
/**
- * register_sound_special
+ * register_sound_special - register a special sound node
* @fops: File operations for the driver
* @unit: Unit number to allocate
*
@@ -288,7 +288,7 @@ int register_sound_special(struct file_operations *fops, int unit)
EXPORT_SYMBOL(register_sound_special);
/**
- * register_sound_mixer
+ * register_sound_mixer - register a mixer device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -306,7 +306,7 @@ int register_sound_mixer(struct file_operations *fops, int dev)
EXPORT_SYMBOL(register_sound_mixer);
/**
- * register_sound_midi
+ * register_sound_midi - register a midi device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -329,7 +329,7 @@ EXPORT_SYMBOL(register_sound_midi);
*/
/**
- * register_sound_dsp
+ * register_sound_dsp - register a DSP device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -350,7 +350,7 @@ int register_sound_dsp(struct file_operations *fops, int dev)
EXPORT_SYMBOL(register_sound_dsp);
/**
- * register_sound_synth
+ * register_sound_synth - register a synth device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -369,7 +369,7 @@ int register_sound_synth(struct file_operations *fops, int dev)
EXPORT_SYMBOL(register_sound_synth);
/**
- * unregister_sound_special
+ * unregister_sound_special - unregister a special sound device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_special.
@@ -385,7 +385,7 @@ void unregister_sound_special(int unit)
EXPORT_SYMBOL(unregister_sound_special);
/**
- * unregister_sound_mixer
+ * unregister_sound_mixer - unregister a mixer
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_mixer.
@@ -400,7 +400,7 @@ void unregister_sound_mixer(int unit)
EXPORT_SYMBOL(unregister_sound_mixer);
/**
- * unregister_sound_midi
+ * unregister_sound_midi - unregister a midi device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_midi.
@@ -415,7 +415,7 @@ void unregister_sound_midi(int unit)
EXPORT_SYMBOL(unregister_sound_midi);
/**
- * unregister_sound_dsp
+ * unregister_sound_dsp - unregister a DSP device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_dsp.
@@ -433,7 +433,7 @@ void unregister_sound_dsp(int unit)
EXPORT_SYMBOL(unregister_sound_dsp);
/**
- * unregister_sound_synth
+ * unregister_sound_synth - unregister a synth device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_synth.
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index f3b008f0c..f222592ea 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -46,14 +46,6 @@
#include "soundmodule.h"
-#if defined(CONFIG_LOWLEVEL_SOUND) && !defined MODULE
-extern void sound_preinit_lowlevel_drivers(void);
-extern void sound_init_lowlevel_drivers(void);
-#endif
-
-/* From obsolete legacy.h */
-#define SELECTED_SOUND_OPTIONS 0x0
-
struct notifier_block *sound_locker=(struct notifier_block *)0;
static int lock_depth = 0;
@@ -65,7 +57,6 @@ static int lock_depth = 0;
#endif
static int chrdev_registered = 0;
-static int is_unloading = 0;
/*
* Table for permanently allocated memory (used when unloading the module)
@@ -80,7 +71,6 @@ int sound_dmap_flag = 1;
int sound_dmap_flag = 0;
#endif
-static int soundcard_configured = 0;
static char dma_alloc_map[MAX_DMA_CHANNELS] = {0};
#define DMA_MAP_UNAVAIL 0
@@ -101,17 +91,14 @@ int *load_mixer_volumes(char *name, int *levels, int present)
{
int i, n;
- for (i = 0; i < num_mixer_volumes; i++)
- {
- if (strcmp(name, mixer_vols[i].name) == 0)
- {
+ for (i = 0; i < num_mixer_volumes; i++) {
+ if (strcmp(name, mixer_vols[i].name) == 0) {
if (present)
mixer_vols[i].num = i;
return mixer_vols[i].levels;
}
}
- if (num_mixer_volumes >= MAX_MIXER_DEV)
- {
+ if (num_mixer_volumes >= MAX_MIXER_DEV) {
printk(KERN_ERR "Sound: Too many mixers (%s)\n", name);
return levels;
}
@@ -229,26 +216,15 @@ static long long sound_lseek(struct file *file, long long offset, int orig)
static int sound_open(struct inode *inode, struct file *file)
{
- int dev, retval;
+ int dev = MINOR(inode->i_rdev);
+ int retval;
- if (is_unloading) {
- /* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/
- return -EBUSY;
- }
- dev = MINOR(inode->i_rdev);
- if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) {
- /* printk("SoundCard Error: The sound system has not been configured\n");*/
- return -ENXIO;
- }
DEB(printk("sound_open(dev=%d)\n", dev));
if ((dev >= SND_NDEVS) || (dev < 0)) {
/* printk(KERN_ERR "Invalid minor device %d\n", dev);*/
return -ENXIO;
}
switch (dev & 0x0f) {
- case SND_DEV_STATUS:
- break;
-
case SND_DEV_CTL:
dev >>= 4;
if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
@@ -296,7 +272,6 @@ static int sound_release(struct inode *inode, struct file *file)
DEB(printk("sound_release(dev=%d)\n", dev));
switch (dev & 0x0f) {
- case SND_DEV_STATUS:
case SND_DEV_CTL:
break;
@@ -470,45 +445,38 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
dev_class = dev & 0x0f;
dev >>= 4;
- if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO)
- {
-/* printk("Sound: mmap() not supported for other than audio devices\n");*/
+ if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) {
+ printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
return -EINVAL;
}
if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */
dmap = audio_devs[dev]->dmap_out;
else if (vma->vm_flags & VM_READ)
dmap = audio_devs[dev]->dmap_in;
- else
- {
-/* printk("Sound: Undefined mmap() access\n");*/
+ else {
+ printk(KERN_ERR "Sound: Undefined mmap() access\n");
return -EINVAL;
}
- if (dmap == NULL)
- {
-/* printk("Sound: mmap() error. dmap == NULL\n");*/
+ if (dmap == NULL) {
+ printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
return -EIO;
}
- if (dmap->raw_buf == NULL)
- {
-/* printk("Sound: mmap() called when raw_buf == NULL\n");*/
+ if (dmap->raw_buf == NULL) {
+ printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
return -EIO;
}
- if (dmap->mapping_flags)
- {
-/* printk("Sound: mmap() called twice for the same DMA buffer\n");*/
+ if (dmap->mapping_flags) {
+ printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
return -EIO;
}
- if (vma->vm_pgoff != 0)
- {
-/* printk("Sound: mmap() offset must be 0.\n");*/
+ if (vma->vm_pgoff != 0) {
+ printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
return -EINVAL;
}
size = vma->vm_end - vma->vm_start;
- if (size != dmap->bytes_in_use)
- {
+ if (size != dmap->bytes_in_use) {
printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use);
}
if (remap_page_range(vma->vm_start, virt_to_phys(dmap->raw_buf),
@@ -546,19 +514,14 @@ struct file_operations oss_sound_fops =
static int create_special_devices(void)
{
int seq1,seq2;
- int sndstat=register_sound_special(&oss_sound_fops, 6);
- if(sndstat==-1)
- goto bad1;
seq1=register_sound_special(&oss_sound_fops, 1);
if(seq1==-1)
- goto bad2;
+ goto bad;
seq2=register_sound_special(&oss_sound_fops, 8);
if(seq2!=-1)
return 0;
unregister_sound_special(1);
-bad2:
- unregister_sound_special(6);
-bad1:
+bad:
return -1;
}
@@ -594,30 +557,27 @@ soundcard_make_name(char *buf, char *name, int idx) {
/* Register/unregister audio entries */
static void soundcard_register_devfs (int do_register)
{
- char name_buf[32];
- int i, j, num;
-
- for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++)
- {
- num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num;
- for (j = 0; j < num || j == 0; j++)
- {
- soundcard_make_name (name_buf, dev_list[i].name, j);
- if (do_register)
- devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
- SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
- S_IFCHR | dev_list[i].mode, 0, 0,
- &oss_sound_fops, NULL);
- else
- {
- devfs_handle_t de;
-
- de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
+ char name_buf[32];
+ int i, j, num;
+
+ for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) {
+ num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num;
+ for (j = 0; j < num || j == 0; j++) {
+ soundcard_make_name (name_buf, dev_list[i].name, j);
+ if (do_register)
+ devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
+ SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
+ S_IFCHR | dev_list[i].mode, 0, 0,
+ &oss_sound_fops, NULL);
+ else {
+ devfs_handle_t de;
+
+ de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
DEVFS_SPECIAL_CHR, 0);
- devfs_unregister (de);
- }
+ devfs_unregister (de);
+ }
+ }
}
- }
}
#ifdef MODULE
@@ -638,10 +598,6 @@ soundcard_init(void)
chrdev_registered = 1;
#endif
- soundcard_configured = 1;
-
- audio_init_devices();
-
soundcard_register_devfs(1); /* register after we know # of devices */
}
@@ -650,14 +606,9 @@ soundcard_init(void)
static void destroy_special_devices(void)
{
unregister_sound_special(6);
- unregister_sound_special(1);
unregister_sound_special(8);
}
-static int sound[20] = {
- 0
-};
-
static int dmabuf = 0;
static int dmabug = 0;
@@ -668,12 +619,12 @@ int init_module(void)
{
int err;
+#ifdef CONFIG_PCI
if(dmabug)
isa_dma_bridge_buggy = dmabug;
-
+#endif
err = create_special_devices();
- if (err)
- {
+ if (err) {
printk(KERN_ERR "sound: driver already loaded/included in kernel\n");
return err;
}
@@ -695,10 +646,8 @@ void cleanup_module(void)
int i;
if (MOD_IN_USE)
- {
return;
- }
- remove_proc_entry("sound", NULL);
+
soundcard_register_devfs (0);
if (chrdev_registered)
destroy_special_devices();
@@ -708,17 +657,13 @@ void cleanup_module(void)
sequencer_unload();
for (i = 0; i < MAX_DMA_CHANNELS; i++)
- {
- if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
- {
+ if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) {
printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i);
sound_free_dma(i);
}
- }
+
for (i = 0; i < sound_nblocks; i++)
- {
vfree(sound_mem_blocks[i]);
- }
}
#endif
@@ -739,16 +684,14 @@ int sound_open_dma(int chn, char *deviceID)
{
unsigned long flags;
- if (!valid_dma(chn))
- {
+ if (!valid_dma(chn)) {
printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn);
return 1;
}
save_flags(flags);
cli();
- if (dma_alloc_map[chn] != DMA_MAP_FREE)
- {
+ if (dma_alloc_map[chn] != DMA_MAP_FREE) {
printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]);
restore_flags(flags);
return 1;
@@ -760,8 +703,7 @@ int sound_open_dma(int chn, char *deviceID)
void sound_free_dma(int chn)
{
- if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL)
- {
+ if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) {
/* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */
return;
}
@@ -776,8 +718,7 @@ void sound_close_dma(int chn)
save_flags(flags);
cli();
- if (dma_alloc_map[chn] != DMA_MAP_BUSY)
- {
+ if (dma_alloc_map[chn] != DMA_MAP_BUSY) {
printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn);
restore_flags(flags);
return;
@@ -799,8 +740,7 @@ void request_sound_timer(int count)
{
extern unsigned long seq_time;
- if (count < 0)
- {
+ if (count < 0) {
seq_timer.expires = (-count) + jiffies;
add_timer(&seq_timer);
return;
@@ -879,8 +819,7 @@ void sound_notifier_chain_register(struct notifier_block *bl)
* Normalise the lock count by calling the entry directly. We
* have to call the module as it owns its own use counter
*/
- while(ct<lock_depth)
- {
+ while(ct<lock_depth) {
bl->notifier_call(bl, 1, 0);
ct++;
}
diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c
index d36da3f9c..986544401 100644
--- a/drivers/sound/trix.c
+++ b/drivers/sound/trix.c
@@ -318,7 +318,7 @@ static int __init probe_trix_sb(struct address_info *hw_config)
sb_initialized = 1;
hw_config->name = "AudioTrix SB";
- return sb_dsp_detect(hw_config, 0, 0);
+ return sb_dsp_detect(hw_config, 0, 0, NULL);
}
static void __init attach_trix_sb(struct address_info *hw_config)
diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c
index 5745a9037..7f88b8177 100644
--- a/drivers/sound/via82cxxx_audio.c
+++ b/drivers/sound/via82cxxx_audio.c
@@ -486,7 +486,7 @@ static int __init via_probe_sb(struct address_info *hw_config)
return 0;
}
DPRINTK("EXIT after sb_dsp_detect\n");
- return sb_dsp_detect(hw_config, 0, 0);
+ return sb_dsp_detect(hw_config, 0, 0, NULL);
}
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
index 0f3195163..fc4f61b34 100644
--- a/drivers/telephony/phonedev.c
+++ b/drivers/telephony/phonedev.c
@@ -28,6 +28,7 @@
#include <asm/system.h>
#include <linux/kmod.h>
+#include <linux/sem.h>
#define PHONE_NUM_DEVICES 256
@@ -37,6 +38,7 @@
*/
static struct phone_device *phone_device[PHONE_NUM_DEVICES];
+static DECLARE_MUTEX(phone_lock);
/*
* Open a phone device.
@@ -45,29 +47,37 @@ static struct phone_device *phone_device[PHONE_NUM_DEVICES];
static int phone_open(struct inode *inode, struct file *file)
{
unsigned int minor = MINOR(inode->i_rdev);
- int err;
+ int err = 0;
struct phone_device *p;
if (minor >= PHONE_NUM_DEVICES)
return -ENODEV;
+ down(&phone_lock);
p = phone_device[minor];
if (p == NULL) {
char modname[32];
+ up(&phone_lock);
sprintf(modname, "char-major-%d-%d", PHONE_MAJOR, minor);
request_module(modname);
+ down(&phone_lock);
p = phone_device[minor];
if (p == NULL)
- return -ENODEV;
+ {
+ err=-ENODEV;
+ goto end;
+ }
}
if (p->open) {
err = p->open(p, file); /* Tell the device it is open */
if (err)
- return err;
+ goto end;
}
file->f_op = p->f_op;
- return 0;
+end:
+ up(&phone_lock);
+ return err;
}
/*
@@ -87,14 +97,18 @@ int phone_register_device(struct phone_device *p, int unit)
base = unit;
end = unit + 1; /* enter the loop at least one time */
}
+
+ down(&phone_lock);
for (i = base; i < end; i++) {
if (phone_device[i] == NULL) {
phone_device[i] = p;
p->minor = i;
MOD_INC_USE_COUNT;
+ up(&phone_lock);
return 0;
}
}
+ up(&phone_lock);
return -ENFILE;
}
@@ -104,9 +118,11 @@ int phone_register_device(struct phone_device *p, int unit)
void phone_unregister_device(struct phone_device *pfd)
{
+ down(&phone_lock);
if (phone_device[pfd->minor] != pfd)
panic("phone: bad unregister");
phone_device[pfd->minor] = NULL;
+ up(&phone_lock);
MOD_DEC_USE_COUNT;
}
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 28ad96481..460a44105 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -6,6 +6,10 @@ comment 'USB support'
tristate 'Support for USB' CONFIG_USB
if [ ! "$CONFIG_USB" = "n" ]; then
+ bool ' USB verbose debug messages' CONFIG_USB_DEBUG
+
+comment 'Miscellaneous USB options'
+ bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
comment 'USB Controllers'
if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
@@ -13,19 +17,13 @@ comment 'USB Controllers'
fi
if [ "$CONFIG_USB_UHCI" != "y" ]; then
dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
- if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
- fi
fi
dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
-comment 'Miscellaneous USB options'
- bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
-
comment 'USB Devices'
dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
- dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB
+ dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
if [ "$CONFIG_USB_SERIAL" != "n" ]; then
@@ -38,9 +36,8 @@ comment 'USB Devices'
fi
bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
fi
- dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
- dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB
- dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
+ dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
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
@@ -52,12 +49,12 @@ comment 'USB Devices'
dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB
- dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB
+ dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET
+ dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
- dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB
+ dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV
fi
-
+
comment 'USB HID'
dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
if [ "$CONFIG_USB_HID" != "y" ]; then
@@ -69,12 +66,8 @@ comment 'USB HID'
dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB
dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
- bool ' Mix all mice into one device' CONFIG_INPUT_MOUSEDEV_MIX
- bool ' Support for digitizers' CONFIG_INPUT_MOUSEDEV_DIGITIZER
- if [ "$CONFIG_INPUT_MOUSEDEV_DIGITIZER" != "n" ]; then
- int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
- int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
- fi
+ int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
+ int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
fi
dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB
dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 06b0a4648..f0ca0476e 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -42,7 +42,7 @@ obj- :=
ifeq ($(CONFIG_USB_SERIAL),y)
SUB_DIRS += serial
- obj-y += serial/serial.o
+ obj-y += serial/usb-serial.o
else
ifeq ($(CONFIG_USB_SERIAL),m)
MOD_IN_SUB_DIRS += serial
@@ -71,7 +71,6 @@ obj-$(CONFIG_USB_SCANNER) += scanner.o
obj-$(CONFIG_USB_ACM) += acm.o
obj-$(CONFIG_USB_PRINTER) += printer.o
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
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 723ceb481..453c4af19 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -52,6 +52,10 @@
#define DEBUG
#include <linux/usb.h>
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned minor);
+void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
+
/*
* CMSPAR, some architectures can't have space and mark parity.
*/
@@ -143,6 +147,7 @@ struct acm {
};
static struct usb_driver acm_driver;
+static struct tty_driver acm_tty_driver;
static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, /* .... */ };
#define ACM_READY(acm) (acm && acm->dev && acm->used)
@@ -306,20 +311,19 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
if (!acm || !acm->used) return;
- MOD_DEC_USE_COUNT;
-
- if (--acm->used) return;
-
- if (acm->dev) {
- acm_set_control(acm, acm->ctrlout = 0);
- usb_unlink_urb(&acm->ctrlurb);
- usb_unlink_urb(&acm->writeurb);
- usb_unlink_urb(&acm->readurb);
- return;
+ if (!--acm->used) {
+ if (acm->dev) {
+ acm_set_control(acm, acm->ctrlout = 0);
+ usb_unlink_urb(&acm->ctrlurb);
+ usb_unlink_urb(&acm->writeurb);
+ usb_unlink_urb(&acm->readurb);
+ } else {
+ tty_unregister_devfs(&acm_tty_driver, acm->minor);
+ acm_table[acm->minor] = NULL;
+ kfree(acm);
+ }
}
-
- acm_table[acm->minor] = NULL;
- kfree(acm);
+ MOD_DEC_USE_COUNT;
}
static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
@@ -572,6 +576,7 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+ tty_register_devfs(&acm_tty_driver, 0, minor);
return acm_table[minor] = acm;
}
@@ -599,6 +604,7 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
usb_driver_release_interface(&acm_driver, acm->iface + 1);
if (!acm->used) {
+ tty_unregister_devfs(&acm_tty_driver, acm->minor);
acm_table[acm->minor] = NULL;
kfree(acm);
return;
@@ -630,14 +636,14 @@ static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
static struct tty_driver acm_tty_driver = {
magic: TTY_DRIVER_MAGIC,
- driver_name: "usb",
- name: "ttyACM",
+ driver_name: "acm",
+ name: "usb/acm/%d",
major: ACM_TTY_MAJOR,
minor_start: 0,
num: ACM_TTY_MINORS,
type: TTY_DRIVER_TYPE_SERIAL,
subtype: SERIAL_TYPE_NORMAL,
- flags: TTY_DRIVER_REAL_RAW,
+ flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
refcount: &acm_tty_refcount,
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index ad2f666d5..6772889b0 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -1395,25 +1395,30 @@ static int usbout_start(struct usb_audiodev *as)
/* --------------------------------------------------------------------- */
-static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt)
+static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int rate)
{
unsigned int i;
- /* first find an exact match */
- for (i = 0; i < nr; i++)
- if (afp[i].format == fmt)
+ /* first find an exact match, taking both format and sample rate into account,
+ but ignore stereo bit */
+ for (i = 0; i < nr; i++) {
+ if (afp[i].format == (fmt & ~AFMT_STEREO) && rate >= afp[i].sratelo && rate <= afp[i].sratehi)
return i;
+ }
+
/* second find a match with the same stereo/mono and 8bit/16bit property */
for (i = 0; i < nr; i++)
if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
- !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt))
+ !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt) &&
+ rate >= afp[i].sratelo && rate <= afp[i].sratehi)
return i;
/* third find a match with the same number of channels */
for (i = 0; i < nr; i++)
- if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt))
+ if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
+ rate >= afp[i].sratelo && rate <= afp[i].sratehi)
return i;
- /* return anything */
- return 0;
+ /* return failure */
+ return -1;
}
static int set_format_in(struct usb_audiodev *as)
@@ -1432,7 +1437,13 @@ static int set_format_in(struct usb_audiodev *as)
if (u->interface < 0 || u->interface >= config->bNumInterfaces)
return 0;
iface = &config->interface[u->interface];
- fmtnr = find_format(as->fmtin, as->numfmtin, d->format);
+
+ fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
+ if (fmtnr < 0) {
+ printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
+ return -1;
+ }
+
fmt = as->fmtin + fmtnr;
alts = &iface->altsetting[fmt->altsetting];
u->format = fmt->format;
@@ -1513,7 +1524,13 @@ static int set_format_out(struct usb_audiodev *as)
if (u->interface < 0 || u->interface >= config->bNumInterfaces)
return 0;
iface = &config->interface[u->interface];
- fmtnr = find_format(as->fmtout, as->numfmtout, d->format);
+
+ fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
+ if (fmtnr < 0) {
+ printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
+ return -1;
+ }
+
fmt = as->fmtout + fmtnr;
u->format = fmt->format;
alts = &iface->altsetting[fmt->altsetting];
@@ -3330,7 +3347,7 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
struct usb_interface *iface;
unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
unsigned char *p1;
- unsigned int i, j, numifin = 0, numifout = 0;
+ unsigned int i, j, k, numifin = 0, numifout = 0;
if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
return NULL;
@@ -3377,12 +3394,25 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
dev->devnum, ctrlif, j);
continue;
}
- if (iface->num_altsetting < 2 ||
- iface->altsetting[0].bNumEndpoints > 0) {
- printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u altsetting 0 not zero bandwidth\n",
- dev->devnum, ctrlif);
+ if (iface->num_altsetting == 0) {
+ printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has no working interface.\n", dev->devnum, ctrlif);
+ continue;
+ }
+ if (iface->num_altsetting == 1) {
+ printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
continue;
}
+ if (iface->altsetting[0].bNumEndpoints > 0) {
+ /* Check all endpoints; should they all have a bandwidth of 0 ? */
+ for (k = 0; k < iface->altsetting[0].bNumEndpoints; k++) {
+ if (iface->altsetting[0].endpoint[k].wMaxPacketSize > 0) {
+ printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
+ break;
+ }
+ }
+ if (k < iface->altsetting[0].bNumEndpoints)
+ continue;
+ }
if (iface->altsetting[1].bNumEndpoints < 1) {
printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
dev->devnum, ctrlif, j);
@@ -3418,7 +3448,7 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
}
- ret:
+ret:
if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
kfree(s);
return NULL;
diff --git a/drivers/usb/audio.h b/drivers/usb/audio.h
index a0ecb51ee..bb51e468b 100644
--- a/drivers/usb/audio.h
+++ b/drivers/usb/audio.h
@@ -30,7 +30,7 @@
#define MAX_FREQ 16
#define MAX_IFACE 8
#define MAX_FORMAT 8
-#define MAX_ALT 8
+#define MAX_ALT 32 /* Sorry, we need quite a few for the Philips webcams */
struct usb_audio_terminal
{
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
deleted file mode 100644
index 510e8297f..000000000
--- a/drivers/usb/cpia.c
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
- * USB CPiA Video Camera driver
- *
- * Supports CPiA based Video Cameras. Many manufacturers use this chipset.
- *
- * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
- * (C) Copyright 1999 Randy Dunlap
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <asm/io.h>
-
-#include "cpia.h"
-
-static int debug = 0;
-MODULE_PARM(debug, "i");
-
-/* Video Size 384 x 288 x 3 bytes for RGB */
-/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */
-#define MAX_FRAME_SIZE (384 * 288 * 3)
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x) do { } while(0) /* Debug memory management */
-
-static struct usb_driver cpia_driver;
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
- unsigned long ret = 0UL;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- if (!pgd_none(*pgd)) {
- pmd = pmd_offset(pgd, adr);
- if (!pmd_none(*pmd)) {
- ptep = pte_offset(pmd, adr);
- pte = *ptep;
- if (pte_present(pte))
- ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
- }
- }
- MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
- unsigned long kva, ret;
-
- kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
- ret = virt_to_bus((void *)kva);
- MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
- unsigned long va, kva, ret;
-
- va = VMALLOC_VMADDR(adr);
- kva = uvirt_to_kva(pgd_offset_k(va), va);
- ret = virt_to_bus((void *)kva);
- MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long va, kva, ret;
-
- va = VMALLOC_VMADDR(adr);
- kva = uvirt_to_kva(pgd_offset_k(va), va);
- ret = __pa(kva);
- MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr, page;
-
- /* Round it off to PAGE_SIZE */
- size += (PAGE_SIZE - 1);
- size &= ~(PAGE_SIZE - 1);
-
- mem = vmalloc(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- page = kvirt_to_pa(adr);
- mem_map_reserve(MAP_NR(__va(page)));
- adr += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr, page;
-
- if (!mem)
- return;
-
- size += (PAGE_SIZE - 1);
- size &= ~(PAGE_SIZE - 1);
-
- adr=(unsigned long) mem;
- while (size > 0) {
- page = kvirt_to_pa(adr);
- mem_map_unreserve(MAP_NR(__va(page)));
- adr += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
- vfree(mem);
-}
-
-static int usb_cpia_get_version(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_VERSION,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 4, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_PNP_ID,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 6, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_CAMERA_STATUS,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 8, HZ);
-}
-#endif
-
-static int usb_cpia_goto_hi_power(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_GOTO_HI_POWER, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_CPIA_GET_VP_VERSION,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 4, HZ);
-}
-
-static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_SENSOR_FPS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (sensorbaserate << 8) + sensorclkdivisor, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_GRAB_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- streamstartline << 8, 0, NULL, 0, HZ);
-}
-#endif
-
-static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_UPLOAD_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- forceupload, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_GRAB_MODE,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, continuousgrab,
- 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_FORMAT,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (subsample << 8) + size, order, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_ROI,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (colend << 8) + colstart, (rowend << 8) + rowstart,
- NULL, 0, HZ);
-}
-
-static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_COMPRESSION,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (decimation << 8) + compmode, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_set_compression_target(struct usb_device *dev, int target, int targetfr, int targetq)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_SET_COMPRESSION_TARGET,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (targetfr << 8) + target, targetq, NULL, 0, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_INIT_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (streamstartline << 8) + skipframes, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_finistreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_FINI_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_startstreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_START_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_endstreamcap(struct usb_device *dev)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CPIA_END_STREAM_CAP,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-#endif
-
-/* How much data is left in the scratch buf? */
-#define scratch_left(x) (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))
-
-static void cpia_parse_data(struct usb_cpia *cpia)
-{
- struct cpia_frame *frame, *pframe;
- unsigned char *data = cpia->scratch;
- unsigned long left;
- long copylen = 0;
-
- /* Grab the current frame and the previous frame */
- frame = &cpia->frame[cpia->curframe];
- pframe = &cpia->frame[(cpia->curframe - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES];
-
- while (1) {
- if (!scratch_left(data))
- goto out;
-
- switch (frame->scanstate) {
- case STATE_SCANNING:
- {
- struct cpia_frame_header *header;
-
- /* We need at least 2 bytes for the magic value */
- if (scratch_left(data) < 2)
- goto out;
-
- header = (struct cpia_frame_header *)data;
-
- if (be16_to_cpup(&header->magic) == CPIA_MAGIC) {
- frame->scanstate = STATE_HEADER;
- break;
- }
-
- /* Woops, lost the header, find the end of the frame */
- if (scratch_left(data) < 4)
- goto out;
-
- /* See if we found the end of the frame */
- while (scratch_left(data) >= 4) {
- if (*((__u32 *)data) == 0xFFFFFFFF) {
- data += 4;
- if (debug >= 1)
- printk(KERN_INFO "cpia: EOF while scanning for magic\n");
- goto error;
- }
- data++;
- }
- break;
- }
- case STATE_HEADER:
- /* We need at least 64 bytes for the header */
- if (scratch_left(data) <
- sizeof(struct cpia_frame_header))
- goto out;
-
- memcpy(&frame->header, data,
- sizeof(struct cpia_frame_header));
-
- /* Skip over the header */
- data += sizeof(struct cpia_frame_header);
-
- frame->hdrwidth = (frame->header.col_end -
- frame->header.col_start) * 8;
- frame->hdrheight = (frame->header.row_end -
- frame->header.row_start) * 4;
- if (debug >= 2) {
- printk(KERN_DEBUG "cpia: frame size %dx%d\n",
- frame->hdrwidth, frame->hdrheight);
- printk(KERN_DEBUG "cpia: frame %scompressed\n",
- frame->header.comp_enable ? "" : "not ");
- }
-
- frame->scanstate = STATE_LINES;
- frame->curline = 0;
- break;
-
- case STATE_LINES:
- {
- unsigned char *f, *end;
- unsigned int len;
- int i;
- int y, u, y1, v, r, g, b;
-
- /* We want at least 2 bytes for the length */
- if (scratch_left(data) < 2)
- goto out;
-
- /* Grab the length */
- len = data[0] + (data[1] << 8);
-
- /* Check to make sure it's nothing outrageous */
- if (len > (frame->hdrwidth * 2) + 1) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: bad length, resynching (expected %d, got %d)\n", (frame->hdrwidth * 2) + 1, len);
- goto error;
- }
-
- /* Make sure there's enough data for the entire line */
- if (scratch_left(data + 2) < len)
- goto out;
-
- /* Skip over the length */
- data += 2;
-
- /* Is the end of the line there */
- if (data[len - 1] != 0xFD) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: lost synch\n");
- goto error;
- }
-
- /* Start at the beginning */
- end = data + len - 1;
-
- f = frame->data + (frame->width * 3 * frame->curline);
-
- if (frame->header.comp_enable) {
- unsigned char *fp;
-
- /* We use the previous frame as a reference */
- fp = pframe->data +
- (frame->width * 3 * frame->curline);
-
- while (data < end) {
- if (*data & 1) {
- /* Compress RLE data */
- i = *data >> 1;
- memcpy(f, fp, i * 3);
- copylen += (i * 3);
- f += (i * 3);
- fp += (i * 3);
- data++;
- } else {
- /* Raw data */
-
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
-y = *data++ - 16;
-u = *data++ - 128;
-y1 = *data++ - 16;
-v = *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
- fp += 6;
- copylen += 6;
- }
- }
- } else {
- /* Raw data */
- while (data < end) {
-y = *data++ - 16;
-u = *data++ - 128;
-y1 = *data++ - 16;
-v = *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
-copylen += 6;
- }
- }
-
- /* Skip the last byte */
- data++;
-
- if (++frame->curline >= frame->hdrheight)
- goto nextframe;
-
- break;
- } /* end case STATE_LINES */
- } /* end switch (scanstate) */
- } /* end while (1) */
-
-nextframe:
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: marking as success\n");
-
- if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF)
- data += 4;
-
- frame->grabstate = FRAME_DONE;
-
- goto wakeup;
-
-error:
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: marking as error\n");
-
- frame->grabstate = FRAME_ERROR;
-
- /* Get a fresh frame since this frame may have been important */
- cpia->compress = 0;
-
- copylen = 0;
-
-wakeup:
- cpia->curframe = -1;
-
- /* This will cause the process to request another frame. */
- if (waitqueue_active(&frame->wq))
- wake_up_interruptible(&frame->wq);
-
-out:
- /* Grab the remaining */
- left = scratch_left(data);
- memmove(cpia->scratch, data, left);
- cpia->scratchlen = left;
-
- /* Update the frame's uncompressed length. */
- frame->scanlength += copylen;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int cpia_compress_isochronous(struct usb_cpia *cpia, urb_t *urb)
-{
- unsigned char *cdata, *data;
- int i, totlen = 0;
-
- data = cpia->scratch + cpia->scratchlen;
- for (i = 0; i < urb->number_of_packets; i++) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
-
- cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (st && debug >= 1)
- printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
- i, n, st);
-
- if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
- printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n",cpia->scratchlen, n );
- return totlen;
- }
-
- if (n) {
- memmove(data, cdata, n);
- data += n;
- totlen += n;
- cpia->scratchlen += n;
- }
- }
-
- return totlen;
-}
-
-static void cpia_isoc_irq(struct urb *urb)
-{
- int len;
- struct usb_cpia *cpia = urb->context;
- struct cpia_sbuf *sbuf;
- int i;
-
- if (!cpia->dev)
- return;
-
- if (!cpia->streaming) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: oops, not streaming, but interrupt\n");
- return;
- }
-
- sbuf = &cpia->sbuf[cpia->cursbuf];
-
- /* Copy the data received into our scratch buffer */
- len = cpia_compress_isochronous(cpia, urb);
-
- /* If we don't have a frame we're current working on, complain */
- if (cpia->scratchlen) {
- if (cpia->curframe < 0) {
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: received data, but no frame available\n");
- } else
- cpia_parse_data(cpia);
- }
-
- for (i = 0; i < FRAMES_PER_DESC; i++) {
- sbuf->urb->iso_frame_desc[i].status = 0;
- sbuf->urb->iso_frame_desc[i].actual_length = 0;
- }
-
- /* Move to the next sbuf */
- cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
-
- return;
-}
-
-static int cpia_init_isoc(struct usb_cpia *cpia)
-{
- urb_t *urb;
- int fx, err;
-
- cpia->compress = 0;
- cpia->curframe = -1;
- cpia->cursbuf = 0;
- cpia->scratchlen = 0;
-
- /* Alternate interface 3 is is the biggest frame size */
- if (usb_set_interface(cpia->dev, cpia->iface, 3) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return -EBUSY;
- }
-
- /* We double buffer the Iso lists */
- urb = usb_alloc_urb(FRAMES_PER_DESC);
-
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
- 0);
- return -ENOMEM;
- }
- cpia->sbuf[0].urb = urb;
- urb->dev = cpia->dev;
- urb->context = cpia;
- urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
- urb->transfer_flags = USB_ISO_ASAP;
- urb->transfer_buffer = cpia->sbuf[0].data;
- urb->complete = cpia_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
- urb = usb_alloc_urb(FRAMES_PER_DESC);
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
- 0);
- return -ENOMEM;
- }
- cpia->sbuf[1].urb = urb;
- urb->dev = cpia->dev;
- urb->context = cpia;
- urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
- urb->transfer_flags = USB_ISO_ASAP;
- urb->transfer_buffer = cpia->sbuf[1].data;
- urb->complete = cpia_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
-
- cpia->sbuf[1].urb->next = cpia->sbuf[0].urb;
- cpia->sbuf[0].urb->next = cpia->sbuf[1].urb;
-
- err = usb_submit_urb(cpia->sbuf[0].urb);
- if (err)
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(0) ret %d\n",
- err);
- err = usb_submit_urb(cpia->sbuf[1].urb);
- if (err)
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(1) ret %d\n",
- err);
-
- cpia->streaming = 1;
-
- return 0;
-}
-
-static void cpia_stop_isoc(struct usb_cpia *cpia)
-{
- if (!cpia->streaming || !cpia->dev)
- return;
-
- /* Turn off continuous grab */
- if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
- printk(KERN_ERR "cpia_set_grab_mode error\n");
- return /* -EBUSY */;
- }
-
- /* Set packet size to 0 */
- if (usb_set_interface(cpia->dev, cpia->iface, 0) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return /* -EINVAL */;
- }
-
- cpia->streaming = 0;
-
- /* Unschedule all of the iso td's */
- if (cpia->sbuf[1].urb) {
- cpia->sbuf[1].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[1].urb);
- usb_free_urb(cpia->sbuf[1].urb);
- cpia->sbuf[1].urb = NULL;
- }
- if (cpia->sbuf[0].urb) {
- cpia->sbuf[0].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[0].urb);
- usb_free_urb(cpia->sbuf[0].urb);
- cpia->sbuf[0].urb = NULL;
- }
-}
-
-static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
-{
- struct cpia_frame *frame;
- int width, height;
-
- if (!cpia->dev)
- return -1;
-
- /* If we're not grabbing a frame right now and the other frame is */
- /* ready to be grabbed into, then use it instead */
- if (cpia->curframe == -1) {
- if (cpia->frame[(framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES].grabstate == FRAME_READY)
- framenum = (framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES;
- } else
- return 0;
-
- frame = &cpia->frame[framenum];
- width = frame->width;
- height = frame->height;
-
- frame->grabstate = FRAME_GRABBING;
- frame->scanstate = STATE_SCANNING;
- frame->scanlength = 0; /* accumulated in cpia_parse_data() */
-
- cpia->curframe = framenum;
-
- /* Make sure it's not too big */
- if (width > 352)
- width = 352;
- width = (width / 8) * 8; /* Multiple of 8 */
-
- if (height > 288)
- height = 288;
- height = (height / 4) * 4; /* Multiple of 4 */
-
- /* Set the ROI they want */
- if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
- return -EBUSY;
-
- if (usb_cpia_set_compression(cpia->dev, cpia->compress ?
- COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) {
- printk(KERN_ERR "cpia_set_compression error\n");
- return -EBUSY;
- }
-
- /* We want a fresh frame every 30 we get */
- cpia->compress = (cpia->compress + 1) % 30;
-
- /* Grab the frame */
- if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) {
- printk(KERN_ERR "cpia_upload_frame error\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-/* Video 4 Linux API */
-static int cpia_open(struct video_device *dev, int flags)
-{
- int err = -EBUSY;
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- down(&cpia->lock);
- if (cpia->user)
- goto out_unlock;
-
- cpia->frame[0].grabstate = FRAME_UNUSED;
- cpia->frame[1].grabstate = FRAME_UNUSED;
-
- err = -ENOMEM;
-
- /* Allocate memory for the frame buffers */
- cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
- if (!cpia->fbuf)
- goto open_err_ret;
-
- cpia->frame[0].data = cpia->fbuf;
- cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
-
- cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!cpia->sbuf[0].data)
- goto open_err_on0;
-
- cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!cpia->sbuf[1].data)
- goto open_err_on1;
-
- /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
- * (using read() instead). */
- cpia->frame[0].width = 352;
- cpia->frame[0].height = 288;
- cpia->frame[0].bytes_read = 0;
- cpia->frame[1].width = 352;
- cpia->frame[1].height = 288;
- cpia->frame[1].bytes_read = 0;
-
- err = cpia_init_isoc(cpia);
- if (err)
- goto open_err_on2;
-
- cpia->user++;
- up(&cpia->lock);
-
- MOD_INC_USE_COUNT;
-
- return 0;
-
-open_err_on2:
- kfree (cpia->sbuf[1].data);
-open_err_on1:
- kfree (cpia->sbuf[0].data);
-open_err_on0:
- rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-open_err_ret:
- return err;
-
-out_unlock:
- up(&cpia->lock);
- return err;
-}
-
-static void cpia_close(struct video_device *dev)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- down(&cpia->lock);
- cpia->user--;
-
- MOD_DEC_USE_COUNT;
-
- cpia_stop_isoc(cpia);
-
- rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-
- kfree(cpia->sbuf[1].data);
- kfree(cpia->sbuf[0].data);
-
- up(&cpia->lock);
-
- if (!cpia->dev) {
- video_unregister_device(&cpia->vdev);
- kfree(cpia);
- }
-}
-
-static int cpia_init_done(struct video_device *dev)
-{
- return 0;
-}
-
-static long cpia_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
-{
- return -EINVAL;
-}
-
-static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
- if (!cpia->dev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability b;
-
- strcpy(b.name, "CPiA USB Camera");
- b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- b.channels = 1;
- b.audios = 0;
- b.maxwidth = 352; /* CIF */
- b.maxheight = 288; /* " */
- b.minwidth = 8;
- b.minheight = 4;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel v;
-
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- if (v.channel != 0)
- return -EINVAL;
-
- v.flags = 0;
- v.tuners = 0;
- v.type = VIDEO_TYPE_CAMERA;
- strcpy(v.name, "Camera");
-
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSCHAN:
- {
- int v;
-
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
-
- if (v != 0)
- return -EINVAL;
-
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture p;
-
- p.colour = 0x8000; /* Damn British people :) */
- p.hue = 0x8000;
- p.brightness = 180 << 8; /* XXX */
- p.contrast = 192 << 8; /* XXX */
- p.whiteness = 105 << 8; /* XXX */
- p.depth = 24;
- p.palette = VIDEO_PALETTE_RGB24;
-
- if (copy_to_user(arg, &p, sizeof(p)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture p;
-
- if (copy_from_user(&p, arg, sizeof(p)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window vw;
-
- if (copy_from_user(&vw, arg, sizeof(vw)))
- return -EFAULT;
- if (vw.flags)
- return -EINVAL;
- if (vw.clipcount)
- return -EINVAL;
- if (vw.height != 288)
- return -EINVAL;
- if (vw.width != 352)
- return -EINVAL;
-
- cpia->compress = 0;
-
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window vw;
-
- vw.x = 0;
- vw.y = 0;
- vw.width = 352;
- vw.height = 288;
- vw.chromakey = 0;
- vw.flags = 30; /* 30 fps */
-
- if (copy_to_user(arg, &vw, sizeof(vw)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf vm;
-
- memset(&vm, 0, sizeof(vm));
- vm.size = MAX_FRAME_SIZE * 2;
- vm.frames = 2;
- vm.offsets[0] = 0;
- vm.offsets[1] = MAX_FRAME_SIZE;
-
- if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap vm;
-
- if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
- return -EFAULT;
-
- if (debug >= 1)
- printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n",
- vm.frame, vm.width, vm.height, vm.format);
-
- if (vm.format != VIDEO_PALETTE_RGB24)
- return -EINVAL;
-
- if ((vm.frame != 0) && (vm.frame != 1))
- return -EINVAL;
-
- if (cpia->frame[vm.frame].grabstate == FRAME_GRABBING)
- return -EBUSY;
-
- /* Don't compress if the size changed */
- if ((cpia->frame[vm.frame].width != vm.width) ||
- (cpia->frame[vm.frame].height != vm.height))
- cpia->compress = 0;
-
- cpia->frame[vm.frame].width = vm.width;
- cpia->frame[vm.frame].height = vm.height;
-
- /* Mark it as ready */
- cpia->frame[vm.frame].grabstate = FRAME_READY;
-
- return cpia_new_frame(cpia, vm.frame);
- }
- case VIDIOCSYNC:
- {
- int frame;
-
- if (copy_from_user((void *)&frame, arg, sizeof(int)))
- return -EFAULT;
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: syncing to frame %d\n", frame);
-
- switch (cpia->frame[frame].grabstate) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- case FRAME_ERROR:
-redo:
- if (!cpia->dev)
- return -EIO;
-
- do {
- interruptible_sleep_on(&cpia->frame[frame].wq);
- if (signal_pending(current))
- return -EINTR;
- } while (cpia->frame[frame].grabstate == FRAME_GRABBING);
-
- if (cpia->frame[frame].grabstate == FRAME_ERROR) {
- int ret;
-
- if ((ret = cpia_new_frame(cpia, frame)) < 0)
- return ret;
- goto redo;
- }
- case FRAME_DONE:
- cpia->frame[frame].grabstate = FRAME_UNUSED;
- break;
- }
-
- cpia->frame[frame].grabstate = FRAME_UNUSED;
-
- return 0;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer vb;
-
- memset(&vb, 0, sizeof(vb));
- vb.base = NULL; /* frame buffer not supported, not used */
-
- if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- return -EINVAL;
- case VIDIOCSFBUF:
- return -EINVAL;
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- return -EINVAL;
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- return -EINVAL;
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
- int frmx = -1;
- volatile struct cpia_frame *frame;
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: %ld bytes, noblock=%d\n", count, noblock);
-
- if (!dev || !buf)
- return -EFAULT;
-
- if (!cpia->dev)
- return -EIO;
-
- /* See if a frame is completed, then use it. */
- if (cpia->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */
- frmx = 0;
- else if (cpia->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
- frmx = 1;
-
- if (noblock && (frmx == -1))
- return -EAGAIN;
-
- /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
- /* See if a frame is in process (grabbing), then use it. */
- if (frmx == -1) {
- if (cpia->frame[0].grabstate == FRAME_GRABBING)
- frmx = 0;
- else if (cpia->frame[1].grabstate == FRAME_GRABBING)
- frmx = 1;
- }
-
- /* If no frame is active, start one. */
- if (frmx == -1)
- cpia_new_frame(cpia, frmx = 0);
-
- frame = &cpia->frame[frmx];
-
-restart:
- if (!cpia->dev)
- return -EIO;
-
- while (frame->grabstate == FRAME_GRABBING) {
- interruptible_sleep_on(&frame->wq);
- if (signal_pending(current))
- return -EINTR;
- }
-
- if (frame->grabstate == FRAME_ERROR) {
- frame->bytes_read = 0;
-printk("cpia_read: errored frame %d\n", cpia->curframe);
- if (cpia_new_frame(cpia, frmx))
- printk(KERN_ERR "cpia_read: cpia_new_frame error\n");
- goto restart;
- }
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n",
- frmx, frame->bytes_read, frame->scanlength);
-
- /* copy bytes to user space; we allow for partials reads */
- if ((count + frame->bytes_read) > frame->scanlength)
- count = frame->scanlength - frame->bytes_read;
-
- if (copy_to_user(buf, frame->data + frame->bytes_read, count))
- return -EFAULT;
-
- frame->bytes_read += count;
- if (debug >= 1)
- printk(KERN_DEBUG "cpia_read: {copy} count used=%ld, new bytes_read=%ld\n",
- count, frame->bytes_read);
-
- if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
- frame->bytes_read = 0;
-
- /* Mark it as available to be used again. */
- cpia->frame[frmx].grabstate = FRAME_UNUSED;
- if (cpia_new_frame(cpia, frmx ? 0 : 1))
- printk(KERN_ERR "cpia_read: cpia_new_frame returned error\n");
- }
-
- return count;
-}
-
-static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size)
-{
- struct usb_cpia *cpia = (struct usb_cpia *)dev;
- unsigned long start = (unsigned long)adr;
- unsigned long page, pos;
-
- if (!cpia->dev)
- return -EIO;
-
- if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
- return -EINVAL;
-
- pos = (unsigned long)cpia->fbuf;
- while (size > 0) {
- page = kvirt_to_pa(pos);
- if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
-
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return 0;
-}
-
-static struct video_device cpia_template = {
- "CPiA USB Camera",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_CPIA,
- cpia_open,
- cpia_close,
- cpia_read,
- cpia_write,
- NULL,
- cpia_ioctl,
- cpia_mmap,
- cpia_init_done,
- NULL,
- 0,
- 0
-};
-
-static int usb_cpia_configure(struct usb_cpia *cpia)
-{
- struct usb_device *dev = cpia->dev;
- unsigned char version[4];
-
- /* Set altsetting 0 */
- if (usb_set_interface(dev, cpia->iface, 0) < 0) {
- printk(KERN_ERR "usb_set_interface error\n");
- return -EBUSY;
- }
-
- if (usb_cpia_get_version(dev, version) < 0) {
- printk(KERN_ERR "cpia_get_version error\n");
- return -EBUSY;
- }
-
- if (debug >= 1)
- printk(KERN_DEBUG "cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
- version[0], version[1], version[2], version[3]);
-
- memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template));
-
- init_waitqueue_head(&cpia->frame[0].wq);
- init_waitqueue_head(&cpia->frame[1].wq);
-
- if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) {
- printk(KERN_ERR "video_register_device failed\n");
- return -EBUSY;
- }
-
- if (usb_cpia_goto_hi_power(dev) < 0) {
- printk(KERN_ERR "cpia_goto_hi_power error\n");
- goto error;
- }
-
- if (usb_cpia_get_vp_version(dev, version) < 0) {
- printk(KERN_ERR "cpia_get_vp_version error\n");
- goto error;
- }
-
- if (debug >= 1) {
- printk(KERN_DEBUG "cpia: VP v%d rev %d\n", version[0], version[1]);
- printk(KERN_DEBUG "cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
- }
-
- /* Turn on continuous grab */
- if (usb_cpia_set_grab_mode(dev, 1) < 0) {
- printk(KERN_ERR "cpia_set_grab_mode error\n");
- goto error;
- }
-
- /* Set up the sensor to be 30fps */
- if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
- printk(KERN_ERR "cpia_set_sensor_fps error\n");
- goto error;
- }
-
- /* Set video into CIF mode, and order into YUYV mode */
- if (usb_cpia_set_format(dev, FORMAT_CIF, FORMAT_422,
- FORMAT_YUYV) < 0) {
- printk(KERN_ERR "cpia_set_format error\n");
- goto error;
- }
-
- /* Turn off compression */
- if (usb_cpia_set_compression(dev, COMP_DISABLED, DONT_DECIMATE) < 0) {
- printk(KERN_ERR "cpia_set_compression error\n");
- goto error;
- }
-
- cpia->compress = 0;
-
- return 0;
-
-error:
- video_unregister_device(&cpia->vdev);
- usb_driver_release_interface(&cpia_driver,
- &dev->actconfig->interface[0]);
-
- kfree(cpia);
-
- return -EBUSY;
-}
-
-static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_interface_descriptor *interface;
- struct usb_cpia *cpia;
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return NULL;
-
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
-
- /* Is it a CPiA? */
- if (dev->descriptor.idVendor != 0x0553)
- return NULL;
- if (dev->descriptor.idProduct != 0x0002)
- return NULL;
-
- /* Checking vendor/product should be enough, but what the hell */
- if (interface->bInterfaceClass != 0xFF)
- return NULL;
- if (interface->bInterfaceSubClass != 0x00)
- return NULL;
-
- /* We found a CPiA */
- printk(KERN_INFO "USB CPiA camera found\n");
-
- if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "couldn't kmalloc cpia struct\n");
- return NULL;
- }
-
- memset(cpia, 0, sizeof(*cpia));
-
- cpia->dev = dev;
- cpia->iface = interface->bInterfaceNumber;
-
- if (!usb_cpia_configure(cpia)) {
- cpia->user=0;
- init_MUTEX(&cpia->lock); /* to 1 == available */
-
- return cpia;
- } else
- return NULL;
-}
-
-static void cpia_disconnect(struct usb_device *dev, void *ptr)
-{
- struct usb_cpia *cpia = (struct usb_cpia *) ptr;
-
- /* We don't want people trying to open up the device */
- if (!cpia->user)
- video_unregister_device(&cpia->vdev);
-
- usb_driver_release_interface(&cpia_driver,
- &cpia->dev->actconfig->interface[0]);
-
- cpia->dev = NULL;
- cpia->frame[0].grabstate = FRAME_ERROR;
- cpia->frame[1].grabstate = FRAME_ERROR;
- cpia->curframe = -1;
-
- /* This will cause the process to request another frame. */
- if (waitqueue_active(&cpia->frame[0].wq))
- wake_up_interruptible(&cpia->frame[0].wq);
-
- if (waitqueue_active(&cpia->frame[1].wq))
- wake_up_interruptible(&cpia->frame[1].wq);
-
- cpia->streaming = 0;
-
- /* Unschedule all of the iso td's */
- if (cpia->sbuf[1].urb) {
- cpia->sbuf[1].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[1].urb);
- usb_free_urb(cpia->sbuf[1].urb);
- cpia->sbuf[1].urb = NULL;
- }
- if (cpia->sbuf[0].urb) {
- cpia->sbuf[0].urb->next = NULL;
- usb_unlink_urb(cpia->sbuf[0].urb);
- usb_free_urb(cpia->sbuf[0].urb);
- cpia->sbuf[0].urb = NULL;
- }
-
- /* Free the memory */
- if (!cpia->user)
- kfree(cpia);
-}
-
-static struct usb_driver cpia_driver = {
- "cpia",
- cpia_probe,
- cpia_disconnect,
- { NULL, NULL }
-};
-
-int usb_cpia_init(void)
-{
- return usb_register(&cpia_driver);
-}
-
-void usb_cpia_cleanup(void)
-{
- usb_deregister(&cpia_driver);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- return usb_cpia_init();
-}
-
-void cleanup_module(void)
-{
- usb_cpia_cleanup();
-}
-#endif
diff --git a/drivers/usb/cpia.h b/drivers/usb/cpia.h
deleted file mode 100644
index 8a8342853..000000000
--- a/drivers/usb/cpia.h
+++ /dev/null
@@ -1,205 +0,0 @@
-#ifndef __LINUX_CPIA_H
-#define __LINUX_CPIA_H
-
-#include <linux/list.h>
-
-#define USB_REQ_CPIA_GET_VERSION 0x01
-#define USB_REQ_CPIA_GET_PNP_ID 0x02
-#define USB_REQ_CPIA_GET_CAMERA_STATUS 0x03
-#define USB_REQ_CPIA_GOTO_HI_POWER 0x04
-#define USB_REQ_CPIA_GOTO_LO_POWER 0x05
-/* No 0x06 */
-#define USB_REQ_CPIA_GOTO_SUSPEND 0x07
-#define USB_REQ_CPIA_GOTO_PASS_THROUGH 0x08
-/* No 0x09 */
-#define USB_REQ_CPIA_MODIFY_CAMERA_STATUS 0x0A
-
-#define USB_REQ_CPIA_READ_VC_REGS 0x21
-#define USB_REQ_CPIA_WRITE_BC_REG 0x22
-#define USB_REQ_CPIA_READ_MC_PORTS 0x23
-#define USB_REQ_CPIA_WRITE_MC_PORT 0x24
-#define USB_REQ_CPIA_SET_BAUD_RATE 0x25
-#define USB_REQ_CPIA_SET_ECP_TIMING 0x26
-#define USB_REQ_CPIA_READ_IDATA 0x27
-#define USB_REQ_CPIA_WRITE_IDATA 0x28
-#define USB_REQ_CPIA_GENERIC_CALL 0x29
-#define USB_REQ_CPIA_I2CSTART 0x2A
-#define USB_REQ_CPIA_I2CSTOP 0x2B
-#define USB_REQ_CPIA_I2CWRITE 0x2C
-#define USB_REQ_CPIA_I2CREAD 0x2D
-
-#define USB_REQ_CPIA_GET_VP_VERSION 0xA1
-#define USB_REQ_CPIA_SET_COLOUR_PARAMS 0xA3
-#define USB_REQ_CPIA_SET_EXPOSURE 0xA4
-/* No 0xA5 */
-#define USB_REQ_CPIA_SET_COLOUR_BALANCE 0xA6
-#define USB_REQ_CPIA_SET_SENSOR_FPS 0xA7
-#define USB_REQ_CPIA_SET_VP_DEFAULTS 0xA8
-#define USB_REQ_CPIA_SET_APCOR 0xA9
-#define USB_REQ_CPIA_SET_FLICKER_CTRL 0xAA
-#define USB_REQ_CPIA_SET_VL_OFFSET 0xAB
-
-#define USB_REQ_CPIA_GET_COLOUR_PARAMETERS 0xB0
-#define USB_REQ_CPIA_GET_COLOUR_BALANCE 0xB1
-#define USB_REQ_CPIA_GET_EXPOSURE 0xB2
-#define USB_REQ_CPIA_SET_SENSOR_MATRIX 0xB3
-
-#define USB_REQ_CPIA_COLOUR_BARS 0xBD
-#define USB_REQ_CPIA_READ_VP_REGS 0xBE
-#define USB_REQ_CPIA_WRITE_VP_REGS 0xBF
-
-#define USB_REQ_CPIA_GRAB_FRAME 0xC1
-#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
-#define WAIT_FOR_NEXT_FRAME 0
-#define FORCE_FRAME_UPLOAD 1
-#define USB_REQ_CPIA_SET_GRAB_MODE 0xC3
-#define USB_REQ_CPIA_INIT_STREAM_CAP 0xC4
-#define USB_REQ_CPIA_FINI_STREAM_CAP 0xC5
-#define USB_REQ_CPIA_START_STREAM_CAP 0xC6
-#define USB_REQ_CPIA_END_STREAM_CAP 0xC7
-#define USB_REQ_CPIA_SET_FORMAT 0xC8
-#define FORMAT_QCIF 0
-#define FORMAT_CIF 1
-#define FORMAT_YUYV 0
-#define FORMAT_UYVY 1
-#define FORMAT_420 0
-#define FORMAT_422 1
-#define USB_REQ_CPIA_SET_ROI 0xC9
-#define USB_REQ_CPIA_SET_COMPRESSION 0xCA
-#define COMP_DISABLED 0
-#define COMP_AUTO 1
-#define COMP_MANUAL 2
-#define DONT_DECIMATE 0
-#define DECIMATE 1
-#define USB_REQ_CPIA_SET_COMPRESSION_TARGET 0xCB
-#define TARGET_QUALITY 0
-#define TARGET_FRAMERATE 1
-#define USB_REQ_CPIA_SET_YUV_THRESH 0xCC
-#define USB_REQ_CPIA_SET_COMPRESSION_PARAMS 0xCD
-#define USB_REQ_CPIA_DISCARD_FRAME 0xCE
-
-#define USB_REQ_CPIA_OUTPUT_RS232 0xE1
-#define USB_REQ_CPIA_ABORT_PROCESS 0xE4
-#define USB_REQ_CPIA_SET_DRAM_PAGE 0xE5
-#define USB_REQ_CPIA_START_DRAM_UPLOAD 0xE6
-#define USB_REQ_CPIA_START_DUMMY_STREAM 0xE8
-#define USB_REQ_CPIA_ABORT_STREAM 0xE9
-#define USB_REQ_CPIA_DOWNLOAD_DRAM 0xEA
-/* #define USB_REQ_CPIA_NULL_CMD 0x?? */
-
-#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
-/* #define STREAM_BUF_SIZE (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC) */
-
-#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
-
-#define FRAMES_PER_DESC 10
-#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
-
-enum {
- STATE_SCANNING, /* Scanning for start */
- STATE_HEADER, /* Parsing header */
- STATE_LINES, /* Parsing lines */
-};
-
-#define CPIA_MAGIC 0x1968
-struct cpia_frame_header {
- __u16 magic; /* 0 - 1 */
- __u16 timestamp; /* 2 - 3 */
- __u16 unused; /* 4 - 5 */
- __u16 timestamp1; /* 6 - 7 */
- __u8 unused1[8]; /* 8 - 15 */
- __u8 video_size; /* 16 0 = QCIF, 1 = CIF */
- __u8 sub_sample; /* 17 0 = 4:2:0, 1 = 4:2:2 */
- __u8 yuv_order; /* 18 0 = YUYV, 1 = UYVY */
- __u8 unused2[5]; /* 19 - 23 */
- __u8 col_start; /* 24 */
- __u8 col_end; /* 25 */
- __u8 row_start; /* 26 */
- __u8 row_end; /* 27 */
- __u8 comp_enable; /* 28 0 = non compressed, 1 = compressed */
- __u8 decimation; /* 29 0 = no decimation, 1 = decimation */
- __u8 y_thresh; /* 30 */
- __u8 uv_thresh; /* 31 */
- __u8 system_state; /* 32 */
- __u8 grab_state; /* 33 */
- __u8 stream_state; /* 34 */
- __u8 fatal_error; /* 35 */
- __u8 cmd_error; /* 36 */
- __u8 debug_flags; /* 37 */
- __u8 camera_state_7; /* 38 */
- __u8 camera_state_8; /* 39 */
- __u8 cr_achieved; /* 40 */
- __u8 fr_achieved; /* 41 */
- __u8 unused3[22]; /* 42 - 63 */
-};
-
-struct usb_device;
-
-struct cpia_sbuf {
- char *data;
- urb_t *urb;
-};
-
-enum {
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
- FRAME_READY, /* Ready to start grabbing */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_ERROR, /* Something bad happened while processing */
-};
-
-struct cpia_frame {
- char *data; /* Frame buffer */
-
- struct cpia_frame_header header; /* Header from stream */
-
- int width; /* Width application is expecting */
- int height; /* Height */
-
- int hdrwidth; /* Width the frame actually is */
- int hdrheight; /* Height */
-
- volatile int grabstate; /* State of grabbing */
- int scanstate; /* State of scanning */
-
- int curline; /* Line of frame we're working on */
-
- long scanlength; /* uncompressed, raw data length of frame */
- long bytes_read; /* amount of scanlength that has been read from *data */
-
- wait_queue_head_t wq; /* Processes waiting */
-};
-
-#define CPIA_NUMFRAMES 2
-#define CPIA_NUMSBUF 2
-
-struct usb_cpia {
- struct video_device vdev;
-
- /* Device structure */
- struct usb_device *dev;
-
- unsigned char iface;
-
- struct semaphore lock;
- int user; /* user count for exclusive use */
-
- int streaming; /* Are we streaming Isochronous? */
- int grabbing; /* Are we grabbing? */
-
- int compress; /* Should the next frame be compressed? */
-
- char *fbuf; /* Videodev buffer area */
-
- int curframe;
- struct cpia_frame frame[CPIA_NUMFRAMES]; /* Double buffering */
-
- int cursbuf; /* Current receiving sbuf */
- struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
-
- /* Scratch space from the Isochronous pipe */
- unsigned char scratch[SCRATCH_BUF_SIZE];
- int scratchlen;
-};
-
-#endif
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
index 099d90372..874887a63 100644
--- a/drivers/usb/devices.c
+++ b/drivers/usb/devices.c
@@ -54,10 +54,9 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
-
#define MAX_TOPO_LEVEL 6
/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index c28614d07..933895934 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -41,9 +41,9 @@
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
struct async {
struct list_head asynclist;
diff --git a/drivers/usb/drivers.c b/drivers/usb/drivers.c
index 0dcc9f719..11e16b784 100644
--- a/drivers/usb/drivers.c
+++ b/drivers/usb/drivers.c
@@ -37,11 +37,9 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
-
-
/*****************************************************************/
/*
diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c
index 9cca9fdf6..1d42f7df0 100644
--- a/drivers/usb/evdev.c
+++ b/drivers/usb/evdev.c
@@ -29,9 +29,9 @@
*/
#define EVDEV_MINOR_BASE 64
+#define EVDEV_MINORS 32
#define EVDEV_BUFFER_SIZE 64
-#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/malloc.h>
#include <linux/module.h>
@@ -39,11 +39,12 @@
#include <linux/input.h>
struct evdev {
- char name[32];
int used;
+ int open;
+ int minor;
struct input_handle handle;
- struct miscdevice misc;
wait_queue_head_t wait;
+ devfs_handle_t devfs;
struct evdev_list *list;
};
@@ -56,8 +57,7 @@ struct evdev_list {
struct evdev_list *next;
};
-static unsigned long evdev_miscbits = 0;
-static struct evdev *evdev_base[BITS_PER_LONG];
+static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ };
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
@@ -99,10 +99,13 @@ static int evdev_release(struct inode * inode, struct file * file)
while (*listptr && (*listptr != list))
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
+
+ if (!--list->evdev->open)
+ input_close_device(&list->evdev->handle);
if (!--list->evdev->used) {
- clear_bit(list->evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits);
- misc_deregister(&list->evdev->misc);
+ input_unregister_minor(list->evdev->devfs);
+ evdev_table[list->evdev->minor] = NULL;
kfree(list->evdev);
}
@@ -117,23 +120,28 @@ static int evdev_open(struct inode * inode, struct file * file)
struct evdev_list *list;
int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
- if (i > BITS_PER_LONG || !test_bit(i, &evdev_miscbits))
+ if (i > EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
- return -ENOMEM;
+ MOD_INC_USE_COUNT;
+ if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
memset(list, 0, sizeof(struct evdev_list));
- list->evdev = evdev_base[i];
- list->next = evdev_base[i]->list;
- evdev_base[i]->list = list;
+ list->evdev = evdev_table[i];
+ list->next = evdev_table[i]->list;
+ evdev_table[i]->list = list;
file->private_data = list;
list->evdev->used++;
- MOD_INC_USE_COUNT;
+ if (!list->evdev->open++)
+ input_open_device(&list->evdev->handle);
+
return 0;
}
@@ -193,34 +201,81 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
return 0;
}
+static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct evdev_list *list = file->private_data;
+ struct evdev *evdev = list->evdev;
+ struct input_dev *dev = evdev->handle.dev;
+
+ switch (cmd) {
+
+ case EVIOCGVERSION:
+ return put_user(EV_VERSION, (__u32 *) arg);
+ case EVIOCGID:
+ return copy_to_user(&dev->id, (void *) arg,
+ sizeof(struct input_id)) ? -EFAULT : 0;
+ default:
+
+ if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+ return -EINVAL;
+
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+ long *bits = NULL;
+ int len = 0;
+
+ switch (_IOC_NR(cmd) & EV_MAX) {
+ case 0: bits = dev->evbit; len = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+ default: return -EINVAL;
+ }
+ len = NBITS(len) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user((void *) arg, bits, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+ int len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
+ }
+ }
+ return -EINVAL;
+}
+
static struct file_operations evdev_fops = {
read: evdev_read,
write: evdev_write,
poll: evdev_poll,
open: evdev_open,
release: evdev_release,
+ ioctl: evdev_ioctl,
fasync: evdev_fasync,
};
-static int evdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct evdev *evdev;
+ int minor;
- if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
- return -1;
+ for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
+ if (evdev_table[minor]) {
+ printk(KERN_ERR "evdev: no more free evdev devices\n");
+ return NULL;
+ }
+ if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
+ return NULL;
memset(evdev, 0, sizeof(struct evdev));
init_waitqueue_head(&evdev->wait);
- evdev->misc.minor = ffz(evdev_miscbits);
- set_bit(evdev->misc.minor, &evdev_miscbits);
- evdev_base[evdev->misc.minor] = evdev;
-
- sprintf(evdev->name, "evdev%d", evdev->misc.minor);
- evdev->misc.name = evdev->name;
- evdev->misc.minor += EVDEV_MINOR_BASE;
- evdev->misc.fops = &evdev_fops;
+ evdev->minor = minor;
+ evdev_table[minor] = evdev;
evdev->handle.dev = dev;
evdev->handle.handler = handler;
@@ -228,24 +283,23 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev)
evdev->used = 1;
- misc_register(&evdev->misc);
- input_open_device(&evdev->handle);
+ evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
- printk("%s: Event device for input%d on misc%d - /dev/input%d\n",
- evdev->name, dev->number, evdev->misc.minor, evdev->misc.minor - EVDEV_MINOR_BASE);
+ printk("event%d: Event device for input%d\n", minor, dev->number);
- return 0;
+ return &evdev->handle;
}
static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
- input_close_device(handle);
+ if (evdev->open)
+ input_close_device(handle);
if (!--evdev->used) {
- clear_bit(evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits);
- misc_deregister(&evdev->misc);
+ input_unregister_minor(evdev->devfs);
+ evdev_table[evdev->minor] = NULL;
kfree(evdev);
}
}
@@ -254,6 +308,8 @@ static struct input_handler evdev_handler = {
event: evdev_event,
connect: evdev_connect,
disconnect: evdev_disconnect,
+ fops: &evdev_fops,
+ minor: EVDEV_MINOR_BASE,
};
static int __init evdev_init(void)
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index b8af56051..05372ef33 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -1288,7 +1288,7 @@ static void hid_init_input(struct hid_device *hid)
hid_configure_usage(hid, report->field[i], report->field[i]->usage + j);
if (k == HID_INPUT_REPORT) {
- usb_set_idle(hid->dev, hid->ifnum, report->id, 0);
+ usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
hid_read_report(hid, report);
}
}
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 8bd919d67..821dedb4a 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -6,12 +6,17 @@
* (C) Copyright 1999 Gregory P. Smith
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
#include <asm/uaccess.h>
@@ -609,5 +614,28 @@ void usb_hub_cleanup(void)
usb_deregister(&hub_driver);
} /* usb_hub_cleanup() */
+int usb_reset_device(struct usb_device *dev)
+{
+ struct usb_device *parent = dev->parent;
+ int i;
+
+ if (!parent) {
+ err("attempting to reset root hub!");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < parent->maxchild; i++) {
+ if (parent->children[i] == dev) {
+ usb_set_port_feature(parent, i + 1,
+ USB_PORT_FEAT_RESET);
+ usb_disconnect(&dev);
+ usb_hub_port_connect_change(parent, i);
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
index fe93e5bcc..2deab03fa 100644
--- a/drivers/usb/ibmcam.c
+++ b/drivers/usb/ibmcam.c
@@ -58,6 +58,8 @@ typedef enum {
#define FLAGS_DISPLAY_HINTS (1 << 2)
#define FLAGS_OVERLAY_STATS (1 << 3)
#define FLAGS_FORCE_TESTPATTERN (1 << 4)
+#define FLAGS_SEPARATE_FRAMES (1 << 5)
+#define FLAGS_CLEAN_FRAMES (1 << 6)
static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
@@ -2238,6 +2240,12 @@ static void ibmcam_stop_isoc(struct usb_ibmcam *ibmcam)
}
}
+/*
+ * ibmcam_new_frame()
+ *
+ * History:
+ * 29-Mar-00 Added copying of previous frame into the current one.
+ */
static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
{
struct ibmcam_frame *frame;
@@ -2258,10 +2266,33 @@ static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
frame->scanstate = STATE_SCANNING;
frame->scanlength = 0; /* Accumulated in ibmcam_parse_data() */
ibmcam->curframe = framenum;
-#if 0
- /* This provides a "clean" frame but slows things down */
- memset(frame->data, 0, MAX_FRAME_SIZE);
-#endif
+
+ /*
+ * Normally we would want to copy previous frame into the current one
+ * before we even start filling it with data; this allows us to stop
+ * filling at any moment; top portion of the frame will be new and
+ * bottom portion will stay as it was in previous frame. If we don't
+ * do that then missing chunks of video stream will result in flickering
+ * portions of old data whatever it was before.
+ *
+ * If we choose not to copy previous frame (to, for example, save few
+ * bus cycles - the frame can be pretty large!) then we have an option
+ * to clear the frame before using. If we experience losses in this
+ * mode then missing picture will be black (no flickering).
+ *
+ * Finally, if user chooses not to clean the current frame before
+ * filling it with data then the old data will be visible if we fail
+ * to refill entire frame with new data.
+ */
+ if (!(flags & FLAGS_SEPARATE_FRAMES)) {
+ /* This copies previous frame into this one to mask losses */
+ memmove(frame->data, ibmcam->frame[1-framenum].data, MAX_FRAME_SIZE);
+ } else {
+ if (flags & FLAGS_CLEAN_FRAMES) {
+ /* This provides a "clean" frame but slows things down */
+ memset(frame->data, 0, MAX_FRAME_SIZE);
+ }
+ }
switch (videosize) {
case VIDEOSIZE_128x96:
frame->frmwidth = 128;
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index c30f2eaff..50970155b 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -38,10 +38,9 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
-#include "usbdevice_fs.h"
-
/* --------------------------------------------------------------------- */
static LIST_HEAD(superlist);
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
index e370927b3..73f39db7c 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -35,20 +35,25 @@
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-#ifndef MODULE
EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device);
EXPORT_SYMBOL(input_register_handler);
EXPORT_SYMBOL(input_unregister_handler);
+EXPORT_SYMBOL(input_register_minor);
+EXPORT_SYMBOL(input_unregister_minor);
EXPORT_SYMBOL(input_open_device);
EXPORT_SYMBOL(input_close_device);
EXPORT_SYMBOL(input_event);
-#endif
+
+#define INPUT_MAJOR 13
+#define INPUT_DEVICES 256
static struct input_dev *input_dev = NULL;
static struct input_handler *input_handler = NULL;
-
+static struct input_handler *input_table[8] = { NULL, /* ... */ };
+static devfs_handle_t input_devfs_handle = NULL;
static int input_number = 0;
+static long input_devices[NBITS(INPUT_DEVICES)] = { 0, /* ... */ };
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -142,7 +147,8 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
*/
while (handle) {
- handle->handler->event(handle, type, code, value);
+ if (handle->open)
+ handle->handler->event(handle, type, code, value);
handle = handle->dnext;
}
}
@@ -154,9 +160,48 @@ static void input_repeat_key(unsigned long data)
mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]);
}
+int input_open_device(struct input_handle *handle)
+{
+ handle->open++;
+ if (handle->dev->open)
+ return handle->dev->open(handle->dev);
+ return 0;
+}
+
+void input_close_device(struct input_handle *handle)
+{
+ if (handle->dev->close)
+ handle->dev->close(handle->dev);
+ handle->open--;
+}
+
+static void input_link_handle(struct input_handle *handle)
+{
+ handle->dnext = handle->dev->handle;
+ handle->hnext = handle->handler->handle;
+ handle->dev->handle = handle;
+ handle->handler->handle = handle;
+}
+
+static void input_unlink_handle(struct input_handle *handle)
+{
+ struct input_handle **handleptr;
+
+ handleptr = &handle->dev->handle;
+ while (*handleptr && (*handleptr != handle))
+ handleptr = &((*handleptr)->dnext);
+ *handleptr = (*handleptr)->dnext;
+
+ handleptr = &handle->handler->handle;
+ while (*handleptr && (*handleptr != handle))
+ handleptr = &((*handleptr)->hnext);
+ *handleptr = (*handleptr)->hnext;
+}
+
void input_register_device(struct input_dev *dev)
{
struct input_handler *handler = input_handler;
+ struct input_handle *handle;
/*
* Initialize repeat timer to default values.
@@ -172,17 +217,25 @@ void input_register_device(struct input_dev *dev)
* Add the device.
*/
- MOD_INC_USE_COUNT;
- dev->number = input_number++;
+ if (input_number >= INPUT_DEVICES) {
+ printk(KERN_WARNING "input: ran out of input device numbers!\n");
+ dev->number = input_number;
+ } else {
+ dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
+ set_bit(dev->number, input_devices);
+ }
+
dev->next = input_dev;
input_dev = dev;
+ input_number++;
/*
* Notify handlers.
*/
while (handler) {
- handler->connect(handler, dev);
+ if ((handle = handler->connect(handler, dev)))
+ input_link_handle(handle);
handler = handler->next;
}
}
@@ -203,6 +256,7 @@ void input_unregister_device(struct input_dev *dev)
*/
while (handle) {
+ input_unlink_handle(handle);
handle->handler->disconnect(handle);
handle = handle->dnext;
}
@@ -216,12 +270,22 @@ void input_unregister_device(struct input_dev *dev)
*devptr = (*devptr)->next;
input_number--;
- MOD_DEC_USE_COUNT;
+
+ if (dev->number < INPUT_DEVICES)
+ clear_bit(dev->number, input_devices);
}
void input_register_handler(struct input_handler *handler)
{
struct input_dev *dev = input_dev;
+ struct input_handle *handle;
+
+/*
+ * Add minors if needed.
+ */
+
+ if (handler->fops != NULL)
+ input_table[handler->minor >> 5] = handler;
/*
* Add the handler.
@@ -235,7 +299,8 @@ void input_register_handler(struct input_handler *handler)
*/
while (dev) {
- handler->connect(handler, dev);
+ if ((handle = handler->connect(handler, dev)))
+ input_link_handle(handle);
dev = dev->next;
}
}
@@ -250,6 +315,7 @@ void input_unregister_handler(struct input_handler *handler)
*/
while (handle) {
+ input_unlink_handle(handle);
handler->disconnect(handle);
handle = handle->hnext;
}
@@ -263,42 +329,59 @@ void input_unregister_handler(struct input_handler *handler)
*handlerptr = (*handlerptr)->next;
+/*
+ * Remove minors.
+ */
+
+ if (handler->fops != NULL)
+ input_table[handler->minor >> 5] = NULL;
}
-void input_open_device(struct input_handle *handle)
+static int input_open_file(struct inode *inode, struct file *file)
{
- handle->dnext = handle->dev->handle;
- handle->hnext = handle->handler->handle;
- handle->dev->handle = handle;
- handle->handler->handle = handle;
+ struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];
- if (handle->dev->open)
- handle->dev->open(handle->dev);
-}
+ if (!handler || !handler->fops || !handler->fops->open)
+ return -ENODEV;
-void input_close_device(struct input_handle *handle)
-{
- struct input_handle **handleptr;
+ file->f_op = handler->fops;
- if (handle->dev->close)
- handle->dev->close(handle->dev);
-/*
- * Remove from device list of handles.
- */
+ return handler->fops->open(inode, file);
+}
- handleptr = &handle->dev->handle;
+static struct file_operations input_fops = {
+ open: input_open_file,
+};
- while (*handleptr && (*handleptr != handle))
- handleptr = &((*handleptr)->dnext);
- *handleptr = (*handleptr)->dnext;
+devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
+{
+ char devfs_name[16];
+ sprintf(devfs_name, name, minor);
+ return devfs_register(input_devfs_handle, devfs_name, 0, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
+ S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, &input_fops, NULL);
+}
-/*
- * Remove from handler list of handles.
- */
+void input_unregister_minor(devfs_handle_t handle)
+{
+ devfs_unregister(handle);
+}
- handleptr = &handle->handler->handle;
+static int __init input_init(void)
+{
+ if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
+ printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
+ return -EBUSY;
+ }
+ input_devfs_handle = devfs_mk_dir(NULL, "input", 5, NULL);
+ return 0;
+}
- while (*handleptr && (*handleptr != handle))
- handleptr = &((*handleptr)->hnext);
- *handleptr = (*handleptr)->hnext;
+static void __exit input_exit(void)
+{
+ devfs_unregister(input_devfs_handle);
+ if (devfs_unregister_chrdev(INPUT_MAJOR, "input"))
+ printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
}
+
+module_init(input_init);
+module_exit(input_exit);
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index 9b54300e2..585740db9 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -45,15 +45,18 @@
#include <linux/poll.h>
#include <linux/init.h>
-#define JOYDEV_MAJOR 15
+#define JOYDEV_MINOR_BASE 0
+#define JOYDEV_MINORS 32
#define JOYDEV_BUFFER_SIZE 64
struct joydev {
- char name[32];
int used;
- struct input_handle handle;
+ int open;
int minor;
+ char name[32];
+ struct input_handle handle;
wait_queue_head_t wait;
+ devfs_handle_t devfs;
struct joydev *next;
struct joydev_list *list;
struct js_corr corr[ABS_MAX];
@@ -76,11 +79,10 @@ struct joydev_list {
struct joydev_list *next;
};
-static unsigned long joydev_minors = 0;
-static struct joydev *joydev_base[BITS_PER_LONG];
+static struct joydev *joydev_table[JOYDEV_MINORS];
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_SUPPORTED_DEVICE("js");
+MODULE_SUPPORTED_DEVICE("input/js");
static int joydev_correct(int value, struct js_corr *corr)
{
@@ -164,9 +166,13 @@ static int joydev_release(struct inode * inode, struct file * file)
while (*listptr && (*listptr != list))
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
+
+ if (!--list->joydev->open)
+ input_close_device(&list->joydev->handle);
if (!--list->joydev->used) {
- clear_bit(list->joydev->minor, &joydev_minors);
+ input_unregister_minor(list->joydev->devfs);
+ joydev_table[list->joydev->minor] = NULL;
kfree(list->joydev);
}
@@ -179,28 +185,30 @@ static int joydev_release(struct inode * inode, struct file * file)
static int joydev_open(struct inode *inode, struct file *file)
{
struct joydev_list *list;
- int i = MINOR(inode->i_rdev);
+ int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
- if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
- return -EINVAL;
-
- if (i > BITS_PER_LONG || !test_bit(i, &joydev_minors))
+ if (i > JOYDEV_MINORS || !joydev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
- return -ENOMEM;
+ MOD_INC_USE_COUNT;
+ if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
memset(list, 0, sizeof(struct joydev_list));
- list->joydev = joydev_base[i];
- list->next = joydev_base[i]->list;
- joydev_base[i]->list = list;
+ list->joydev = joydev_table[i];
+ list->next = joydev_table[i]->list;
+ joydev_table[i]->list = list;
file->private_data = list;
list->joydev->used++;
- MOD_INC_USE_COUNT;
+ if (!list->joydev->open++)
+ input_open_device(&list->joydev->handle);
+
return 0;
}
@@ -370,30 +378,33 @@ static struct file_operations joydev_fops = {
fasync: joydev_fasync,
};
-static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct joydev *joydev;
- int i, j;
+ int i, j, minor;
if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) &&
(test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
- || test_bit(BTN_1, dev->keybit)))) return -1;
+ || test_bit(BTN_1, dev->keybit)))) return NULL;
- if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
- return -1;
+ for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+ if (joydev_table[minor]) {
+ printk(KERN_ERR "joydev: no more free joydev devices\n");
+ return NULL;
+ }
+ if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
+ return NULL;
memset(joydev, 0, sizeof(struct joydev));
init_waitqueue_head(&joydev->wait);
- if (joydev_minors == -1) {
- printk("Can't register new joystick - 32 devices already taken.\n");
- return -1;
- }
-
sprintf(joydev->name, "joydev%d", joydev->minor);
+ joydev->minor = minor;
+ joydev_table[minor] = joydev;
+
joydev->handle.dev = dev;
joydev->handle.handler = handler;
joydev->handle.private = joydev;
@@ -421,10 +432,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
joydev->nkey++;
}
- joydev->minor = ffz(joydev_minors);
- set_bit(joydev->minor, &joydev_minors);
- joydev_base[joydev->minor] = joydev;
-
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
if (dev->absmax[j] == dev->absmin[j]) {
@@ -439,21 +446,23 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev)
joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
}
- input_open_device(&joydev->handle);
+ joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
- printk("%s: Joystick device for input%d on /dev/js%d\n", joydev->name, dev->number, joydev->minor);
+ printk("js%d: Joystick device for input%d\n", minor, dev->number);
- return 0;
+ return &joydev->handle;
}
static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
- input_close_device(handle);
+ if (joydev->open)
+ input_close_device(handle);
if (!--joydev->used) {
- clear_bit(joydev->minor, &joydev_minors);
+ input_unregister_minor(joydev->devfs);
+ joydev_table[joydev->minor] = NULL;
kfree(joydev);
}
}
@@ -462,14 +471,12 @@ static struct input_handler joydev_handler = {
event: joydev_event,
connect: joydev_connect,
disconnect: joydev_disconnect,
+ fops: &joydev_fops,
+ minor: JOYDEV_MINOR_BASE,
};
static int __init joydev_init(void)
{
- if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) {
- printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR);
- return -EBUSY;
- }
input_register_handler(&joydev_handler);
return 0;
}
@@ -477,8 +484,6 @@ static int __init joydev_init(void)
static void __exit joydev_exit(void)
{
input_unregister_handler(&joydev_handler);
- if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
- printk(KERN_ERR "js: can't unregister device\n");
}
module_init(joydev_init);
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index 7c94c185b..4723ba11b 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -36,17 +36,63 @@
#include <linux/module.h>
#include <linux/kbd_kern.h>
-#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS)
+
+static int x86_sysrq_alt = 0;
+
+static unsigned short x86_keycodes[256] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 89, 85, 86, 87, 88,115,119,120,121,375,123, 90,
+ 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
+ 367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
+ 360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
+ 103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
+ 291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
+ 118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269,
+ 271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
+ 308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
+ 332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
+
+static int emulate_raw(unsigned int keycode, int down)
+{
+ if (keycode > 255 || !x86_keycodes[keycode])
+ return -1;
+
+ if (keycode == KEY_PAUSE) {
+ handle_scancode(0xe1, 1);
+ handle_scancode(0x1d, down);
+ handle_scancode(0x45, down);
+ return 0;
+ }
+
+ if (keycode == KEY_SYSRQ && x86_sysrq_alt) {
+ handle_scancode(0x54, down);
+ return 0;
+ }
+
+ if (x86_keycodes[keycode] & 0x100)
+ handle_scancode(0xe0, 1);
-static unsigned char keybdev_x86_e0s[] =
- { 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48,
- 0x49, 0x4b, 0x4d, 0x4f, 0x50, 0x51, 0x52, 0x53,
- 0x26, 0x25, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x00,
- 0x23, 0x24, 0x25, 0x26, 0x27 };
+ handle_scancode(x86_keycodes[keycode] & 0x7f, down);
-#elif CONFIG_ADB_KEYBOARD
+ if (keycode == KEY_SYSRQ) {
+ handle_scancode(0xe0, 1);
+ handle_scancode(0x37, down);
+ }
+
+ if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
+ x86_sysrq_alt = down;
-static unsigned char keybdev_mac_codes[256] =
+ return 0;
+}
+
+#elif defined(CONFIG_ADB_KEYBOARD)
+
+static unsigned char mac_keycodes[128] =
{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1,
2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
@@ -56,10 +102,19 @@ static unsigned char keybdev_mac_codes[256] =
76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117,
0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 };
+static int emulate_raw(unsigned int code, unsigned char upflag)
+{
+ if (keycode > 127 || !mac_keycodes[keycode])
+ return -1;
+
+ handle_scancode(mac_keycodes[keycode] & 0x7f, down);
+
+ return 0;
+}
+
#endif
static struct input_handler keybdev_handler;
-static int keybdev_alt = 0;
void keybdev_ledfunc(unsigned int led)
{
@@ -76,70 +131,30 @@ void keybdev_ledfunc(unsigned int led)
void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
{
- if (type != EV_KEY || code > 255) return;
+ if (type != EV_KEY) return;
-#if defined(CONFIG_X86) || defined(CONFIG_IA64)
-
- if (code >= 189) {
- printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
- return;
- } else if (code >= 162) {
- handle_scancode(0xe0, 1);
- handle_scancode(code - 161, down);
- } else if (code >= 125) {
- handle_scancode(0xe0, 1);
- handle_scancode(code - 34, down);
- } else if (code == 119) {
- handle_scancode(0xe1, 1);
- handle_scancode(0x1d, down);
- handle_scancode(0x45, down);
- } else if (code >= 96) {
- if (code == 99 && keybdev_alt) {
- handle_scancode(84, down);
- } else {
- handle_scancode(0xe0, 1);
- 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])
- handle_scancode(keybdev_mac_codes[code] & 0x7f, down);
- else
- printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
-
-#else
-#error "Cannot generate rawmode keyboard for your architecture yet."
-#endif
+ if (emulate_raw(code, down))
+ printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
tasklet_schedule(&keyboard_tasklet);
}
-static int keybdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct input_handle *handle;
int i;
if (!test_bit(EV_KEY, dev->evbit))
- return -1;
+ return NULL;
for (i = KEY_RESERVED; i < BTN_MISC; i++)
if (test_bit(i, dev->keybit)) break;
if (i == BTN_MISC)
- return -1;
+ return NULL;
if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
- return -1;
+ return NULL;
memset(handle, 0, sizeof(struct input_handle));
handle->dev = dev;
@@ -149,15 +164,13 @@ static int keybdev_connect(struct input_handler *handler, struct input_dev *dev)
printk("keybdev.c: Adding keyboard: input%d\n", dev->number);
- return 0;
+ return handle;
}
static void keybdev_disconnect(struct input_handle *handle)
{
printk("keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
-
input_close_device(handle);
-
kfree(handle);
}
diff --git a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c
index c8063c927..a45f8c798 100644
--- a/drivers/usb/mdc800.c
+++ b/drivers/usb/mdc800.c
@@ -26,11 +26,19 @@
* 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
+ * mknod /dev/mustek c 180 32
*
* The driver supports only one camera.
*
* version 0.7.1
+ * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
+ * problems when compiled as Module.
+ * (04/04/2000)
+ *
+ * The mdc800 driver gets assigned the USB Minor 32-47. The Registration
+ * was updated to use these values.
+ * (26/03/2000)
+ *
* The Init und Exit Module Function are updated.
* (01/03/2000)
*
@@ -57,7 +65,6 @@
#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>
@@ -67,22 +74,22 @@
#include <linux/usb.h>
#define VERSION "0.7.1"
-#define RELEASE_DATE "(01/03/2000)"
+#define RELEASE_DATE "(26/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_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
+#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
+/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
+#define MDC800_DEVICE_MINOR_BASE 32
/**************************************************************************
@@ -514,11 +521,20 @@ static int mdc800_getAnswerSize (char command)
static int mdc800_device_open (struct inode* inode, struct file *file)
{
int retval=0;
+
+ MOD_INC_USE_COUNT;
+
if (mdc800->state == NOT_CONNECTED)
+ {
+ MOD_DEC_USE_COUNT;
return -EBUSY;
+ }
if (mdc800->open)
+ {
+ MOD_DEC_USE_COUNT;
return -EBUSY;
+ }
mdc800->rw_lock=0;
mdc800->in_count=0;
@@ -535,10 +551,10 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
if (usb_submit_urb (mdc800->irq_urb))
{
err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
- MOD_INC_USE_COUNT;
mdc800->open=1;
dbg ("Mustek MDC800 device opened.");
@@ -792,21 +808,6 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
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 =
{
@@ -828,17 +829,22 @@ static struct file_operations mdc800_device_ops =
};
+
/*
- * The Misc Device Configuration Struct
+ * USB Driver Struct for this device
*/
-static struct miscdevice mdc800_device =
+static struct usb_driver mdc800_usb_driver =
{
- MDC800_DEVICE_MINOR,
- "USB Mustek MDC800 Camera",
- &mdc800_device_ops
+ "mdc800",
+ mdc800_usb_probe,
+ mdc800_usb_disconnect,
+ { 0,0 },
+ &mdc800_device_ops,
+ MDC800_DEVICE_MINOR_BASE
};
+
/************************************************************************
Init and Cleanup this driver (Main Functions)
*************************************************************************/
@@ -872,8 +878,6 @@ int __init usb_mdc800_init (void)
/* 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>");
@@ -882,9 +886,6 @@ int __init usb_mdc800_init (void)
/* Clean driver up, when something fails */
-cleanup_on_misc_register_fail:
- usb_deregister (&mdc800_usb_driver);
-
cleanup_on_fail:
if (mdc800 != 0)
@@ -909,7 +910,6 @@ cleanup_on_fail:
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);
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index bfdc4ab3d..765f61556 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -29,8 +29,9 @@
*/
#define MOUSEDEV_MINOR_BASE 32
+#define MOUSEDEV_MINORS 32
+#define MOUSEDEV_MIX 31
-#include <linux/miscdevice.h>
#include <linux/malloc.h>
#include <linux/poll.h>
#include <linux/module.h>
@@ -46,12 +47,13 @@
#endif
struct mousedev {
- char name[32];
int used;
- struct input_handle handle;
- struct miscdevice misc;
+ int open;
+ int minor;
wait_queue_head_t wait;
struct mousedev_list *list;
+ struct input_handle handle;
+ devfs_handle_t devfs;
};
struct mousedev_list {
@@ -71,77 +73,80 @@ struct mousedev_list {
static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
-static struct mousedev mousedev_single;
-#else
-static unsigned long mousedev_miscbits = 0;
-static struct mousedev *mousedev_base[BITS_PER_LONG];
-#endif
+static struct input_handler mousedev_handler;
+
+static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
+static struct mousedev mousedev_mix;
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
- struct mousedev *mousedev = handle->private;
- struct mousedev_list *list = mousedev->list;
+ struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
+ struct mousedev **mousedev = mousedevs;
+ struct mousedev_list *list;
int index, size;
- while (list) {
- switch (type) {
- case EV_ABS:
- switch (code) {
- case ABS_X:
- size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
- list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
- list->oldx += list->dx * size;
- 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;
- break;
- }
- break;
- case EV_REL:
- switch (code) {
- case REL_X: list->dx += value; break;
- case REL_Y: list->dy -= value; break;
- case REL_WHEEL: if (list->mode) list->dz -= value; break;
- }
- break;
+ while (*mousedev) {
+ list = (*mousedev)->list;
+ while (list) {
+ switch (type) {
+ case EV_ABS:
+ switch (code) {
+ case ABS_X:
+ size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
+ list->dx += (value * CONFIG_MOUSEDEV_SCREEN_X - list->oldx) / size;
+ list->oldx += list->dx * size;
+ 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;
+ break;
+ }
+ break;
+ case EV_REL:
+ switch (code) {
+ case REL_X: list->dx += value; break;
+ case REL_Y: list->dy -= value; break;
+ case REL_WHEEL: if (list->mode) list->dz -= value; break;
+ }
+ break;
+
+ case EV_KEY:
+ switch (code) {
+ case BTN_0:
+ case BTN_TOUCH:
+ case BTN_LEFT: index = 0; break;
+ case BTN_4:
+ case BTN_EXTRA: if (list->mode > 1) { index = 4; break; }
+ case BTN_STYLUS:
+ case BTN_1:
+ case BTN_RIGHT: index = 1; break;
+ case BTN_3:
+ case BTN_SIDE: if (list->mode > 1) { index = 3; break; }
+ case BTN_2:
+ case BTN_STYLUS2:
+ case BTN_MIDDLE: index = 2; break;
+ default: return;
+ }
+ switch (value) {
+ case 0: clear_bit(index, &list->buttons); break;
+ case 1: set_bit(index, &list->buttons); break;
+ case 2: return;
+ }
+ break;
+ }
+
+ list->ready = 1;
- case EV_KEY:
- switch (code) {
- case BTN_0:
- case BTN_TOUCH:
- case BTN_LEFT: index = 0; break;
- case BTN_4:
- case BTN_EXTRA: if (list->mode > 1) { index = 4; break; }
- case BTN_STYLUS:
- case BTN_1:
- case BTN_RIGHT: index = 1; break;
- case BTN_3:
- case BTN_SIDE: if (list->mode > 1) { index = 3; break; }
- case BTN_2:
- case BTN_STYLUS2:
- case BTN_MIDDLE: index = 2; break;
- default: return;
- }
- switch (value) {
- case 0: clear_bit(index, &list->buttons); break;
- case 1: set_bit(index, &list->buttons); break;
- case 2: return;
- }
- break;
- }
-
- list->ready = 1;
+ if (list->fasync)
+ kill_fasync(list->fasync, SIGIO, POLL_IN);
- if (list->fasync)
- kill_fasync(list->fasync, SIGIO, POLL_IN);
+ list = list->next;
+ }
- list = list->next;
+ wake_up_interruptible(&((*mousedev)->wait));
+ mousedev++;
}
-
- wake_up_interruptible(&mousedev->wait);
}
static int mousedev_fasync(int fd, struct file *file, int on)
@@ -162,14 +167,27 @@ static int mousedev_release(struct inode * inode, struct file * file)
while (*listptr && (*listptr != list))
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
+
+ if (!--list->mousedev->open) {
+ if (list->mousedev->minor == MOUSEDEV_MIX) {
+ struct input_handle *handle = mousedev_handler.handle;
+ while (handle) {
+ struct mousedev *mousedev = handle->private;
+ if (!mousedev->open)
+ input_close_device(handle);
+ handle = handle->hnext;
+ }
+ } else {
+ if (!mousedev_mix.open)
+ input_close_device(&list->mousedev->handle);
+ }
+ }
-#ifndef CONFIG_INPUT_MOUSEDEV_MIX
if (!--list->mousedev->used) {
- clear_bit(list->mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits);
- misc_deregister(&list->mousedev->misc);
+ input_unregister_minor(list->mousedev->devfs);
+ mousedev_table[list->mousedev->minor] = NULL;
kfree(list->mousedev);
}
-#endif
kfree(list);
@@ -180,33 +198,41 @@ static int mousedev_release(struct inode * inode, struct file * file)
static int mousedev_open(struct inode * inode, struct file * file)
{
struct mousedev_list *list;
-
-#ifndef CONFIG_INPUT_MOUSEDEV_MIX
int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
- if (i > BITS_PER_LONG || !test_bit(i, &mousedev_miscbits))
+
+ if (i > MOUSEDEV_MINORS || !mousedev_table[i])
return -ENODEV;
-#endif
- if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
- return -ENOMEM;
+ MOD_INC_USE_COUNT;
+ if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
memset(list, 0, sizeof(struct mousedev_list));
+ list->mousedev = mousedev_table[i];
+ list->next = mousedev_table[i]->list;
+ mousedev_table[i]->list = list;
+ file->private_data = list;
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- list->mousedev = &mousedev_single;
- list->next = mousedev_single.list;
- mousedev_single.list = list;
-#else
- list->mousedev = mousedev_base[i];
- list->next = mousedev_base[i]->list;
- mousedev_base[i]->list = list;
list->mousedev->used++;
-#endif
- file->private_data = list;
+ if (!list->mousedev->open++) {
+ if (list->mousedev->minor == MOUSEDEV_MIX) {
+ struct input_handle *handle = mousedev_handler.handle;
+ while (handle) {
+ struct mousedev *mousedev = handle->private;
+ if (!mousedev->open)
+ input_open_device(handle);
+ handle = handle->hnext;
+ }
+ } else {
+ if (!mousedev_mix.open)
+ input_open_device(&list->mousedev->handle);
+ }
+ }
- MOD_INC_USE_COUNT;
return 0;
}
@@ -357,119 +383,93 @@ struct file_operations mousedev_fops = {
fasync: mousedev_fasync,
};
-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
{
+ struct mousedev *mousedev;
+ int minor = 0;
if (!test_bit(EV_KEY, dev->evbit) ||
(!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
- return -1;
+ return NULL;
if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
(!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
- return -1;
-
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- {
- struct input_handle *handle;
-
- if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
- return -1;
-
- memset(handle, 0, sizeof(struct input_handle));
+ return NULL;
- handle->dev = dev;
- handle->handler = handler;
- handle->private = &mousedev_single;
-
- input_open_device(handle);
-
- printk("mousedev.c: Adding mouse: input%d\n", dev->number);
+ for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
+ if (mousedev_table[minor]) {
+ printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+ return NULL;
}
-#else
- {
- struct mousedev *mousedev;
-
- if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
- return -1;
- memset(mousedev, 0, sizeof(struct mousedev));
+ if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
+ return NULL;
+ memset(mousedev, 0, sizeof(struct mousedev));
+ init_waitqueue_head(&mousedev->wait);
- mousedev->misc.minor = ffz(mousedev_miscbits);
- set_bit(mousedev->misc.minor, &mousedev_miscbits);
- mousedev_base[mousedev->misc.minor] = mousedev;
+ mousedev->used = 1;
+ mousedev->minor = minor;
+ mousedev_table[minor] = mousedev;
- sprintf(mousedev->name, "mousedev%d", mousedev->misc.minor);
- mousedev->misc.name = mousedev->name;
- mousedev->misc.minor += MOUSEDEV_MINOR_BASE;
- mousedev->misc.fops = &mousedev_fops;
+ mousedev->handle.dev = dev;
+ mousedev->handle.handler = handler;
+ mousedev->handle.private = mousedev;
- mousedev->handle.dev = dev;
- mousedev->handle.handler = handler;
- mousedev->handle.private = mousedev;
+ mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
- init_waitqueue_head(&mousedev->wait);
-
- mousedev->used = 1;
-
- misc_register(&mousedev->misc);
+ if (mousedev_mix.open) {
input_open_device(&mousedev->handle);
-
- printk("%s: PS/2 mouse device for input%d on misc%d\n",
- mousedev->name, dev->number, mousedev->misc.minor);
+ mousedev_mix.open++;
}
-#endif
- return 0;
+ printk("mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
+
+ return &mousedev->handle;
}
static void mousedev_disconnect(struct input_handle *handle)
{
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- printk("mousedev.c: Removing mouse: input%d\n", handle->dev->number);
- input_close_device(handle);
- kfree(handle);
-#else
struct mousedev *mousedev = handle->private;
- input_close_device(handle);
+
+ if (mousedev->open || mousedev_mix.open) {
+ input_close_device(handle);
+ mousedev_mix.open--;
+ }
+
if (!--mousedev->used) {
- clear_bit(mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits);
- misc_deregister(&mousedev->misc);
+ input_unregister_minor(mousedev->devfs);
+ mousedev_table[mousedev->minor] = NULL;
kfree(mousedev);
}
-#endif
}
static struct input_handler mousedev_handler = {
event: mousedev_event,
connect: mousedev_connect,
disconnect: mousedev_disconnect,
+ fops: &mousedev_fops,
+ minor: MOUSEDEV_MINOR_BASE,
};
static int __init mousedev_init(void)
{
input_register_handler(&mousedev_handler);
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- memset(&mousedev_single, 0, sizeof(struct mousedev));
-
- init_waitqueue_head(&mousedev_single.wait);
- mousedev_single.misc.minor = MOUSEDEV_MINOR_BASE;
- mousedev_single.misc.name = "mousedev";
- mousedev_single.misc.fops = &mousedev_fops;
+ memset(&mousedev_mix, 0, sizeof(struct mousedev));
+ init_waitqueue_head(&mousedev_mix.wait);
+ mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
+ mousedev_mix.used = 1;
+ mousedev_mix.minor = MOUSEDEV_MIX;
+ mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
- misc_register(&mousedev_single.misc);
-
- printk("mousedev: PS/2 mouse device on misc%d\n", mousedev_single.misc.minor);
-#endif
+ printk("mice: PS/2 mouse device common for all mice\n");
return 0;
}
static void __exit mousedev_exit(void)
{
-#ifdef CONFIG_INPUT_MOUSEDEV_MIX
- misc_deregister(&mousedev_single.misc);
-#endif
+ input_unregister_minor(mousedev_mix.devfs);
input_unregister_handler(&mousedev_handler);
}
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index d1f5048e3..78551b77c 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -4,12 +4,13 @@
* Many improvements by Bret Wallach
* Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
* Snapshot code by Kevin Moore
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
*
* Based on the Linux CPiA driver.
*
* Released under GPL v.2 license.
*
- * Version: 1.09
+ * Version: 1.11
*
* Please see the file: linux/Documentation/usb/ov511.txt
* and the website at: http://alpha.dyndns.org/ov511
@@ -34,8 +35,6 @@
#define __NO_VERSION__
-/* Handle mangled (versioned) external symbols */
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
@@ -83,10 +82,14 @@ static int fix_rgb_offset = 0;
/* Snapshot mode enabled flag */
static int snapshot = 0;
+/* Sensor detection override (global for all attached cameras) */
+static int sensor = 0;
+
MODULE_PARM(autoadjust, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(fix_rgb_offset, "i");
MODULE_PARM(snapshot, "i");
+MODULE_PARM(sensor, "i");
MODULE_AUTHOR("Mark McClelland (and others)");
MODULE_DESCRIPTION("OV511 USB Camera Driver");
@@ -210,7 +213,9 @@ static void rvfree(void *mem, unsigned long size)
vfree(mem);
}
-int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+static int ov511_reg_write(struct usb_device *dev,
+ unsigned char reg,
+ unsigned char value)
{
int rc;
@@ -219,14 +224,17 @@ int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char val
2 /* REG_IO */,
USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, &value, 1, HZ);
-
+
PDEBUG(5, "reg write: 0x%02X:0x%02X, 0x%x", reg, value, rc);
-
+
+ if (rc < 0)
+ err("ov511_reg_write: error %d", rc);
+
return rc;
}
/* returns: negative is error, pos or zero is data */
-int ov511_reg_read(struct usb_device *dev, unsigned char reg)
+static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
{
int rc;
unsigned char buffer[1];
@@ -239,13 +247,17 @@ int ov511_reg_read(struct usb_device *dev, unsigned char reg)
PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]);
- if(rc < 0)
+ if(rc < 0) {
+ err("ov511_reg_read: error %d", rc);
return rc;
+ }
else
return buffer[0];
}
-int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+static int ov511_i2c_write(struct usb_device *dev,
+ unsigned char reg,
+ unsigned char value)
{
int rc, retries;
@@ -255,19 +267,19 @@ int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char val
for(retries = OV511_I2C_RETRIES;;) {
/* Select camera register */
rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
/* Write "value" to I2C data port of OV511 */
rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
/* Initiate 3-byte write cycle */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
if((rc&2) == 0) /* Ack? */
break;
@@ -275,14 +287,22 @@ int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char val
/* I2C abort */
ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
#endif
- if (--retries < 0) return -1;
+ if (--retries < 0) {
+ err("i2c write retries exhausted");
+ rc = -1;
+ goto error;
+ }
}
return 0;
+
+error:
+ err("ov511_i2c_write: error %d", rc);
+ return rc;
}
/* returns: negative is error, pos or zero is data */
-int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
+static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
{
int rc, value, retries;
@@ -290,15 +310,15 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
for(retries = OV511_I2C_RETRIES;;) {
/* Select camera register */
rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
/* Initiate 2-byte write cycle */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
if((rc&2) == 0) /* Ack? */
break;
@@ -306,27 +326,35 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
/* I2C abort */
ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
- if (--retries < 0) return -1;
+ if (--retries < 0) {
+ err("i2c write retries exhausted");
+ rc = -1;
+ goto error;
+ }
}
/* Two byte read cycle */
for(retries = OV511_I2C_RETRIES;;) {
/* Initiate 2-byte read cycle */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
if((rc&2) == 0) /* Ack? */
break;
/* I2C abort */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
- if (--retries < 0) return -1;
+ if (--retries < 0) {
+ err("i2c read retries exhausted");
+ rc = -1;
+ goto error;
+ }
}
value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
@@ -335,60 +363,41 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
/* This is needed to make ov511_i2c_write() work */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
- if (rc < 0) return rc;
+ if (rc < 0) goto error;
- return (value);
-}
-
-
-// This version doesn't always work
-#if 0
- /* returns: negative is error, pos or zero is data */
- int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
- {
- int rc, value;
-
- /* Select camera register */
- rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
- if (rc < 0) return rc;
-
-
- /* Initiate 2-byte write cycle */
- rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
- if (rc < 0) return rc;
-
-
- /* Initiate 2-byte read cycle */
- rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
- if (rc < 0) return rc;
-
- value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+ return value;
- PDEBUG(5, "i2c read: 0x%02X:0x%02X", reg, value);
-
- return (value);
- }
-#endif
+error:
+ err("ov511_i2c_read: error %d", rc);
+ return rc;
+}
static int ov511_write_regvals(struct usb_device *dev,
struct ov511_regvals * pRegvals)
{
- int ret;
+ int rc;
+
while(pRegvals->bus != OV511_DONE_BUS) {
if (pRegvals->bus == OV511_REG_BUS) {
- if ((ret = ov511_reg_write(dev, pRegvals->reg,
+ if ((rc = ov511_reg_write(dev, pRegvals->reg,
pRegvals->val)) < 0)
- return ret;
+ goto error;
} else if (pRegvals->bus == OV511_I2C_BUS) {
- if ((ret = ov511_i2c_write(dev, pRegvals->reg,
+ if ((rc = ov511_i2c_write(dev, pRegvals->reg,
pRegvals->val)) < 0)
- return ret;
+ goto error;
} else {
- err("Bad regval array");
+ err("Bad regval array");
+ rc = -1;
+ goto error;
}
pRegvals++;
}
return 0;
+
+error:
+ err("ov511_write_regvals: error %d", rc);
+ return rc;
}
#if 0
@@ -396,10 +405,9 @@ static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
{
int i;
int rc;
- for(i=reg1; i<=regn; i++) {
- rc = ov511_i2c_read(dev, i);
-
- PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc);
+ for(i = reg1; i <= regn; i++) {
+ rc = ov511_i2c_read(dev, i);
+ PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc);
}
}
@@ -413,7 +421,7 @@ static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
{
int i;
int rc;
- for(i=reg1; i<=regn; i++) {
+ for(i = reg1; i <= regn; i++) {
rc = ov511_reg_read(dev, i);
PDEBUG(1, "OV511[0x%X] = 0x%X", i, rc);
}
@@ -443,72 +451,82 @@ static void ov511_dump_regs( struct usb_device *dev)
}
#endif
-int ov511_reset(struct usb_device *dev, unsigned char reset_type)
+static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
{
int rc;
PDEBUG(3, "Reset: type=0x%X", reset_type);
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
- if (rc < 0)
- err("reset: command failed");
-
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
+
if (rc < 0)
err("reset: command failed");
return rc;
}
-int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov511_stop(struct usb_device *dev)
{
- int alt, multiplier, rc;
-
- PDEBUG(3, "set packet size: %d", size);
-
- switch (size) {
- case 992:
- alt = 0;
- multiplier = 31;
- break;
- case 993:
- alt = 1;
- multiplier = 31;
- break;
- case 768:
- alt = 2;
- multiplier = 24;
- break;
- case 769:
- alt = 3;
- multiplier = 24;
- break;
- case 512:
- alt = 4;
- multiplier = 16;
- break;
- case 513:
- alt = 5;
- multiplier = 16;
- break;
- case 257:
- alt = 6;
- multiplier = 8;
- break;
- case 0:
- alt = 7;
- multiplier = 1; // FIXME - is this correct?
- break;
- default:
+ PDEBUG(4, "ov511_stop()");
+ return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));
+}
+
+/* Restarts OV511 after ov511_stop() is called */
+static inline int ov511_restart(struct usb_device *dev)
+{
+ PDEBUG(4, "ov511_restart()");
+ return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));
+}
+
+static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+{
+ int alt, mult;
+
+ if (ov511_stop(ov511->dev) < 0)
+ return -EIO;
+
+ mult = size / 32;
+
+ if (ov511->bridge == BRG_OV511) {
+ if (size == 0) alt = OV511_ALT_SIZE_0;
+ else if (size == 257) alt = OV511_ALT_SIZE_257;
+// else if (size == 512) alt = OV511_ALT_SIZE_512;
+ else if (size == 513) alt = OV511_ALT_SIZE_513;
+// else if (size == 768) alt = OV511_ALT_SIZE_768;
+ else if (size == 769) alt = OV511_ALT_SIZE_769;
+// else if (size == 992) alt = OV511_ALT_SIZE_992;
+ else if (size == 993) alt = OV511_ALT_SIZE_993;
+ else {
err("Set packet size: invalid size (%d)", size);
return -EINVAL;
+ }
+ }
+ else if (ov511->bridge == BRG_OV511PLUS) {
+ if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
+ else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
+ else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
+ else if (size == 257) alt = OV511PLUS_ALT_SIZE_257;
+ else if (size == 385) alt = OV511PLUS_ALT_SIZE_385;
+ else if (size == 513) alt = OV511PLUS_ALT_SIZE_513;
+ else if (size == 769) alt = OV511PLUS_ALT_SIZE_769;
+ else if (size == 961) alt = OV511PLUS_ALT_SIZE_961;
+ else {
+ err("Set packet size: invalid size (%d)", size);
+ return -EINVAL;
+ }
+ }
+ else {
+ err("Set packet size: Invalid bridge type");
+ return -EINVAL;
}
- rc = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
- multiplier);
- if (rc < 0) {
- err("Set packet size: Set FIFO size ret %d", rc);
+ PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
+
+ if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+ mult) < 0)
return -ENOMEM;
- }
if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
err("Set packet size: set interface error");
@@ -519,6 +537,11 @@ int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
return -ENOMEM;
+ ov511->packet_size = size;
+
+ if (ov511_restart(ov511->dev) < 0)
+ return -EIO;
+
return 0;
}
@@ -526,34 +549,44 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
struct video_picture *p)
{
int ret;
+ struct usb_device *dev = ov511->dev;
- /* Stop the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
- err("reset: command failed");
+ PDEBUG(4, "ov511_set_picture");
+
+ if (ov511_stop(dev) < 0)
return -EIO;
- }
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_COM_B)) < 0)
+ if((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
return -EIO;
#if 0
- if(ov511_i2c_write(ov511->dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
+ if(ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
return -EIO;
#endif
+ if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE)
+ if(ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0)
+ return -EIO;
+
+ if (ov511->sensor == SEN_OV7610) {
+ if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+ return -EIO;
+
+ if(ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
+ return -EIO;
+ }
+ else if ((ov511->sensor == SEN_OV7620)
+ || (ov511->sensor == SEN_OV7620AE)) {
+// cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
+// cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
+// // DEBUG_CODE
+// PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
+// ov511_i2c_read(dev, OV7610_REG_BRT));
+//
+// if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+// return -EIO;
+ }
- if(ov511_i2c_write(ov511->dev, OV7610_REG_SAT, p->colour >> 8) < 0)
- return -EIO;
-
- if(ov511_i2c_write(ov511->dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
- return -EIO;
-
- if(ov511_i2c_write(ov511->dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
- return -EIO;
-
- /* Restart the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) {
- err("reset: command failed");
+ if (ov511_restart(dev) < 0)
return -EIO;
- }
return 0;
}
@@ -562,20 +595,20 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
struct video_picture *p)
{
int ret;
+ struct usb_device *dev = ov511->dev;
- /* Stop the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
- err("reset: command failed");
+ PDEBUG(4, "ov511_get_picture");
+
+ if (ov511_stop(dev) < 0)
return -EIO;
- }
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_SAT)) < 0) return -EIO;
+ if((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO;
p->colour = ret << 8;
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_CNT)) < 0) return -EIO;
+ if((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO;
p->contrast = ret << 8;
- if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_BRT)) < 0) return -EIO;
+ if((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO;
p->brightness = ret << 8;
p->hue = 0x8000;
@@ -583,11 +616,8 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
p->depth = 3; /* Don't know if this is right */
p->palette = VIDEO_PALETTE_RGB24;
- /* Restart the camera */
- if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) {
- err("reset: command failed");
+ if (ov511_restart(dev) < 0)
return -EIO;
- }
return 0;
}
@@ -597,67 +627,93 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
{
int rc = 0;
struct usb_device *dev = ov511->dev;
+ int hwsbase = 0;
+ int hwebase = 0;
PDEBUG(3, "ov511_mode_init_regs(ov511, w:%d, h:%d, mode:%d, sub:%d)",
width, height, mode, sub_flag);
-// ov511_set_packet_size(ov511, 0);
- if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) {
- err("reset: command failed");
+ if (ov511_stop(ov511->dev) < 0)
return -EIO;
- }
if (mode == VIDEO_PALETTE_GREY) {
ov511_reg_write(dev, 0x16, 0x00);
- ov511_i2c_write(dev, 0x0e, 0x44);
- ov511_i2c_write(dev, 0x13, 0x21);
+ if (ov511->sensor == SEN_OV7610
+ || ov511->sensor == SEN_OV7620AE) {
+ /* these aren't valid on the OV7620 */
+ ov511_i2c_write(dev, 0x0e, 0x44);
+ }
+ ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20);
/* For snapshot */
ov511_reg_write(dev, 0x1e, 0x00);
ov511_reg_write(dev, 0x1f, 0x01);
} else {
ov511_reg_write(dev, 0x16, 0x01);
- ov511_i2c_write(dev, 0x0e, 0x04);
- ov511_i2c_write(dev, 0x13, 0x01);
+ if (ov511->sensor == SEN_OV7610
+ || ov511->sensor == SEN_OV7620AE) {
+ /* not valid on the OV7620 */
+ ov511_i2c_write(dev, 0x0e, 0x04);
+ }
+ ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00);
/* For snapshot */
ov511_reg_write(dev, 0x1e, 0x01);
ov511_reg_write(dev, 0x1f, 0x03);
}
+ /* The different sensor ICs handle setting up of window differently */
+ switch (ov511->sensor) {
+ case SEN_OV7610:
+ case SEN_OV7620AE:
+ hwsbase = 0x38;
+ hwebase = 0x3a; break;
+ case SEN_OV7620:
+ hwsbase = 0x2c;
+ hwebase = 0x2d; break;
+ default:
+ hwsbase = 0;
+ hwebase = 0; break;
+ }
+
if (width == 640 && height == 480) {
if (sub_flag) {
- ov511_i2c_write(ov511->dev, 0x17, 0x38+(ov511->subx>>2));
- ov511_i2c_write(ov511->dev, 0x18,
- 0x3a+((ov511->subx+ov511->subw)>>2));
- ov511_i2c_write(ov511->dev, 0x19, 0x5+(ov511->suby>>1));
- ov511_i2c_write(ov511->dev, 0x1a,
+ /* horizontal window start */
+ ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2));
+ /* horizontal window end */
+ ov511_i2c_write(dev, 0x18,
+ hwebase+((ov511->subx+ov511->subw)>>2));
+ /* vertical window start */
+ ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
+ /* vertical window end */
+ ov511_i2c_write(dev, 0x1a,
0x5+((ov511->suby+ov511->subh)>>1));
- ov511_reg_write(ov511->dev, 0x12, (ov511->subw>>3)-1);
- ov511_reg_write(ov511->dev, 0x13, (ov511->subh>>3)-1);
+ ov511_reg_write(dev, 0x12, (ov511->subw>>3)-1);
+ ov511_reg_write(dev, 0x13, (ov511->subh>>3)-1);
+ /* clock rate control */
ov511_i2c_write(dev, 0x11, 0x01);
/* Snapshot additions */
- ov511_reg_write(ov511->dev, 0x1a, (ov511->subw>>3)-1);
- ov511_reg_write(ov511->dev, 0x1b, (ov511->subh>>3)-1);
- ov511_reg_write(ov511->dev, 0x1c, 0x00);
- ov511_reg_write(ov511->dev, 0x1d, 0x00);
+ ov511_reg_write(dev, 0x1a, (ov511->subw>>3)-1);
+ ov511_reg_write(dev, 0x1b, (ov511->subh>>3)-1);
+ ov511_reg_write(dev, 0x1c, 0x00);
+ ov511_reg_write(dev, 0x1d, 0x00);
} else {
- ov511_i2c_write(ov511->dev, 0x17, 0x38);
- ov511_i2c_write(ov511->dev, 0x18, 0x3a + (640>>2));
- ov511_i2c_write(ov511->dev, 0x19, 0x5);
- ov511_i2c_write(ov511->dev, 0x1a, 5 + (480>>1));
+ ov511_i2c_write(dev, 0x17, hwsbase);
+ ov511_i2c_write(dev, 0x18, hwebase + (640>>2));
+ ov511_i2c_write(dev, 0x19, 0x5);
+ ov511_i2c_write(dev, 0x1a, 5 + (480>>1));
ov511_reg_write(dev, 0x12, 0x4f);
ov511_reg_write(dev, 0x13, 0x3d);
/* Snapshot additions */
- ov511_reg_write(ov511->dev, 0x1a, 0x4f);
- ov511_reg_write(ov511->dev, 0x1b, 0x3d);
- ov511_reg_write(ov511->dev, 0x1c, 0x00);
- ov511_reg_write(ov511->dev, 0x1d, 0x00);
+ ov511_reg_write(dev, 0x1a, 0x4f);
+ ov511_reg_write(dev, 0x1b, 0x3d);
+ ov511_reg_write(dev, 0x1c, 0x00);
+ ov511_reg_write(dev, 0x1d, 0x00);
if (mode == VIDEO_PALETTE_GREY) {
- ov511_i2c_write(dev, 0x11, 4); /* check */
+ ov511_i2c_write(dev, 0x11, 4); /* check */
} else {
- ov511_i2c_write(dev, 0x11, 6); /* check */
+ ov511_i2c_write(dev, 0x11, 6); /* check */
}
}
@@ -669,7 +725,10 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
ov511_i2c_write(dev, 0x12, 0x24);
ov511_i2c_write(dev, 0x14, 0x04);
- ov511_i2c_write(dev, 0x35, 0x9e);
+
+ /* 7620 doesn't have register 0x35, so play it safe */
+ if (ov511->sensor != SEN_OV7620)
+ ov511_i2c_write(dev, 0x35, 0x9e);
} else if (width == 320 && height == 240) {
ov511_reg_write(dev, 0x12, 0x27);
ov511_reg_write(dev, 0x13, 0x1f);
@@ -697,12 +756,8 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
rc = -EINVAL;
}
-// ov511_set_packet_size(ov511, 993);
-
- if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00) < 0) {
- err("reset: command failed");
+ if (ov511_restart(ov511->dev) < 0)
return -EIO;
- }
return rc;
}
@@ -928,29 +983,30 @@ static void ov511_parse_data_grey(unsigned char * pIn0,
*************************************************************/
static void fixFrameRGBoffset(struct ov511_frame *frame)
{
- int x,y;
- int rowBytes=frame->width*3,w=frame->width;
- unsigned char *rgb=frame->data;
- const int shift=1;//Distance to shift pixels by, vertically
+ int x, y;
+ int rowBytes = frame->width*3, w = frame->width;
+ unsigned char *rgb = frame->data;
+ const int shift = 1; //Distance to shift pixels by, vertically
- if (frame->width<400)
- return;//Don't bother with little images
+ if (frame->width < 400)
+ return; //Don't bother with little images
//Shift red channel up
- for (y=shift;y<frame->height;y++)
+ for (y = shift; y < frame->height; y++)
{
- int lp=(y-shift)*rowBytes;//Previous line offset
- int lc=y*rowBytes;//Current line offset
- for (x=0;x<w;x++)
- rgb[lp+x*3+2]=rgb[lc+x*3+2];//Shift red up
+ int lp = (y-shift)*rowBytes; //Previous line offset
+ int lc = y*rowBytes; //Current line offset
+ for (x = 0; x < w; x++)
+ rgb[lp+x*3+2] = rgb[lc+x*3+2]; //Shift red up
}
+
//Shift blue channel down
- for (y=frame->height-shift-1;y>=0;y--)
+ for (y=frame->height-shift-1; y >= 0; y--)
{
- int ln=(y+shift)*rowBytes;//Next line offset
- int lc=y*rowBytes;//Current line offset
- for (x=0;x<w;x++)
- rgb[ln+x*3+0]=rgb[lc+x*3+0];//Shift blue down
+ int ln = (y+shift)*rowBytes; //Next line offset
+ int lc = y*rowBytes; //Current line offset
+ for (x = 0; x < w; x++)
+ rgb[ln+x*3+0] = rgb[lc+x*3+0]; //Shift blue down
}
}
@@ -962,6 +1018,8 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
int aPackNum[10];
struct ov511_frame *frame;
+ PDEBUG(4, "ov511_move_data");
+
for (i = 0; i < urb->number_of_packets; i++) {
int n = urb->iso_frame_desc[i].actual_length;
int st = urb->iso_frame_desc[i].status;
@@ -969,7 +1027,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
urb->iso_frame_desc[i].status = 0;
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- aPackNum[i] = n ? cdata[992] : -1;
+ aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
if (!n || ov511->curframe == -1) continue;
@@ -988,7 +1046,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
do_gettimeofday(ts);
PDEBUG(4, "Frame End, curframe = %d, packnum=%d, hw=%d, vw=%d",
- ov511->curframe, (int)(cdata[992]),
+ ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
(int)(cdata[9]), (int)(cdata[10]));
if (frame->scanstate == STATE_LINES) {
@@ -1051,7 +1109,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
}
/* Parse the segments */
- while(iPix <= 992 - frame->segsize &&
+ while(iPix <= (ov511->packet_size - 1) - frame->segsize &&
frame->segment < frame->width * frame->height / 256) {
int iSegY;
int iSegUV;
@@ -1099,7 +1157,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
/* Save extra data for next time */
if (frame->segment < frame->width * frame->height / 256) {
- ov511->scratchlen = 992 - iPix;
+ ov511->scratchlen = (ov511->packet_size - 1) - iPix;
if (ov511->scratchlen < frame->segsize) {
memmove(ov511->scratch, pData, ov511->scratchlen);
} else {
@@ -1149,13 +1207,20 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
{
urb_t *urb;
int fx, err;
-
+
+ PDEBUG(4, "ov511_init_isoc");
+
ov511->compress = 0;
ov511->curframe = -1;
ov511->cursbuf = 0;
ov511->scratchlen = 0;
- ov511_set_packet_size(ov511, 993);
+ if (ov511->bridge == BRG_OV511)
+ ov511_set_packet_size(ov511, 993);
+ else if (ov511->bridge == BRG_OV511PLUS)
+ ov511_set_packet_size(ov511, 961);
+ else
+ err("invalid bridge type");
/* We double buffer the Iso lists */
urb = usb_alloc_urb(FRAMES_PER_DESC);
@@ -1172,10 +1237,10 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb->transfer_buffer = ov511->sbuf[0].data;
urb->complete = ov511_isoc_irq;
urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+ urb->iso_frame_desc[fx].length = ov511->packet_size;
}
urb = usb_alloc_urb(FRAMES_PER_DESC);
@@ -1191,10 +1256,10 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb->transfer_buffer = ov511->sbuf[1].data;
urb->complete = ov511_isoc_irq;
urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+ urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+ urb->iso_frame_desc[fx].length = ov511->packet_size;
}
ov511->sbuf[1].urb->next = ov511->sbuf[0].urb;
@@ -1215,6 +1280,7 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
static void ov511_stop_isoc(struct usb_ov511 *ov511)
{
+ PDEBUG(4, "ov511_stop_isoc");
if (!ov511->streaming || !ov511->dev)
return;
@@ -1239,10 +1305,11 @@ static void ov511_stop_isoc(struct usb_ov511 *ov511)
static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
{
-#if 1
struct ov511_frame *frame;
int width, height;
+ PDEBUG(4, "ov511_new_frame");
+
if (!ov511->dev)
return -1;
@@ -1277,7 +1344,6 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
// /* We want a fresh frame every 30 we get */
// ov511->compress = (ov511->compress + 1) % 30;
-#endif
return 0;
}
@@ -1311,10 +1377,10 @@ static int ov511_open(struct video_device *dev, int flags)
PDEBUG(4, "frame [0] @ %p", ov511->frame[0].data);
PDEBUG(4, "frame [1] @ %p", ov511->frame[1].data);
- ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!ov511->sbuf[0].data)
goto open_err_on0;
- ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!ov511->sbuf[1].data)
goto open_err_on1;
@@ -1835,9 +1901,11 @@ static struct video_device ov511_template = {
initialize: ov511_init_done,
};
-static int ov7610_configure(struct usb_device *dev)
+static int ov7610_configure(struct usb_ov511 *ov511)
{
+ struct usb_device *dev = ov511->dev;
int tries;
+ int rc;
if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
OV7610_I2C_WRITE_ID) < 0)
@@ -1865,13 +1933,42 @@ static int ov7610_configure(struct usb_device *dev)
--tries;
}
- if (tries == 0) {
- err("Failed to read OV7610 ID. You might not have an OV7610,");
+ if (tries == 1) {
+ err("Failed to read sensor ID. You might not have an OV7610/20,");
err("or it may be not responding. Report this to");
err("mmcclelland@delphi.com");
return -1;
}
+ if (sensor == 0) {
+ rc = ov511_i2c_read(dev, OV7610_REG_COM_I);
+
+ if (rc < 0) {
+ err("Error detecting sensor type");
+ return -1;
+ }
+ else if((rc & 3) == 3) {
+ printk("ov511: Sensor is an OV7610\n");
+ ov511->sensor = SEN_OV7610;
+ }
+ else if((rc & 3) == 1) {
+ printk("ov511: Sensor is an OV7620AE\n");
+ ov511->sensor = SEN_OV7620AE;
+ }
+ else if((rc & 3) == 0) {
+ printk("ov511: Sensor is an OV7620\n");
+ ov511->sensor = SEN_OV7620;
+ }
+ else {
+ err("Unknown image sensor version: %d", rc & 3);
+ return -1;
+ }
+ }
+ else { /* sensor != 0; user overrode detection */
+ ov511->sensor = sensor;
+ printk("ov511: Sensor set to type %d\n", ov511->sensor);
+ }
+
return 0;
}
@@ -1890,9 +1987,9 @@ static int ov511_configure(struct usb_ov511 *ov511)
{OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d},
{OV511_DONE_BUS, 0x0, 0x00},
};
- static struct ov511_regvals aRegvalsNorm[] =
- {{OV511_REG_BUS, 0x20, 1},
-#if 1
+
+ static struct ov511_regvals aRegvalsNorm7610[] =
+ {{OV511_REG_BUS, 0x20, 0x01},
{OV511_REG_BUS, 0x52, 0x02},
{OV511_REG_BUS, 0x52, 0x00},
{OV511_REG_BUS, 0x31, 0x1f}, /* 0f */
@@ -1907,16 +2004,14 @@ static int ov511_configure(struct usb_ov511 *ov511)
{OV511_REG_BUS, 0x78, 0x06},
{OV511_REG_BUS, 0x79, 0x03},
-
{OV511_I2C_BUS, 0x10, 0xff},
{OV511_I2C_BUS, 0x16, 0x06},
- {OV511_I2C_BUS, 0x28, 0x24}, /* 24 */
+ {OV511_I2C_BUS, 0x28, 0x24},
{OV511_I2C_BUS, 0x2b, 0xac},
{OV511_I2C_BUS, 0x05, 0x00},
{OV511_I2C_BUS, 0x06, 0x00},
{OV511_I2C_BUS, 0x12, 0x00},
-// {OV511_I2C_BUS, 0x13, 0x00},
{OV511_I2C_BUS, 0x38, 0x81},
{OV511_I2C_BUS, 0x28, 0x24}, /* 0c */
{OV511_I2C_BUS, 0x05, 0x00},
@@ -1931,26 +2026,64 @@ static int ov511_configure(struct usb_ov511 *ov511)
{OV511_I2C_BUS, 0x29, 0x03}, /* 91 */
{OV511_I2C_BUS, 0x2a, 0x04},
{OV511_I2C_BUS, 0x2c, 0xfe},
- {OV511_I2C_BUS, 0x2d, 0x93}, /* d7 */
{OV511_I2C_BUS, 0x30, 0x71},
{OV511_I2C_BUS, 0x31, 0x60},
{OV511_I2C_BUS, 0x32, 0x26},
{OV511_I2C_BUS, 0x33, 0x20},
{OV511_I2C_BUS, 0x34, 0x48},
{OV511_I2C_BUS, 0x12, 0x24},
-// {OV511_I2C_BUS, 0x13, 0x01},
{OV511_I2C_BUS, 0x11, 0x01},
{OV511_I2C_BUS, 0x0c, 0x24},
{OV511_I2C_BUS, 0x0d, 0x24},
-#endif
{OV511_DONE_BUS, 0x0, 0x00},
};
- /* Set altsetting 0 */
- if (usb_set_interface(dev, ov511->iface, 0) < 0) {
- err("usb_set_interface error");
- return -EBUSY;
- }
+ static struct ov511_regvals aRegvalsNorm7620[] =
+ {{OV511_REG_BUS, 0x20, 0x01},
+ {OV511_REG_BUS, 0x52, 0x02},
+ {OV511_REG_BUS, 0x52, 0x00},
+ {OV511_REG_BUS, 0x31, 0x1f},
+ {OV511_REG_BUS, 0x70, 0x3f},
+ {OV511_REG_BUS, 0x71, 0x3f},
+ {OV511_REG_BUS, 0x72, 0x01},
+ {OV511_REG_BUS, 0x73, 0x01},
+ {OV511_REG_BUS, 0x74, 0x01},
+ {OV511_REG_BUS, 0x75, 0x01},
+ {OV511_REG_BUS, 0x76, 0x01},
+ {OV511_REG_BUS, 0x77, 0x01},
+ {OV511_REG_BUS, 0x78, 0x06},
+ {OV511_REG_BUS, 0x79, 0x03},
+
+ {OV511_I2C_BUS, 0x10, 0xff},
+ {OV511_I2C_BUS, 0x16, 0x06},
+ {OV511_I2C_BUS, 0x28, 0x24},
+ {OV511_I2C_BUS, 0x2b, 0xac},
+
+ {OV511_I2C_BUS, 0x12, 0x00},
+
+ {OV511_I2C_BUS, 0x28, 0x24},
+ {OV511_I2C_BUS, 0x05, 0x00},
+ {OV511_I2C_BUS, 0x0f, 0x05},
+ {OV511_I2C_BUS, 0x15, 0x01},
+ {OV511_I2C_BUS, 0x23, 0x00},
+ {OV511_I2C_BUS, 0x24, 0x10},
+ {OV511_I2C_BUS, 0x25, 0x8a},
+ {OV511_I2C_BUS, 0x26, 0xa2},
+ {OV511_I2C_BUS, 0x27, 0xe2},
+ {OV511_I2C_BUS, 0x29, 0x03},
+ {OV511_I2C_BUS, 0x2a, 0x00},
+ {OV511_I2C_BUS, 0x2c, 0xfe},
+ {OV511_I2C_BUS, 0x30, 0x71},
+ {OV511_I2C_BUS, 0x31, 0x60},
+ {OV511_I2C_BUS, 0x32, 0x26},
+ {OV511_I2C_BUS, 0x33, 0x20},
+ {OV511_I2C_BUS, 0x34, 0x48},
+ {OV511_I2C_BUS, 0x12, 0x24},
+ {OV511_I2C_BUS, 0x11, 0x01},
+ {OV511_I2C_BUS, 0x0c, 0x24},
+ {OV511_I2C_BUS, 0x0d, 0x24},
+ {OV511_DONE_BUS, 0x0, 0x00},
+ };
memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
@@ -1966,18 +2099,17 @@ static int ov511_configure(struct usb_ov511 *ov511)
if ((rc = ov511_write_regvals(dev, aRegvalsInit)))
return rc;
- if(ov7610_configure(dev) < 0) {
+ if(ov7610_configure(ov511) < 0) {
err("failed to configure OV7610");
goto error;
}
+ ov511_set_packet_size(ov511, 0);
+
/* Disable compression */
- if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
- err("disable compression: command failed");
+ if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0)
goto error;
- }
- ov511->compress = 0;
ov511->snap_enabled = snapshot;
/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
@@ -1990,15 +2122,27 @@ static int ov511_configure(struct usb_ov511 *ov511)
ov511->frame[1].bytes_read = 0;
/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
- if ((rc = ov511_write_regvals(dev, aRegvalsNorm))) goto error;
- if ((rc = ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
- VIDEO_PALETTE_RGB24, 0)) < 0) goto error;
+
+ if (ov511->sensor == SEN_OV7620) {
+ if (ov511_write_regvals(dev, aRegvalsNorm7620)) goto error;
+ }
+ else {
+ if (ov511_write_regvals(dev, aRegvalsNorm7610)) goto error;
+ }
+
+ if (ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ VIDEO_PALETTE_RGB24, 0) < 0) goto error;
if (autoadjust) {
if (ov511_i2c_write(dev, 0x13, 0x01) < 0) goto error;
+ if (ov511_i2c_write(dev, 0x2d,
+ ov511->sensor==SEN_OV7620?0x91:0x93) < 0) goto error;
}
else {
- if (ov511_i2c_write(dev, 0x13, 0x00) < 0 ) goto error;
+ if (ov511_i2c_write(dev, 0x13, 0x00) < 0) goto error;
+ if (ov511_i2c_write(dev, 0x2d,
+ ov511->sensor==SEN_OV7620?0x81:0x83) < 0) goto error;
+ ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
}
return 0;
@@ -2009,6 +2153,7 @@ error:
&dev->actconfig->interface[ov511->iface]);
kfree(ov511);
+ ov511 = NULL;
return -EBUSY;
}
@@ -2027,10 +2172,11 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
interface = &dev->actconfig->interface[ifnum].altsetting[0];
- /* Is it an OV511? */
+ /* Is it an OV511/OV511+? */
if (dev->descriptor.idVendor != 0x05a9)
return NULL;
- if (dev->descriptor.idProduct != 0x0511)
+ if (dev->descriptor.idProduct != 0x0511
+ && dev->descriptor.idProduct != 0xA511)
return NULL;
/* Checking vendor/product should be enough, but what the hell */
@@ -2039,9 +2185,6 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
if (interface->bInterfaceSubClass != 0x00)
return NULL;
- /* We found one */
- printk(KERN_INFO "ov511: USB OV511-based camera found\n");
-
if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
err("couldn't kmalloc ov511 struct");
return NULL;
@@ -2052,15 +2195,24 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
ov511->dev = dev;
ov511->iface = interface->bInterfaceNumber;
+ if (dev->descriptor.idProduct == 0x0511) {
+ info("USB OV511 camera found");
+ ov511->bridge = BRG_OV511;
+ }
+ else if (dev->descriptor.idProduct == 0xA511) {
+ info("USB OV511+ camera found");
+ ov511->bridge = BRG_OV511PLUS;
+ }
+
rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
if (rc < 0) {
err("Unable to read camera bridge registers");
- return NULL;
+ goto error;
}
switch(ov511->customid = rc) {
case 0: /* This also means that no custom ID was set */
- printk("ov511: Camera is probably a MediaForte MV300\n");
+ printk("ov511: Camera is a generic model (no ID)\n");
break;
case 3:
printk("ov511: Camera is a D-Link DSB-C300\n");
@@ -2077,6 +2229,11 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
case 36:
printk("ov511: Camera is a Koala-Cam\n");
break;
+ case 38:
+ printk("ov511: Camera is a Lifeview USB Life TV\n");
+ printk("ov511: This device is not supported, exiting...\n");
+ goto error;
+ break;
case 100:
printk("ov511: Camera is a Lifeview RoboCam\n");
break;
@@ -2090,9 +2247,13 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
err("Specific camera type (%d) not recognized", rc);
err("Please contact mmcclelland@delphi.com to request");
err("support for your camera.");
- return NULL;
}
+// if (ov511->bridge == BRG_OV511PLUS) {
+// err("Sorry, the OV511+ chip is not supported yet");
+// goto error;
+// }
+
if (!ov511_configure(ov511)) {
ov511->user=0;
init_MUTEX(&ov511->lock); /* to 1 == available */
@@ -2100,10 +2261,18 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
}
else {
err("Failed to configure camera");
- return NULL;
+ goto error;
}
return ov511;
+
+error:
+ if (ov511) {
+ kfree(ov511);
+ ov511 = NULL;
+ }
+
+ return NULL;
}
static void ov511_disconnect(struct usb_device *dev, void *ptr)
@@ -2147,7 +2316,7 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
usb_unlink_urb(ov511->sbuf[0].urb);
usb_free_urb(ov511->sbuf[0].urb);
ov511->sbuf[0].urb = NULL;
- }
+ }
/* Free the memory */
if (!ov511->user) {
diff --git a/drivers/usb/ov511.h b/drivers/usb/ov511.h
index 6a4a332bf..7e679eb40 100644
--- a/drivers/usb/ov511.h
+++ b/drivers/usb/ov511.h
@@ -1,8 +1,6 @@
#ifndef __LINUX_OV511_H
#define __LINUX_OV511_H
-//#include <linux/list.h>
-
#define OV511_DEBUG /* Turn on debug messages */
#ifdef OV511_DEBUG
@@ -75,14 +73,16 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51
#define OV511_REG_SYSTEM_SNAPSHOT 0x52
#define OV511_REG_SYSTEM_INIT 0x53
+#define OV511_REG_SYSTEM_PWR_CLK 0x54 /* OV511+ only */
+#define OV511_REG_SYSTEM_LED_CTL 0x55 /* OV511+ only */
#define OV511_REG_SYSTEM_USER_DEFINED 0x5E
#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F
/* OmniCE register numbers */
-#define OV511_OMNICE_PREDICATION_HORIZ_Y 0x70
-#define OV511_OMNICE_PREDICATION_HORIZ_UV 0x71
-#define OV511_OMNICE_PREDICATION_VERT_Y 0x72
-#define OV511_OMNICE_PREDICATION_VERT_UV 0x73
+#define OV511_OMNICE_PREDICTION_HORIZ_Y 0x70
+#define OV511_OMNICE_PREDICTION_HORIZ_UV 0x71
+#define OV511_OMNICE_PREDICTION_VERT_Y 0x72
+#define OV511_OMNICE_PREDICTION_VERT_UV 0x73
#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74
#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75
#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76
@@ -94,15 +94,25 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define OV511_OMNICE_UV_LUT_BEGIN 0xA0
#define OV511_OMNICE_UV_LUT_END 0xBF
-/* Alternate numbers for various max packet sizes */
-#define OV511_ALTERNATE_SIZE_992 0
-#define OV511_ALTERNATE_SIZE_993 1
-#define OV511_ALTERNATE_SIZE_768 2
-#define OV511_ALTERNATE_SIZE_769 3
-#define OV511_ALTERNATE_SIZE_512 4
-#define OV511_ALTERNATE_SIZE_513 5
-#define OV511_ALTERNATE_SIZE_257 6
-#define OV511_ALTERNATE_SIZE_0 7
+/* Alternate numbers for various max packet sizes (OV511 only) */
+#define OV511_ALT_SIZE_992 0
+#define OV511_ALT_SIZE_993 1
+#define OV511_ALT_SIZE_768 2
+#define OV511_ALT_SIZE_769 3
+#define OV511_ALT_SIZE_512 4
+#define OV511_ALT_SIZE_513 5
+#define OV511_ALT_SIZE_257 6
+#define OV511_ALT_SIZE_0 7
+
+/* Alternate numbers for various max packet sizes (OV511+ only) */
+#define OV511PLUS_ALT_SIZE_0 0
+#define OV511PLUS_ALT_SIZE_33 1
+#define OV511PLUS_ALT_SIZE_129 2
+#define OV511PLUS_ALT_SIZE_257 3
+#define OV511PLUS_ALT_SIZE_385 4
+#define OV511PLUS_ALT_SIZE_513 5
+#define OV511PLUS_ALT_SIZE_769 6
+#define OV511PLUS_ALT_SIZE_961 7
/* ov7610 registers */
#define OV7610_REG_GAIN 0x00
@@ -154,7 +164,8 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define SCRATCH_BUF_SIZE 384
#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC 993 /* FIXME - Shouldn't be hardcoded */
+#define FRAME_SIZE_PER_DESC 993 /* FIXME - Deprecated */
+#define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */
// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
@@ -171,6 +182,19 @@ int usb_ov511_reg_write(struct usb_device *dev,
unsigned char reg,
unsigned char value);
+/* Bridge types */
+enum {
+ BRG_OV511,
+ BRG_OV511PLUS,
+};
+
+/* Sensor types */
+enum {
+ SEN_UNKNOWN,
+ SEN_OV7610,
+ SEN_OV7620,
+ SEN_OV7620AE,
+};
enum {
STATE_SCANNING, /* Scanning for start */
@@ -214,7 +238,7 @@ struct ov511_frame {
int hdrheight; /* Height */
int sub_flag; /* Sub-capture mode for this frame? */
- int format; /* Format for this frame */
+ int format; /* Format for this frame */
int segsize; /* How big is each segment from the camera? */
volatile int grabstate; /* State of grabbing */
@@ -274,6 +298,11 @@ struct usb_ov511 {
wait_queue_head_t wq; /* Processes waiting */
int snap_enabled; /* Snapshot mode enabled */
+
+ int bridge; /* Type of bridge (OV511 or OV511+) */
+ int sensor; /* Type of image sensor chip */
+
+ int packet_size; /* Frame size per isoc desc */
};
#endif
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 764f1c055..d16a65725 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -16,11 +16,13 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.3.5 2000/03/21 Written by Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Manolov (petkan@spct.net)\n";
#define PEGASUS_MTU 1500
-#define PEGASUS_MAX_MTU 1536
+#define PEGASUS_MAX_MTU 1536
+#define SROM_WRITE 0x01
+#define SROM_READ 0x02
#define PEGASUS_TX_TIMEOUT (HZ*5)
#define ALIGN(x) x __attribute__((aligned(16)))
@@ -51,12 +53,18 @@ 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 }
+ {"Billionton USB-100", 0x08dd, 0x0986, NULL},
+ {"Corega FEter USB-TX", 0x7aa, 0x0004, NULL},
+ {"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, NULL},
+ {"D-Link DSB-650TX", 0x2001, 0x4001, NULL},
+ {"D-Link DSB-650TX", 0x2001, 0x4002, NULL},
+ {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL},
+ {"Linksys USB100TX", 0x066b, 0x2203, NULL},
+ {"Linksys USB100TX", 0x066b, 0x2204, NULL},
+ {"SMC 202 USB Ethernet", 0x0707, 0x0200, NULL},
+ {"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, NULL},
+ {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL},
+ {NULL, 0, 0, NULL}
};
@@ -105,10 +113,10 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd
return 1;
}
-static int pegasus_read_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata)
+static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
{
int i;
- __u8 data[4] = { index, 0, 0, 0x02 };
+ __u8 data[4] = { index, 0, 0, direction };
pegasus_set_registers(dev, 0x20, 4, data);
for (i = 0; i < 100; i++) {
@@ -120,7 +128,7 @@ static int pegasus_read_srom_word(struct usb_device *dev, __u8 index, __u16 *ret
}
}
- warn("read_srom_word() failed");
+ warn("pegasus_rw_srom_word() failed");
return 1;
}
@@ -128,7 +136,7 @@ static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
{
int i;
for (i = 0; i < 3; i++)
- if (pegasus_read_srom_word(dev, i, (__u16 *)&id[i * 2]))
+ if (pegasus_rw_srom_word(dev,i,(__u16 *)&id[i * 2],SROM_READ))
return 1;
return 0;
}
@@ -170,8 +178,9 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
return 2;
if ((~temp & 4) && !loopback) {
- err("link NOT established - %x", temp);
- return 3;
+ warn("%s: link NOT established (0x%x), check the cable.",
+ dev->name, temp);
+ /* return 3; FIXME */
}
if (pegasus_read_phy_word(usb, 5, &partmedia))
@@ -376,13 +385,14 @@ static void pegasus_set_rx_mode(struct net_device *net)
if (net->flags & IFF_PROMISC) {
info("%s: Promiscuous mode enabled", net->name);
- pegasus_set_register(pegasus->usb, 2, 0x04);
+/* pegasus_set_register(pegasus->usb, 2, 0x04); FIXME */
} else if ((net->mc_count > multicast_filter_limit) ||
(net->flags & IFF_ALLMULTI)) {
pegasus_set_register(pegasus->usb, 0, 0xfa);
pegasus_set_register(pegasus->usb, 2, 0);
+ info("%s set allmulti", net->name);
} else {
- dbg("%s: set Rx mode", net->name);
+ info("%s: set Rx mode", net->name);
}
netif_wake_queue(net);
@@ -395,18 +405,19 @@ static int check_device_ids( __u16 vendor, __u16 product )
while ( usb_dev_id[i].name ) {
if ( (usb_dev_id[i].vendor == vendor) &&
(usb_dev_id[i].device == product) )
- return 0;
+ return i;
i++;
}
- return 1;
+ return -1;
}
static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
{
struct net_device *net;
struct pegasus *pegasus;
+ int dev_indx;
- if ( check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct) ) {
+ if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) {
return NULL;
}
@@ -449,11 +460,11 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2),
pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
pegasus);
- FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 0),
+ FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
pegasus->intr_buff, 8, pegasus_irq, pegasus, 250);
- printk(KERN_INFO "%s: ADMtek AN986 Pegasus usb device\n", net->name);
+ printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
return pegasus;
}
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 4c100f16c..c1a7ddb67 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -160,10 +160,13 @@ static int usblp_open(struct inode *inode, struct file *file)
if (usblp->used)
return -EBUSY;
- if ((retval = usblp_check_status(usblp)))
+ MOD_INC_USE_COUNT;
+
+ if ((retval = usblp_check_status(usblp))) {
+ MOD_DEC_USE_COUNT;
return retval;
+ }
- MOD_INC_USE_COUNT;
usblp->used = 1;
file->private_data = usblp;
@@ -179,17 +182,18 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
- MOD_DEC_USE_COUNT;
usblp->used = 0;
if (usblp->dev) {
usb_unlink_urb(&usblp->readurb);
usb_unlink_urb(&usblp->writeurb);
+ MOD_DEC_USE_COUNT;
return 0;
}
usblp_table[usblp->minor] = NULL;
kfree(usblp);
+ MOD_DEC_USE_COUNT;
return 0;
}
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index 4c69d4221..666752f76 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -1,7 +1,7 @@
/* -*- linux-c -*- */
/*
- * Driver for USB Scanners (linux-2.3.42)
+ * Driver for USB Scanners (linux-2.3.99-pre3-7)
*
* Copyright (C) 1999, 2000 David E. Nelson
*
@@ -148,8 +148,29 @@
* - Increased the timeout parameter in read_scanner() to 120 Secs.
*
*
+ * 0.4.2 3/23/2000
+ *
+ * - Added Umax 1236U ID. Thanks to Philipp Baer <ph_baer@npw.net>.
+ * - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
+ * Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
+ * - Fixed error number reported for non-existant devices. Thanks to
+ * Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
+ * - Added Acer Prisascan 620U ID's. Thanks to Joao <joey@knoware.nl>.
+ * - Replaced __initcall() with module_init()/module_exit(). Updates
+ * from patch-2.3.48.
+ * - Replaced file_operations structure with new syntax. Updates
+ * from patch-2.3.49.
+ * - Changed #include "usb.h" to #include <linux/usb.h>
+ * - Added #define SCN_IOCTL to exclude development areas
+ * since 2.4.x is about to be released. This mainly affects the
+ * ioctl() stuff. See scanner.h for more details.
+ * - Changed the return value for signal_pending() from -ERESTARTSYS to
+ * -EINTR.
+ *
+ *
* TODO
*
+ * - Performance
* - Select/poll methods
* - More testing
* - Proper registry/assignment for LM9830 ioctl's
@@ -214,7 +235,7 @@ open_scanner(struct inode * inode, struct file * file)
if (!p_scn_table[scn_minor]) {
err("open_scanner(%d): invalid scn_minor", scn_minor);
- return -ENOIOCTLCMD;
+ return -ENODEV;
}
scn = p_scn_table[scn_minor];
@@ -255,7 +276,7 @@ close_scanner(struct inode * inode, struct file * file)
if (!p_scn_table[scn_minor]) {
err("close_scanner(%d): invalid scn_minor", scn_minor);
- return -ENOIOCTLCMD;
+ return -ENODEV;
}
scn = p_scn_table[scn_minor];
@@ -279,6 +300,8 @@ write_scanner(struct file * file, const char * buffer,
ssize_t bytes_written = 0; /* Overall count of bytes written */
ssize_t ret = 0;
+ kdev_t scn_minor;
+
int this_write; /* Number of bytes to write */
int partial; /* Number of bytes successfully written */
int result = 0;
@@ -287,6 +310,8 @@ write_scanner(struct file * file, const char * buffer,
scn = file->private_data;
+ scn_minor = scn->scn_minor;
+
obuf = scn->obuf;
dev = scn->scn_dev;
@@ -294,7 +319,7 @@ write_scanner(struct file * file, const char * buffer,
while (count > 0) {
if (signal_pending(current)) {
- ret = -ERESTARTSYS;
+ ret = -EINTR;
break;
}
@@ -306,14 +331,14 @@ write_scanner(struct file * file, const char * buffer,
}
result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
- dbg("write stats(%d): result:%d this_write:%d partial:%d", scn->scn_minor, result, this_write, partial);
+ dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
warn("write_scanner: NAK recieved.");
ret = -ETIME;
break;
} else if (result < 0) { /* We should not get any I/O errors */
- warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn->scn_minor, result);
+ warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result);
ret = -EIO;
break;
}
@@ -322,7 +347,7 @@ write_scanner(struct file * file, const char * buffer,
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
- printk(KERN_DEBUG "dump(%d): ", scn->scn_minor);
+ printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", obuf[cnt]);
}
@@ -355,8 +380,10 @@ read_scanner(struct file * file, char * buffer,
struct scn_usb_data *scn;
struct usb_device *dev;
- ssize_t bytes_read = 0; /* Overall count of bytes_read */
- ssize_t ret = 0;
+ ssize_t bytes_read; /* Overall count of bytes_read */
+ ssize_t ret;
+
+ kdev_t scn_minor;
int partial; /* Number of bytes successfully read */
int this_read; /* Max number of bytes to read */
@@ -366,29 +393,32 @@ read_scanner(struct file * file, char * buffer,
scn = file->private_data;
+ scn_minor = scn->scn_minor;
+
ibuf = scn->ibuf;
dev = scn->scn_dev;
bytes_read = 0;
+ ret = 0;
while (count) {
if (signal_pending(current)) {
- ret = -ERESTARTSYS;
+ ret = -EINTR;
break;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, 120*HZ);
- dbg("read stats(%d): result:%d this_read:%d partial:%d", scn->scn_minor, result, this_read, partial);
+ dbg("read stats(%d): result:%d this_read:%d partial:%d", scn_minor, result, this_read, partial);
if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
- warn("read_scanner(%d): NAK received", scn->scn_minor);
+ warn("read_scanner(%d): NAK received", scn_minor);
ret = -ETIME;
break;
} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
- warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn->scn_minor, (int)result);
+ warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
ret = -EIO;
break;
}
@@ -397,7 +427,7 @@ read_scanner(struct file * file, char * buffer,
if (partial) {
unsigned char cnt, cnt_max;
cnt_max = (partial > 24) ? 24 : partial;
- printk(KERN_DEBUG "dump(%d): ", scn->scn_minor);
+ printk(KERN_DEBUG "dump(%d): ", scn_minor);
for (cnt=0; cnt < cnt_max; cnt++) {
printk("%X ", ibuf[cnt]);
}
@@ -492,15 +522,17 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
if (dev->descriptor.idVendor == 0x1606) { /* Umax */
if (dev->descriptor.idProduct == 0x0010 || /* Astra 1220U */
- dev->descriptor.idProduct == 0x0030) { /* Astra 2000U */
+ dev->descriptor.idProduct == 0x0030 || /* Astra 2000U */
+ dev->descriptor.idProduct == 0x0002) { /* Astra 1236U */
valid_device = 1;
break;
}
}
if (dev->descriptor.idVendor == 0x04b8) { /* Seiko/Epson Corp. */
- if (dev->descriptor.idProduct == 0x0101 || /* Perfection 636 */
- dev->descriptor.idProduct == 0x0104) { /* Perfection 1200U */
+ if (dev->descriptor.idProduct == 0x0101 || /* Perfection 636U and 636Photo */
+ dev->descriptor.idProduct == 0x0103 || /* Perfection 610 */
+ dev->descriptor.idProduct == 0x0104) { /* Perfection 1200U and 1200Photo */
valid_device = 1;
break;
}
@@ -526,15 +558,56 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
}
}
+ if (dev->descriptor.idVendor == 0x0461) { /* Primax/Colorado */
+ if (dev->descriptor.idProduct == 0x0300 || /* G2-300 #1 */
+ dev->descriptor.idProduct == 0x0380 || /* G2-600 #1 */
+ dev->descriptor.idProduct == 0x0301 || /* G2E-300 */
+ dev->descriptor.idProduct == 0x0381 || /* ReadyScan 636i */
+ dev->descriptor.idProduct == 0x0302 || /* G2-300 #2 */
+ dev->descriptor.idProduct == 0x0382 || /* G2-600 #2 */
+ dev->descriptor.idProduct == 0x0303 || /* G2E-300 */
+ dev->descriptor.idProduct == 0x0383 || /* G2E-600 */
+ dev->descriptor.idProduct == 0x0340 || /* Colorado USB 9600 */
+ dev->descriptor.idProduct == 0x0360 || /* Colorado USB 19200 */
+ dev->descriptor.idProduct == 0x0341 || /* Colorado 600u */
+ dev->descriptor.idProduct == 0x0361) { /* Colorado 1200u */
+ valid_device = 1;
+ break;
+ }
+ }
+
+ if (dev->descriptor.idVendor == 0x04a7) { /* Visioneer */
+ if (dev->descriptor.idProduct == 0x0221 || /* OneTouch 5300 */
+ dev->descriptor.idProduct == 0x0221 || /* OneTouch 7600 */
+ dev->descriptor.idProduct == 0x0231) { /* 6100 */
+ valid_device = 1;
+ break;
+ }
+ }
+
+ if (dev->descriptor.idVendor == 0x0458) { /* Genius */
+ if(dev->descriptor.idProduct == 0x2001) { /* ColorPage-Vivid Pro */
+ valid_device = 1;
+ break;
+ }
+ }
+
+ if (dev->descriptor.idVendor == 0x04a5) { /* Acer */
+ if(dev->descriptor.idProduct == 0x2060) { /* Prisa Acerscan 620U */
+ valid_device = 1;
+ break;
+ }
+ }
+
if (dev->descriptor.idVendor == vendor && /* User specified */
dev->descriptor.idProduct == product) { /* User specified */
valid_device = 1;
break;
}
-
-
+
+
} while (0);
-
+
if (!valid_device)
return NULL; /* We didn't find anything pleasing */
@@ -714,6 +787,7 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
kfree (scn);
}
+#ifdef SCN_IOCTL
static int
ioctl_scanner(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
@@ -728,7 +802,7 @@ ioctl_scanner(struct inode *inode, struct file *file,
if (!p_scn_table[scn_minor]) {
err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
- return -ENOIOCTLCMD;
+ return -ENODEV;
}
dev = p_scn_table[scn_minor]->scn_dev;
@@ -790,12 +864,15 @@ ioctl_scanner(struct inode *inode, struct file *file,
}
return 0;
}
+#endif /* SCN_IOCTL */
static struct
file_operations usb_scanner_fops = {
read: read_scanner,
write: write_scanner,
+#ifdef SCN_IOCTL
ioctl: ioctl_scanner,
+#endif /* SCN_IOCTL */
open: open_scanner,
release: close_scanner,
};
@@ -810,12 +887,14 @@ usb_driver scanner_driver = {
SCN_BASE_MNR
};
-void __exit usb_scanner_exit(void)
+void __exit
+usb_scanner_exit(void)
{
usb_deregister(&scanner_driver);
}
-int __init usb_scanner_init(void)
+int __init
+usb_scanner_init (void)
{
if (usb_register(&scanner_driver) < 0)
return -1;
diff --git a/drivers/usb/scanner.h b/drivers/usb/scanner.h
index ed8320424..d4dd607b7 100644
--- a/drivers/usb/scanner.h
+++ b/drivers/usb/scanner.h
@@ -6,8 +6,15 @@
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
+
// #define DEBUG
+
+/* Enable to activate the ioctl interface. This is mainly meant for */
+/* development purposes until an ioctl number is officially registered */
+// #define SCN_IOCTL
+
#include <linux/usb.h>
+// #include "usb.h"
/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 02bd7aad6..95a686e7a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -1,67 +1,11 @@
#
-# Makefile for the kernel USB device drivers.
+# Makefile for the USB serial device drivers.
#
-# Subdirs.
-
-SUB_DIRS :=
-MOD_SUB_DIRS := $(SUB_DIRS)
-MOD_IN_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
-# The target object and module list name.
-
-O_TARGET := serial.o
+O_TARGET := usb-serial.o
M_OBJS := usb-serial.o
-O_OBJS := usb-serial.o
+O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o
MOD_LIST_NAME := USB_SERIAL_MODULES
-# Objects that export symbols.
-
-# Multipart objects.
-
-# Optional parts of multipart objects.
-
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_USB_SERIAL) += usb-serial.o
-
-# Extract lists of the multi-part drivers.
-# The 'int-*' lists are the intermediate files used to build the multi's.
-
-multi-y := $(filter $(list-multi), $(obj-y))
-multi-m := $(filter $(list-multi), $(obj-m))
-int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-
-# Files that are both resident and modular: remove from modular.
-
-obj-m := $(filter-out $(obj-y), $(obj-m))
-int-m := $(filter-out $(int-y), $(int-m))
-
-# Take multi-part drivers out of obj-y and put components in.
-
-obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y)
-
-# Translate to Rules.make lists.
-
-O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
-OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
-M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-
-# The global Rules.make.
-
include $(TOPDIR)/Rules.make
-# Link rules for multi-part drivers.
-
diff --git a/drivers/usb/serial/ezusb_convert.pl b/drivers/usb/serial/ezusb_convert.pl
index b4f08b2d7..3c69e4c1c 100644
--- a/drivers/usb/serial/ezusb_convert.pl
+++ b/drivers/usb/serial/ezusb_convert.pl
@@ -27,6 +27,8 @@ while (<STDIN>) {
push(@records, [$addr, \@bytes]);
}
+@sorted_records = sort { $a->[0] <=> $b->[0] } @records;
+
print <<"EOF";
/*
* ${basename}_fw.h
@@ -39,7 +41,7 @@ print <<"EOF";
EOF
print "static const struct ezusb_hex_record ${basename}_firmware[] = {\n";
-foreach $r (@records) {
+foreach $r (@sorted_records) {
printf("{ 0x%04x,\t%d,\t{", $r->[0], scalar(@{$r->[1]}));
print join(", ", map {sprintf('0x%02x', $_);} @{$r->[1]});
print "} },\n";
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
new file mode 100644
index 000000000..151c4bfe7
--- /dev/null
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -0,0 +1,728 @@
+/*
+ * USB FTDI SIO driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ * Bill Ryder (bryder@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 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (04/04/2000) Bill Ryder
+ * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
+ * handled elsewhere in the serial driver chain).
+ *
+ * (03/30/2000) Bill Ryder
+ * Implemented lots of ioctls
+ * Fixed a race condition in write
+ * Changed some dbg's to errs
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
+/* Thanx to FTDI for so kindly providing details of the protocol required */
+/* to talk to the device */
+
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "ftdi_sio.h"
+
+#define FTDI_VENDOR_ID 0x0403
+#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372
+
+/* function prototypes for a FTDI serial converter */
+static int ftdi_sio_startup (struct usb_serial *serial);
+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_write_bulk_callback (struct urb *urb);
+static void ftdi_sio_read_bulk_callback (struct urb *urb);
+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;
+static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID;
+struct usb_serial_device_type ftdi_sio_device = {
+ name: "FTDI SIO",
+ idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */
+ idProduct: &ftdi_sio_product_id, /* the FTDI SIO product id */
+ needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_interrupt_in: 0,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: ftdi_sio_open,
+ close: ftdi_sio_close,
+ write: ftdi_sio_write,
+ read_bulk_callback: ftdi_sio_read_bulk_callback,
+ write_bulk_callback: ftdi_sio_write_bulk_callback,
+ ioctl: ftdi_sio_ioctl,
+ set_termios: ftdi_sio_set_termios,
+ startup: ftdi_sio_startup,
+};
+
+
+/*
+ * ***************************************************************************
+ * FTDI SIO Serial Converter specific driver functions
+ * ***************************************************************************
+ *
+ * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code
+ * Thanx to FTDI for so kindly providing details of the protocol required
+ * to talk to the device - http://www.ftdi.co.uk
+ *
+ * Tested as at this version - other stuff might work
+ * 23 March 2000
+ * Works:
+ * Baudrates - 9600, 38400,19200, 57600, 115200
+ * TIOCMBIC - TIOCM_DTR / TIOCM_RTS
+ * TIOCMBIS - TIOCM_DTR / TIOCM_RTS
+ * TIOCMSET - DTR on/RTSon / DTR off, RTS off
+ * no parity:CS8 even parity:CS7 odd parity:CS7
+ * CRTSCTS flow control
+ *
+ * Pilot-xfer zillions of times
+ *
+ * cu works with dir option
+ *
+ * Not Tested (ie might not work):
+ * xon/xoff flow control
+ * ppp (modem handling in general)
+ *
+ * KNOWN BUGS:
+ * Multiple Opens
+ * ==============
+ * Seems to have problem when opening an already open port,
+ * Get I/O error on first attempt, then it lets you in.
+ * Need to do proper usage counting - keep registered callbacks for first opener.
+ *
+ * Reproduce with:
+ * cu -l /dev/ttyUSB0 dir
+ * whilst cu is running do:
+ * stty -a < /dev/ttyUSB0
+ *
+ * from stty get: 'bash: /dev/ttyUSB0: Invalid argument '
+ * from cu get
+ * write: Invalid argument
+ *
+ * Initialisation Problem
+ * ======================
+ * Pilot transfer required me to run the serial_loopback program before it would work.
+ * Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio
+ *
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int ftdi_sio_startup (struct usb_serial *serial)
+{
+ init_waitqueue_head(&serial->write_wait);
+
+ return (0);
+}
+
+static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_open */
+ struct termios tmp_termios;
+ struct usb_serial *serial = port->serial;
+ char buf[1]; /* Needed for the usb_control_msg I think */
+
+ dbg("ftdi_sio_open port %d", port->number);
+
+ /* FIXME - multiple concurrent opens cause trouble */
+ if (port->active) {
+ err ("port already open");
+ return -EINVAL;
+ }
+ port->active = 1; /* FIXME - For multiple open this should increment */
+
+ /* See ftdi_sio.h for description of what is reset */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_SIO,
+ 0, buf, 0, WDR_TIMEOUT);
+
+ /* Setup termios */
+ port->tty->termios->c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+
+ ftdi_sio_set_termios(port, &tmp_termios);
+
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("error from flowcontrol urb");
+ return(-EINVAL);
+ }
+
+ /* Turn on RTS and DTR since we are not flow controlling*/
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_HIGH, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from DTR HIGH urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_HIGH, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from RTS HIGH urb");
+ }
+
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ err("usb_submit_urb(read bulk) failed");
+
+ return (0);
+} /* ftdi_sio_open */
+
+
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_close */
+ struct usb_serial *serial = port->serial;
+ unsigned int c_cflag = port->tty->termios->c_cflag;
+ char buf[1];
+
+ dbg("ftdi_sio_close port %d", port->number);
+
+ if (c_cflag & HUPCL){
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("error from flowcontrol urb");
+ }
+
+ /* drop DTR */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from DTR LOW urb");
+ }
+ /* drop RTS */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from RTS LOW urb");
+ }
+ }
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+} /* ftdi_sio_close */
+
+
+
+/* The ftdi_sio requires the first byte to have:
+ * B0 1
+ * B1 0
+ * B2..7 length of message excluding byte 0
+ */
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
+{ /* ftdi_sio_write */
+ struct usb_serial *serial = port->serial;
+ const int data_offset = 1;
+ int rc;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
+
+ if (count == 0) {
+ err("write request of 0 bytes");
+ return 0;
+ }
+
+ /* only do something if we have a bulk out endpoint */
+ if (serial->num_bulk_out) {
+ unsigned char *first_byte = port->write_urb->transfer_buffer;
+
+ /* Was seeing a race here, got a read callback, then write callback before
+ hitting interuptible_sleep_on - so wrapping in add_wait_queue stuff */
+
+ add_wait_queue(&serial->write_wait, &wait);
+ set_current_state (TASK_INTERRUPTIBLE);
+ while (port->write_urb->status == -EINPROGRESS) {
+ dbg("ftdi_sio - write in progress - retrying");
+ if (0 /* file->f_flags & O_NONBLOCK */) {
+ rc = -EAGAIN;
+ goto err;
+ }
+ if (signal_pending(current)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&serial->write_wait, &wait);
+ rc = -ERESTARTSYS;
+ goto err;
+ }
+ schedule();
+ }
+ remove_wait_queue(&serial->write_wait, &wait);
+ set_current_state(TASK_RUNNING);
+
+ count += data_offset;
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+ if (count == 0) {
+ return 0;
+ }
+
+ /* Copy in the data to send */
+ if (from_user) {
+ copy_from_user(port->write_urb->transfer_buffer + data_offset ,
+ buf, count - data_offset );
+ }
+ else {
+ 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 = 1 | ((count-data_offset) << 2) ;
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+
+ if (count) {
+ int i;
+ printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
+ printk ( "0x%02x ", first_byte[i]);
+ if (first_byte[i] > ' ' && first_byte[i] < '~') {
+ printk( "%c ", first_byte[i]);
+ } else {
+ printk( " ");
+ }
+ }
+
+
+ printk ( "\n");
+ }
+
+#endif
+ /* send the data out the bulk port */
+ port->write_urb->transfer_buffer_length = count;
+
+ if (usb_submit_urb(port->write_urb))
+ err("usb_submit_urb(write bulk) failed");
+
+ dbg("write returning: %d", count - data_offset);
+ return (count - data_offset);
+ }
+
+ /* no bulk out, so return 0 bytes written */
+ return 0;
+ err: /* error exit */
+ return(rc);
+} /* ftdi_sio_write */
+
+static void ftdi_sio_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty = port->tty;
+
+ dbg("ftdi_sio_write_bulk_callback");
+
+ if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ wake_up_interruptible(&serial->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ return;
+} /* ftdi_sio_write_bulk_callback */
+
+static void ftdi_sio_read_bulk_callback (struct urb *urb)
+{ /* ftdi_sio_serial_buld_callback */
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty = port->tty ;
+ unsigned char *data = urb->transfer_buffer;
+
+ const int data_offset = 2;
+ int i;
+
+ dbg("ftdi_sio read 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;
+ }
+
+ /* TO DO -- check for hung up line and handle appropriately: */
+ /* send hangup (need to find out how to do this) */
+
+
+ if (urb->status) {
+ /* This will happen at close every time so it is a dbg not an err */
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ if (urb->actual_length > 2) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ( "0x%.2x ", data[i]);
+ if (data[i] > ' ' && data[i] < '~') {
+ printk( "%c ", data[i]);
+ } else {
+ printk( " ");
+ }
+ }
+ printk ( "\n");
+ } else {
+ dbg("Just status");
+ }
+#endif
+
+
+ if (urb->actual_length > data_offset) {
+ for (i = data_offset ; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ err("failed resubmitting read urb");
+
+ return;
+} /* ftdi_sio_serial_read_bulk_callback */
+
+/* As I understand this - old_termios contains the original termios settings */
+/* and tty->termios contains the new setting to be used */
+/* */
+/* WARNING: set_termios calls this with old_termios in kernel space */
+
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{ /* ftdi_sio_set_termios */
+ 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->number);
+
+
+ /* FIXME -For this cut I don't care if the line is really changing or
+ not - so just do the change regardless - should be able to
+ compare old_termios and tty->termios */
+ /* NOTE These routines can get interrupted by
+ ftdi_sio_read_bulk_callback - need to examine what this
+ means - don't see any problems yet */
+
+ /* Set number of data bits, parity, stop bits */
+
+ urb_value = 0;
+ urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
+ FTDI_SIO_SET_DATA_STOP_BITS_1);
+ urb_value |= (cflag & PARENB ?
+ (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
+ FTDI_SIO_SET_DATA_PARITY_EVEN) :
+ FTDI_SIO_SET_DATA_PARITY_NONE);
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS5: urb_value |= 5; dbg("Setting CS5"); break;
+ case CS6: urb_value |= 6; dbg("Setting CS6"); break;
+ case CS7: urb_value |= 7; dbg("Setting CS7"); break;
+ case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+ default:
+ err("CSIZE was set but not CS5-CS8");
+ }
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, 100) < 0) {
+ err("FAILED to set databits/stopbits/parity");
+ }
+
+ /* Now do the baudrate */
+
+ switch(cflag & CBAUD){
+ case B0: break; /* Handled below */
+ case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+ case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+ case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+ case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+ case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+ case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+ case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+ case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+ case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+ case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+ default: dbg("FTDI_SIO does not support the baudrate requested");
+ /* FIXME - how to return an error for this? */ break;
+ }
+ if ((cflag & CBAUD) == B0 ) {
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("error from disable flowcontrol urb");
+ }
+ /* Drop RTS and DTR */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from DTR LOW urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("Error from RTS LOW urb");
+ }
+
+ } else {
+ if (usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BAUDRATE_REQUEST,
+ FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+ urb_value, 0,
+ buf, 0, 100) < 0) {
+ err("urb failed to set baurdrate");
+ }
+ }
+ /* Set flow control */
+ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
+ if (cflag & CRTSCTS) {
+ dbg("Setting to CRTSCTS flow control");
+ if (usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0 , FTDI_SIO_RTS_CTS_HS,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("urb failed to set to rts/cts flow control");
+ }
+
+ } else {
+ /* CHECK Assuming XON/XOFF handled by stack - not by device */
+ /* Disable flow control */
+ dbg("Turning off hardware flow control");
+ if (usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, WDR_TIMEOUT) < 0) {
+ err("urb failed to clear flow control");
+ }
+
+ }
+ return;
+} /* ftdi_sio_set_termios */
+
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ 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 - cmd 0x%04x", cmd);
+
+ /* Based on code from acm.c and others */
+ switch (cmd) {
+
+ case TIOCMGET:
+ dbg("TIOCMGET");
+ /* Request the status from the device */
+ if ((ret = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+ 0, 0,
+ buf, 1, HZ * 5)) < 0 ) {
+ dbg("Get not get modem status of device");
+ return(ret);
+ }
+
+ return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+ (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
+ (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
+ (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0),
+ (unsigned long *) arg);
+ break;
+
+ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+ dbg("TIOCMSET");
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW);
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set DTR failed");
+ return(ret);
+ }
+ urb_value = ((mask & TIOCM_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW);
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set RTS failed");
+ return(ret);
+ }
+ break;
+
+ case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+ dbg("TIOCMBIS");
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ if (mask & TIOCM_DTR){
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_DTR_HIGH , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set DTR failed");
+ return(ret);
+ }
+ }
+ if (mask & TIOCM_RTS) {
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_RTS_HIGH , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to set RTS failed");
+ return(ret);
+ }
+ }
+ break;
+
+ case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+ dbg("TIOCMBIC");
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+ if (mask & TIOCM_DTR){
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_DTR_LOW , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to unset DTR failed");
+ return(ret);
+ }
+ }
+ if (mask & TIOCM_RTS) {
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ FTDI_SIO_SET_RTS_LOW , 0,
+ buf, 0, WDR_TIMEOUT)) < 0){
+ err("Urb to unset RTS failed");
+ return(ret);
+ }
+ }
+ break;
+
+ /*
+ * I had originally implemented TCSET{A,S}{,F,W} and
+ * TCGET{A,S} here separately, however when testing I
+ * found that the higher layers actually do the termios
+ * conversions themselves and pass the call onto
+ * ftdi_sio_set_termios.
+ *
+ */
+
+ default:
+ /* This is not an error - turns out the higher layers will do
+ * some ioctls itself (see comment above)
+ */
+ dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd);
+ return(-ENOIOCTLCMD);
+ break;
+ }
+ dbg("ftdi_sio_ioctl returning 0");
+ return 0;
+} /* ftdi_sio_ioctl */
+
+#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
+
+
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 36fa7bb3e..fe5f545db 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -1,15 +1,23 @@
-/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
-/* The device is based on the FTDI FT8U100AX chip, DB25 on one side, USB on the other */
-/* Thanx to FTDI for so kindly providing details of the protocol required */
-/* http://www.ftdi.co.uk */
-
-/* The implementation of the device I have is called a USC-1000 */
-/* which is available from http://www.dse.co.nz - cat no XH4214 */
-/* It looks similar to this: http://www.dansdata.com/usbser.htm but I can't be sure */
-/* There are other USC-1000s which don't look like my device though so beware */
-
-/* Definitions for the FTDI USB Single Port Serial Converter */
-/* known as FTDI_SIO (Serial Input/Output application of the chipset) */
+/*
+ * Definitions for the FTDI USB Single Port Serial Converter -
+ * known as FTDI_SIO (Serial Input/Output application of the chipset)
+ *
+ * The example I have is known as the USC-1000 which is available from
+ * http://www.dse.co.nz - cat no XH4214 It looks similar to this:
+ * http://www.dansdata.com/usbser.htm but I can't be sure There are other
+ * USC-1000s which don't look like my device though so beware!
+ *
+ * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side,
+ * USB on the other.
+ *
+ * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details
+ * of the protocol required to talk to the device and ongoing assistence
+ * during development.
+ *
+ * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the
+ * FTDI_SIO implementation.
+ *
+ */
#define FTDI_VID 0x0403 /* Vendor Id */
#define FTDI_SIO_PID 0x8372 /* Product Id */
@@ -27,7 +35,7 @@
/* Port Identifier Table */
#define PIT_DEFAULT 0 /* SIOA */
#define PIT_SIOA 1 /* SIOA */
-/* The device this is tested with one has one port */
+/* The device this driver is tested with one has only one port */
#define PIT_SIOB 2 /* SIOB */
#define PIT_PARALLEL 3 /* Parallel */
@@ -37,17 +45,31 @@
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
-/*
- BmRequestType: 0100 0000B
- bRequest: FTDI_SIO_RESET
- wValue: Control Value
- 0 = Reset SIO
- 1 = Purge RX buffer
- 2 = Purge TX buffer
- wIndex: Port
- wLength: 0
- Data: None
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_RESET
+ * wValue: Control Value
+ * 0 = Reset SIO
+ * 1 = Purge RX buffer
+ * 2 = Purge TX buffer
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * The Reset SIO command has this effect:
+ *
+ * Sets flow control set to 'none'
+ * Event char = $0D
+ * Event trigger = disabled
+ * Purge RX buffer
+ * Purge TX buffer
+ * Clear DTR
+ * Clear RTS
+ * baud and data format not reset
+ *
+ * The Purge RX and TX buffer commands affect nothing except the buffers
+ *
*/
/* FTDI_SIO_SET_BAUDRATE */
@@ -55,13 +77,13 @@
#define FTDI_SIO_SET_BAUDRATE_REQUEST 3
/*
- BmRequestType: 0100 0000B
- bRequest: FTDI_SIO_SET_BAUDRATE
- wValue: BaudRate value - see below
- wIndex: Port
- wLength: 0
- Data: None
-*/
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_SET_BAUDRATE
+ * wValue: BaudRate value - see below
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ */
typedef enum {
ftdi_sio_b300 = 0,
@@ -89,28 +111,30 @@ typedef enum {
/* FTDI_SIO_SET_DATA */
-/* BmRequestType: 0100 0000B */
-/* bRequest: FTDI_SIO_SET_DATA */
-/* wValue: Data characteristics (see below) */
-/* wIndex: Port */
-/* wLength: 0 */
-/* Data: None */
-/*
- Data characteristics
-
-B0..7 Number of data bits
-B8..10 Parity
- 0 = None
- 1 = Odd
- 2 = Even
- 3 = Mark
- 4 = Space
- B11..13 Stop Bits
- 0 = 1
- 1 = 1.5
- 2 = 2
- B14..15 Reserved
-*/
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_SET_DATA
+ * wValue: Data characteristics (see below)
+ * wIndex: Port
+ * wLength: 0
+ * Data: No
+ *
+ * Data characteristics
+ *
+ * B0..7 Number of data bits
+ * B8..10 Parity
+ * 0 = None
+ * 1 = Odd
+ * 2 = Even
+ * 3 = Mark
+ * 4 = Space
+ * B11..13 Stop Bits
+ * 0 = 1
+ * 1 = 1.5
+ * 2 = 2
+ * B14..15 Reserved
+ *
+ */
@@ -119,16 +143,17 @@ B8..10 Parity
#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
/*
- BmRequestType: 0100 0000B
- bRequest: FTDI_SIO_MODEM_CTRL
- wValue: ControlValue (see below)
- wIndex: Port
- wLength: 0
- Data: None
-
- NOTE: If the device is in RTS/CTS flow control, the RTS set by this
- command will be IGNORED without an error being returned
-*/
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_MODEM_CTRL
+ * wValue: ControlValue (see below)
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * NOTE: If the device is in RTS/CTS flow control, the RTS set by this
+ * command will be IGNORED without an error being returned
+ * Also - you can not set DTR and RTS with one control message
+ */
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8))
@@ -137,100 +162,107 @@ B8..10 Parity
#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
-/* ControlValue
- B0 DTR state
- 0 = reset
- 1 = set
- B1 RTS state
- 0 = reset
- 1 = set
- B2..7 Reserved
- B8 DTR state enable
- 0 = ignore
- 1 = use DTR state
- B9 RTS state enable
- 0 = ignore
- 1 = use RTS state
- B10..15 Reserved
-*/
+/*
+ * ControlValue
+ * B0 DTR state
+ * 0 = reset
+ * 1 = set
+ * B1 RTS state
+ * 0 = reset
+ * 1 = set
+ * B2..7 Reserved
+ * B8 DTR state enable
+ * 0 = ignore
+ * 1 = use DTR state
+ * B9 RTS state enable
+ * 0 = ignore
+ * 1 = use RTS state
+ * B10..15 Reserved
+ */
/* FTDI_SIO_SET_FLOW_CTRL */
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
-#define FTDI_SIO_RTS_CTS_HS 0x1
-#define FTDI_SIO_DTR_DSR_HS 0x2
-#define FTDI_SIO_XON_XOFF_HS 0x4
-/*
- BmRequestType: 0100 0000b
- bRequest: FTDI_SIO_SET_FLOW_CTRL
- wValue: Xoff/Xon
- wIndex: Protocol/Port - hIndex is protocl / lIndex is port
- wLength: 0
- Data: None
-
-hIndex - protocol has
- B0 Output handshaking using RTS/CTS
- 0 = disabled
- 1 = enabled
- B1 Output handshaking using DTR/DSR
- 0 = disabled
- 1 = enabled
- B2 Xon/Xoff handshaking
- 0 = disabled
- 1 = enabled
-
-A value of zero in the hIndex field selects no handshaking
+#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
+#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
+#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
+/*
+ * BmRequestType: 0100 0000b
+ * bRequest: FTDI_SIO_SET_FLOW_CTRL
+ * wValue: Xoff/Xon
+ * wIndex: Protocol/Port - hIndex is protocl / lIndex is port
+ * wLength: 0
+ * Data: None
+ *
+ * hIndex protocol is:
+ * B0 Output handshaking using RTS/CTS
+ * 0 = disabled
+ * 1 = enabled
+ * B1 Output handshaking using DTR/DSR
+ * 0 = disabled
+ * 1 = enabled
+ * B2 Xon/Xoff handshaking
+ * 0 = disabled
+ * 1 = enabled
+ *
+ * A value of zero in the hIndex field disables handshaking
+ *
+ * If Xon/Xoff handshaking is specified, the hValue field should contain the XOFF character
+ * and the lValue field contains the XON character.
+ */
+
+/*
+ * FTDI_SIO_SET_EVENT_CHAR
+ *
+ * Set the special event character for the specified communications port.
+ * If the device sees this character it will immediately return the
+ * data read so far - rather than wait 40ms or until 62 bytes are read
+ * which is what normally happens.
+ */
-If Xon/Xoff handshaking is specified, the hValue field contains the Xoff character
-and the lValue field contains the Xon character.
-*/
-
-/* FTDI_SIO_SET_EVENT_CHAR */
-/* Set the special event character for the specified communications port */
-/* If the device sees this character it will immediately return the */
-/* data read so far - rather than wait 40ms or until 62 bytes is read */
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
/*
- BmRequestType: 0100 0000b
- bRequest: FTDI_SIO_SET_EVENT_CHAR
- wValue: EventChar
- wIndex: Port
- wLength: 0
- Data: None
-
-wValue:
- B0..7 Event Character
- B8 Event Character Processing
- 0 = disabled
- 1 = enabled
- B9..15 Reserved
-
-*/
+ * BmRequestType: 0100 0000b
+ * bRequest: FTDI_SIO_SET_EVENT_CHAR
+ * wValue: EventChar
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * wValue:
+ * B0..7 Event Character
+ * B8 Event Character Processing
+ * 0 = disabled
+ * 1 = enabled
+ * B9..15 Reserved
+ *
+ */
/* FTDI_SIO_SET_ERROR_CHAR */
+
/* Set the parity error replacement character for the specified communications port */
/*
- BmRequestType: 0100 0000b
- bRequest: FTDI_SIO_SET_EVENT_CHAR
- wValue: Error Char
- wIndex: Port
- wLength: 0
- Data: None
-
-Error Char
- B0..7 Error Character
- B8 Error Character Processing
- 0 = disabled
- 1 = enabled
- B9..15 Reserved
-
-*/
+ * BmRequestType: 0100 0000b
+ * bRequest: FTDI_SIO_SET_EVENT_CHAR
+ * wValue: Error Char
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ *Error Char
+ * B0..7 Error Character
+ * B8 Error Character Processing
+ * 0 = disabled
+ * 1 = enabled
+ * B9..15 Reserved
+ *
+ */
/* FTDI_SIO_GET_MODEM_STATUS */
/* Retreive the current value of the modem status register */
@@ -242,139 +274,140 @@ Error Char
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
/*
- BmRequestType: 1100 0000b
- bRequest: FTDI_SIO_GET_MODEM_STATUS
- wValue: zero
- wIndex: Port
- wLength: 1
- Data: Status
-
-One byte of data is returned
-B0..3 0
-B4 CTS
- 0 = inactive
- 1 = active
-B5 DSR
- 0 = inactive
- 1 = active
-B6 Ring Indicator (RI)
- 0 = inactive
- 1 = active
-B7 Receive Line Signal Detect (RLSD)
- 0 = inactive
- 1 = active
-*/
+ * BmRequestType: 1100 0000b
+ * bRequest: FTDI_SIO_GET_MODEM_STATUS
+ * wValue: zero
+ * wIndex: Port
+ * wLength: 1
+ * Data: Status
+ *
+ * One byte of data is returned
+ * B0..3 0
+ * B4 CTS
+ * 0 = inactive
+ * 1 = active
+ * B5 DSR
+ * 0 = inactive
+ * 1 = active
+ * B6 Ring Indicator (RI)
+ * 0 = inactive
+ * 1 = active
+ * B7 Receive Line Signal Detect (RLSD)
+ * 0 = inactive
+ * 1 = active
+ */
/* Descriptors returned by the device
+ *
+ * Device Descriptor
+ *
+ * Offset Field Size Value Description
+ * 0 bLength 1 0x12 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x01 DEVICE Descriptor Type
+ * 2 bcdUSB 2 0x0110 USB Spec Release Number
+ * 4 bDeviceClass 1 0x00 Class Code
+ * 5 bDeviceSubClass 1 0x00 SubClass Code
+ * 6 bDeviceProtocol 1 0x00 Protocol Code
+ * 7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0
+ * 8 idVendor 2 0x0403 Vendor ID
+ * 10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID)
+ * 12 bcdDevice 2 0x0001 Device release number
+ * 14 iManufacturer 1 0x01 Index of man. string desc
+ * 15 iProduct 1 0x02 Index of prod string desc
+ * 16 iSerialNumber 1 0x02 Index of serial nmr string desc
+ * 17 bNumConfigurations 1 0x01 Number of possible configurations
+ *
+ * Configuration Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x09 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type
+ * 2 wTotalLength 2 0x0020 Total length of data
+ * 4 bNumInterfaces 1 0x01 Number of interfaces supported
+ * 5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req
+ * 6 iConfiguration 1 0x02 Index of config string descriptor
+ * 7 bmAttributes 1 0x20 Config characteristics Remote Wakeup
+ * 8 MaxPower 1 0x1E Max power consumption
+ *
+ * Interface Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x09 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x04 INTERFACE Descriptor Type
+ * 2 bInterfaceNumber 1 0x00 Number of interface
+ * 3 bAlternateSetting 1 0x00 Value used to select alternate
+ * 4 bNumEndpoints 1 0x02 Number of endpoints
+ * 5 bInterfaceClass 1 0xFF Class Code
+ * 6 bInterfaceSubClass 1 0xFF Subclass Code
+ * 7 bInterfaceProtocol 1 0xFF Protocol Code
+ * 8 iInterface 1 0x02 Index of interface string description
+ *
+ * IN Endpoint Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x07 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x05 ENDPOINT descriptor type
+ * 2 bEndpointAddress 1 0x82 Address of endpoint
+ * 3 bmAttributes 1 0x02 Endpoint attributes - Bulk
+ * 4 bNumEndpoints 2 0x0040 maximum packet size
+ * 5 bInterval 1 0x00 Interval for polling endpoint
+ *
+ * OUT Endpoint Descriptor
+ *
+ * Offset Field Size Value
+ * 0 bLength 1 0x07 Size of descriptor in bytes
+ * 1 bDescriptorType 1 0x05 ENDPOINT descriptor type
+ * 2 bEndpointAddress 1 0x02 Address of endpoint
+ * 3 bmAttributes 1 0x02 Endpoint attributes - Bulk
+ * 4 bNumEndpoints 2 0x0040 maximum packet size
+ * 5 bInterval 1 0x00 Interval for polling endpoint
+ *
+ * DATA FORMAT
+ *
+ * IN Endpoint
+ *
+ * The device reserves the first two bytes of data on this endpoint to contain the current
+ * values of the modem and line status registers. In the absence of data, the device
+ * generates a message consisting of these two status bytes every 40 ms
+ *
+ * Byte 0: Modem Status
+ *
+ * Offset Description
+ * B0 Reserved - must be 1
+ * B1 Reserved - must be 0
+ * B2 Reserved - must be 0
+ * B3 Reserved - must be 0
+ * B4 Clear to Send (CTS)
+ * B5 Data Set Ready (DSR)
+ * B6 Ring Indicator (RI)
+ * B7 Receive Line Signal Detect (RLSD)
+ *
+ * Byte 1: Line Status
+ *
+ * Offset Description
+ * B0 Data Ready (DR)
+ * B1 Overrun Error (OE)
+ * B2 Parity Error (PE)
+ * B3 Framing Error (FE)
+ * B4 Break Interrupt (BI)
+ * B5 Transmitter Holding Register (THRE)
+ * B6 Transmitter Empty (TEMT)
+ * B7 Error in RCVR FIFO
+ *
+ * OUT Endpoint
+ *
+ * This device reserves the first bytes of data on this endpoint contain the length
+ * and port identifier of the message. For the FTDI USB Serial converter the port
+ * identifier is always 1.
+ *
+ * Byte 0: Line Status
+ *
+ * Offset Description
+ * B0 Reserved - must be 1
+ * B1 Reserved - must be 0
+ * B2..7 Length of message - (not including Byte 0)
+ *
+ */
- Device Descriptor
-
-Offset Field Size Value Description
-0 bLength 1 0x12 Size of descriptor in bytes
-1 bDescriptorType 1 0x01 DEVICE Descriptor Type
-2 bcdUSB 2 0x0110 USB Spec Release Number
-4 bDeviceClass 1 0x00 Class Code
-5 bDeviceSubClass 1 0x00 SubClass Code
-6 bDeviceProtocol 1 0x00 Protocol Code
-7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0
-8 idVendor 2 0x0403 Vendor ID
-10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID)
-12 bcdDevice 2 0x0001 Device release number
-14 iManufacturer 1 0x01 Index of man. string desc
-15 iProduct 1 0x02 Index of prod string desc
-16 iSerialNumber 1 0x02 Index of serial nmr string desc
-17 bNumConfigurations 1 0x01 Number of possible configurations
-
-Configuration Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x09 Size of descriptor in bytes
-1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type
-2 wTotalLength 2 0x0020 Total length of data
-4 bNumInterfaces 1 0x01 Number of interfaces supported
-5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req
-6 iConfiguration 1 0x02 Index of config string descriptor
-7 bmAttributes 1 0x20 Config characteristics Remote Wakeup
-8 MaxPower 1 0x1E Max power consumption
-
-Interface Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x09 Size of descriptor in bytes
-1 bDescriptorType 1 0x04 INTERFACE Descriptor Type
-2 bInterfaceNumber 1 0x00 Number of interface
-3 bAlternateSetting 1 0x00 Value used to select alternate
-4 bNumEndpoints 1 0x02 Number of endpoints
-5 bInterfaceClass 1 0xFF Class Code
-6 bInterfaceSubClass 1 0xFF Subclass Code
-7 bInterfaceProtocol 1 0xFF Protocol Code
-8 iInterface 1 0x02 Index of interface string description
-
-IN Endpoint Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x07 Size of descriptor in bytes
-1 bDescriptorType 1 0x05 ENDPOINT descriptor type
-2 bEndpointAddress 1 0x82 Address of endpoint
-3 bmAttributes 1 0x02 Endpoint attributes - Bulk
-4 bNumEndpoints 2 0x0040 maximum packet size
-5 bInterval 1 0x00 Interval for polling endpoint
-
-OUT Endpoint Descriptor
-
-Offset Field Size Value
-0 bLength 1 0x07 Size of descriptor in bytes
-1 bDescriptorType 1 0x05 ENDPOINT descriptor type
-2 bEndpointAddress 1 0x02 Address of endpoint
-3 bmAttributes 1 0x02 Endpoint attributes - Bulk
-4 bNumEndpoints 2 0x0040 maximum packet size
-5 bInterval 1 0x00 Interval for polling endpoint
-
-DATA FORMAT
-
-IN Endpoint
-
-The device reserves the first two bytes of data on this endpoint to contain the current
-values of the modem and line status registers. In the absence of data, the device
-generates a message consisting of these two status bytes every 40 ms
-
-Byte 0: Modem Status
-
-Offset Description
-B0 Reserved - must be 1
-B1 Reserved - must be 0
-B2 Reserved - must be 0
-B3 Reserved - must be 0
-B4 Clear to Send (CTS)
-B5 Data Set Ready (DSR)
-B6 Ring Indicator (RI)
-B7 Receive Line Signal Detect (RLSD)
-
-Byte 1: Line Status
-
-Offset Description
-B0 Data Ready (DR)
-B1 Overrun Error (OE)
-B2 Parity Error (PE)
-B3 Framing Error (FE)
-B4 Break Interrupt (BI)
-B5 Transmitter Holding Register (THRE)
-B6 Transmitter Empty (TEMT)
-B7 Error in RCVR FIFO
-
-OUT Endpoint
-
-This device reserves the first bytes of data on this endpoint contain the length
-and port identifier of the message. For the FTDI USB Serial converter the port
-identifier is always 1.
-
-Byte 0: Line Status
-
-Offset Description
-B0 Reserved - must be 1
-B1 Reserved - must be 0
-B2..7 Length of message - (not including Byte 0)
-
-*/
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
new file mode 100644
index 000000000..9fb22e4a8
--- /dev/null
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -0,0 +1,717 @@
+/*
+ * USB Keyspan PDA Converter driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+struct ezusb_hex_record {
+ __u16 address;
+ __u8 data_size;
+ __u8 data[16];
+};
+
+#include "keyspan_pda_fw.h"
+
+#include "usb-serial.h"
+
+#define KEYSPAN_VENDOR_ID 0x06cd
+#define KEYSPAN_PDA_FAKE_ID 0x0103
+#define KEYSPAN_PDA_ID 0x0104 /* no clue */
+
+/* function prototypes for a Keyspan PDA serial converter */
+static int keyspan_pda_open (struct usb_serial_port *port,
+ struct file *filp);
+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 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 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 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 usb_serial_port *port,
+ struct termios *old);
+static void keyspan_pda_break_ctl (struct usb_serial_port *port,
+ int break_state);
+static int keyspan_pda_fake_startup (struct usb_serial *serial);
+
+
+/* All of the device info needed for the Keyspan PDA serial converter */
+static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID;
+static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID;
+static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID;
+struct usb_serial_device_type keyspan_pda_fake_device = {
+ name: "Keyspan PDA - (prerenumeration)",
+ idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
+ idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+ startup: keyspan_pda_fake_startup
+};
+struct usb_serial_device_type keyspan_pda_device = {
+ name: "Keyspan PDA",
+ idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
+ idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */
+ needs_interrupt_in: MUST_HAVE,
+ needs_bulk_in: DONT_CARE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 1,
+ num_bulk_in: 0,
+ num_bulk_out: 1,
+ num_ports: 1,
+ 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,
+ chars_in_buffer: keyspan_pda_chars_in_buffer,
+ throttle: keyspan_pda_rx_throttle,
+ unthrottle: keyspan_pda_rx_unthrottle,
+ startup: keyspan_pda_startup,
+ ioctl: keyspan_pda_ioctl,
+ set_termios: keyspan_pda_set_termios,
+ break_ctl: keyspan_pda_break_ctl,
+};
+
+
+static void keyspan_pda_rx_interrupt (struct urb *urb)
+{
+ 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;
+
+ /* the urb might have been killed. */
+ if (urb->status)
+ return;
+
+ 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);
+ }
+ tty_flip_buffer_push(tty);
+ }
+ break;
+ case 1:
+ /* status interrupt */
+ dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
+ switch (data[1]) {
+ 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 */
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* INT urbs are automatically re-submitted */
+}
+
+
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
+{
+ /* 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
+ fills up. If we're doing XON/XOFF, this would be a good time to
+ send an XOFF, although it might make sense to foist that off
+ upon the device too. */
+
+ dbg("keyspan_pda_rx_throttle port %d", port->number);
+ usb_unlink_urb(port->read_urb);
+}
+
+
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
+{
+ /* just restart the receive interrupt 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;
+}
+
+
+static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+{
+ int rc;
+ int bindex;
+
+ switch(baud) {
+ case 110: bindex = 0; break;
+ case 300: bindex = 1; break;
+ case 1200: bindex = 2; break;
+ case 2400: bindex = 3; break;
+ case 4800: bindex = 4; break;
+ case 9600: bindex = 5; break;
+ case 19200: bindex = 6; break;
+ case 38400: bindex = 7; break;
+ case 57600: bindex = 8; break;
+ case 115200: bindex = 9; break;
+ default: return -EINVAL;
+ }
+
+ /* rather than figure out how to sleep while waiting for this
+ to complete, I just use the "legacy" API. */
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ 0, /* set baud */
+ USB_TYPE_VENDOR
+ | USB_RECIP_INTERFACE
+ | USB_DIR_OUT, /* type */
+ bindex, /* value */
+ 0, /* index */
+ NULL, /* &data */
+ 0, /* size */
+ 2*HZ); /* timeout */
+ return(rc);
+}
+
+
+static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
+{
+ struct usb_serial *serial = port->serial;
+ int value;
+ if (break_state == -1)
+ value = 1; /* start break */
+ else
+ value = 0; /* clear break */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ 4, /* set break */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ value, 0, NULL, 0, 2*HZ);
+ /* there is something funky about this.. the TCSBRK that 'cu' performs
+ ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
+ seconds apart, but it feels like the break sent isn't as long as it
+ is on /dev/ttyS0 */
+}
+
+
+static void keyspan_pda_set_termios (struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ 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?:
+ CSTOPB (1 stop bit or 2)
+ PARENB (parity)
+ CSIZE (5bit .. 8bit)
+ There is minimal hw support for parity (a PSW bit seems to hold the
+ parity of whatever is in the accumulator). The UART either deals
+ with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
+ 1 special, stop). So, with firmware changes, we could do:
+ 8N1: 10 bit
+ 8N2: 11 bit, extra bit always (mark?)
+ 8[EOMS]1: 11 bit, extra bit is parity
+ 7[EOMS]1: 10 bit, b0/b7 is parity
+ 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
+
+ HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+ bit.
+
+ For now, just do baud. */
+
+ switch (cflag & CBAUD) {
+ /* we could support more values here, just need to calculate
+ the necessary divisors in the firmware. <asm/termbits.h>
+ has the Bnnn constants. */
+ case B110: keyspan_pda_setbaud(serial, 110); break;
+ case B300: keyspan_pda_setbaud(serial, 300); break;
+ case B1200: keyspan_pda_setbaud(serial, 1200); break;
+ case B2400: keyspan_pda_setbaud(serial, 2400); break;
+ case B4800: keyspan_pda_setbaud(serial, 4800); break;
+ case B9600: keyspan_pda_setbaud(serial, 9600); break;
+ case B19200: keyspan_pda_setbaud(serial, 19200); break;
+ case B38400: keyspan_pda_setbaud(serial, 38400); break;
+ case B57600: keyspan_pda_setbaud(serial, 57600); break;
+ case B115200: keyspan_pda_setbaud(serial, 115200); break;
+ default: dbg("can't handle requested baud rate"); break;
+ }
+}
+
+
+/* modem control pins: DTR and RTS are outputs and can be controlled.
+ DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
+ read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
+
+static int keyspan_pda_get_modem_info(struct usb_serial *serial,
+ unsigned char *value)
+{
+ int rc;
+ unsigned char data;
+ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 3, /* get pins */
+ USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
+ 0, 0, &data, 1, 2*HZ);
+ if (rc > 0)
+ *value = data;
+ return rc;
+}
+
+
+static int keyspan_pda_set_modem_info(struct usb_serial *serial,
+ unsigned char value)
+{
+ int rc;
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ 3, /* set pins */
+ USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
+ value, 0, NULL, 0, 2*HZ);
+ return rc;
+}
+
+
+static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = port->serial;
+ int rc;
+ unsigned int value;
+ unsigned char status, mask;
+
+ switch (cmd) {
+ case TIOCMGET: /* get modem pins state */
+ rc = keyspan_pda_get_modem_info(serial, &status);
+ if (rc < 0)
+ return rc;
+ value =
+ ((status & (1<<7)) ? TIOCM_DTR : 0) |
+ ((status & (1<<6)) ? TIOCM_CAR : 0) |
+ ((status & (1<<5)) ? TIOCM_RNG : 0) |
+ ((status & (1<<4)) ? TIOCM_DSR : 0) |
+ ((status & (1<<3)) ? TIOCM_CTS : 0) |
+ ((status & (1<<2)) ? TIOCM_RTS : 0);
+ if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case TIOCMSET: /* set a state as returned by MGET */
+ if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+ return -EFAULT;
+ status =
+ ((value & TIOCM_DTR) ? (1<<7) : 0) |
+ ((value & TIOCM_CAR) ? (1<<6) : 0) |
+ ((value & TIOCM_RNG) ? (1<<5) : 0) |
+ ((value & TIOCM_DSR) ? (1<<4) : 0) |
+ ((value & TIOCM_CTS) ? (1<<3) : 0) |
+ ((value & TIOCM_RTS) ? (1<<2) : 0);
+ rc = keyspan_pda_set_modem_info(serial, status);
+ if (rc < 0)
+ return rc;
+ return 0;
+ case TIOCMBIS: /* set bits in bitmask <arg> */
+ case TIOCMBIC: /* clear bits from bitmask <arg> */
+ if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+ return -EFAULT;
+ rc = keyspan_pda_get_modem_info(serial, &status);
+ if (rc < 0)
+ return rc;
+ mask =
+ ((value & TIOCM_RTS) ? (1<<2) : 0) |
+ ((value & TIOCM_DTR) ? (1<<7) : 0);
+ if (cmd == TIOCMBIS)
+ status |= mask;
+ else
+ status &= ~mask;
+ rc = keyspan_pda_set_modem_info(serial, status);
+ if (rc < 0)
+ return rc;
+ return 0;
+ case TIOCMIWAIT:
+ /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+ /* TODO */
+ case TIOCGICOUNT:
+ /* return count of modemline transitions */
+ return 0; /* TODO */
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ int request_unthrottle = 0;
+ int rc = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* guess how much room is left in the device's ring buffer, and if we
+ want to send more than that, check first, updating our notion of
+ what is left. If our write will result in no room left, ask the
+ device to give us an interrupt when the room available rises above
+ a threshold, and hold off all writers (eventually, those using
+ select() or poll() too) until we receive that unthrottle interrupt.
+ Block if we can't write anything at all, otherwise write as much as
+ we can. */
+
+ if (count == 0) {
+ dbg(" write request of 0 bytes");
+ return (0);
+ }
+
+ /* we might block because of:
+ the TX urb is in-flight (wait until it completes)
+ the device is full (wait until it says there is room)
+ */
+ while (port->write_urb->status == -EINPROGRESS) {
+ if (0 /* file->f_flags & O_NONBLOCK */) {
+ rc = -EAGAIN;
+ goto err;
+ }
+ interruptible_sleep_on(&serial->write_wait);
+ if (signal_pending(current)) {
+ rc = -ERESTARTSYS;
+ goto err;
+ }
+ }
+
+ /* at this point the URB is in our control, nobody else can submit it
+ again (the only sudden transition was the one from EINPROGRESS to
+ finished) */
+
+ /* the next potential block is that our TX process might be throttled.
+ The transition from throttled->not happens because of an Rx
+ interrupt, and the wake_up occurs during the same interrupt, so we
+ have to be careful to avoid a race that would cause us to sleep
+ forever. */
+
+ add_wait_queue(&serial->write_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (serial->tx_throttled) {
+ /* device can't accomodate any more characters. Sleep until it
+ can. Woken up by an Rx interrupt message, which clears
+ tx_throttled first. */
+ dbg(" tx_throttled, going to sleep");
+ if (signal_pending(current)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&serial->write_wait, &wait);
+ dbg(" woke up because of signal");
+ rc = -ERESTARTSYS;
+ goto err;
+ }
+ schedule();
+ dbg(" woke up");
+ }
+ remove_wait_queue(&serial->write_wait, &wait);
+ set_current_state(TASK_RUNNING);
+
+ 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
+ how much room it really has */
+ rc = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 6, /* write_room */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_IN,
+ 0, /* value: 0 means "remaining room" */
+ 0, /* index */
+ &room,
+ 1,
+ 2*HZ);
+ if (rc < 0) {
+ dbg(" roomquery failed");
+ return rc; /* failed */
+ }
+ if (rc == 0) {
+ dbg(" roomquery returned 0 bytes");
+ return -EIO; /* device didn't return any data */
+ }
+ dbg(" roomquery says %d", room);
+ serial->tx_room = room;
+ if (count > serial->tx_room) {
+ /* we're about to completely fill the Tx buffer, so
+ we'll be throttled afterwards. */
+ count = serial->tx_room;
+ request_unthrottle = 1;
+ }
+ }
+ serial->tx_room -= count;
+
+ if (count) {
+ /* now transfer data */
+ if (from_user) {
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
+ }
+ else {
+ memcpy (port->write_urb->transfer_buffer, buf, count);
+ }
+ /* send the data out the bulk port */
+ port->write_urb->transfer_buffer_length = count;
+
+ if (usb_submit_urb(port->write_urb))
+ dbg(" usb_submit_urb(write bulk) failed");
+ }
+ else {
+ /* There wasn't any room left, so we are throttled until
+ the buffer empties a bit */
+ request_unthrottle = 1;
+ }
+
+ if (request_unthrottle) {
+ dbg(" request_unthrottle");
+ /* ask the device to tell us when the tx buffer becomes
+ sufficiently empty */
+ serial->tx_throttled = 1; /* block writers */
+ rc = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ 7, /* request_unthrottle */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_OUT,
+ 16, /* value: threshold */
+ 0, /* index */
+ NULL,
+ 0,
+ 2*HZ);
+ }
+
+ return (count);
+ err:
+ return (rc);
+}
+
+
+static void keyspan_pda_write_bulk_callback (struct urb *urb)
+{
+ 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);
+
+ wake_up_interruptible(&tty->write_wait);
+}
+
+
+static int keyspan_pda_write_room (struct usb_serial_port *port)
+{
+ 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
+ running a console through the device. */
+
+ return (serial->tx_room);
+}
+
+
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
+{
+ 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. */
+ if (serial->tx_throttled)
+ return 256;
+ return 0;
+}
+
+
+static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned char room;
+ int rc;
+
+ if (port->active) {
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ /* find out how much room is in the Tx ring */
+ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 6, /* write_room */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_IN,
+ 0, /* value */
+ 0, /* index */
+ &room,
+ 1,
+ 2*HZ);
+ if (rc < 0) {
+ dbg(" roomquery failed");
+ return rc; /* failed */
+ }
+ if (rc == 0) {
+ dbg(" roomquery returned 0 bytes");
+ return -EIO; /* device didn't return any data */
+ }
+ serial->tx_room = room;
+ serial->tx_throttled = room ? 0 : 1;
+
+ /* the normal serial device seems to always turn on DTR and RTS here,
+ so do the same */
+ 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))
+ dbg(" usb_submit_urb(read int) failed");
+
+ return (0);
+}
+
+
+static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+
+ /* the normal serial device seems to always shut off DTR and RTS now */
+ 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);
+ port->active = 0;
+}
+
+
+/* download the firmware to a "fake" device (pre-renumeration) */
+static int keyspan_pda_fake_startup (struct usb_serial *serial)
+{
+ int response;
+ const struct ezusb_hex_record *record;
+
+ /* download the firmware here ... */
+ response = ezusb_set_reset(serial, 1);
+
+ record = &keyspan_pda_firmware[0];
+ while(record->address != 0xffff) {
+ response = ezusb_writememory(serial, record->address,
+ (unsigned char *)record->data,
+ record->data_size, 0xa0);
+ if (response < 0) {
+ err("ezusb_writememory failed for Keyspan PDA "
+ "firmware (%d %04X %p %d)",
+ response,
+ record->address, record->data, record->data_size);
+ break;
+ }
+ record++;
+ }
+ /* bring device out of reset. Renumeration will occur in a moment
+ and the new device will bind to the real driver */
+ response = ezusb_set_reset(serial, 0);
+
+ /* we want this device to fail to have a driver assigned to it. */
+ return (1);
+}
+
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int keyspan_pda_startup (struct usb_serial *serial)
+{
+ struct usb_endpoint_descriptor *intin;
+ intin = serial->port[0].interrupt_in_endpoint;
+
+ /* set up the receive interrupt urb */
+ FILL_INT_URB(serial->port[0].read_urb, serial->dev,
+ usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
+ serial->port[0].interrupt_in_buffer,
+ intin->wMaxPacketSize,
+ keyspan_pda_rx_interrupt,
+ serial,
+ intin->bInterval);
+
+ init_waitqueue_head(&serial->write_wait);
+
+ return (0);
+}
+
+#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
+
+
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
deleted file mode 100644
index 021754994..000000000
--- a/drivers/usb/serial/usb-serial.c
+++ /dev/null
@@ -1,2593 +0,0 @@
-/*
- * USB Serial Converter driver
- *
- * (C) Copyright (C) 1999, 2000
- * Greg Kroah-Hartman (greg@kroah.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This driver was originally based on the ACM driver by Armin Fuerst (which was
- * based on a driver by Brad Keryan)
- *
- * 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.
- *
- * (03/06/2000) gkh
- * Added the keyspan pda code from Brian Warner <warner@lothar.com>
- * Moved a bunch of the port specific stuff into its own structure. This
- * is in anticipation of the true multiport devices (there's a bug if you
- * try to access more than one port of any multiport device right now)
- *
- * (02/21/2000) gkh
- * Made it so that any serial devices only have to specify which functions
- * they want to overload from the generic function calls (great,
- * inheritance in C, in a driver, just what I wanted...)
- * Added support for set_termios and ioctl function calls. No drivers take
- * advantage of this yet.
- * Removed the #ifdef MODULE, now there is no module specific code.
- * Cleaned up a few comments in usb-serial.h that were wrong (thanks again
- * to Miles Lott).
- * Small fix to get_free_serial.
- *
- * (02/14/2000) gkh
- * Removed the Belkin and Peracom functionality from the driver due to
- * the lack of support from the vendor, and me not wanting people to
- * accidenatly buy the device, expecting it to work with Linux.
- * Added read_bulk_callback and write_bulk_callback to the type structure
- * for the needs of the FTDI and WhiteHEAT driver.
- * Changed all reverences to FTDI to FTDI_SIO at the request of Bill
- * Ryder.
- * Changed the output urb size back to the max endpoint size to make
- * the ftdi_sio driver have it easier, and due to the fact that it didn't
- * really increase the speed any.
- *
- * (02/11/2000) gkh
- * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
- * patch from Miles Lott (milos@insync.net).
- * Fixed bug with not restoring the minor range that a device grabs, if
- * the startup function fails (thanks Miles for finding this).
- *
- * (02/05/2000) gkh
- * Added initial framework for the Keyspan PDA serial converter so that
- * Brian Warner has a place to put his code.
- * Made the ezusb specific functions generic enough that different
- * devices can use them (whiteheat and keyspan_pda both need them).
- * Split out a whole bunch of structure and other stuff to a seperate
- * usb-serial.h file.
- * Made the Visor connection messages a little more understandable, now
- * that Miles Lott (milos@insync.net) has gotten the Generic channel to
- * work. Also made them always show up in the log file.
- *
- * (01/25/2000) gkh
- * Added initial framework for FTDI serial converter so that Bill Ryder
- * has a place to put his code.
- * Added the vendor specific info from Handspring. Now we can print out
- * informational debug messages as well as understand what is happening.
- *
- * (01/23/2000) gkh
- * Fixed problem of crash when trying to open a port that didn't have a
- * device assigned to it. Made the minor node finding a little smarter,
- * now it looks to find a continous space for the new device.
- *
- * (01/21/2000) gkh
- * Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
- * Fixed get_serial_by_minor which was all messed up for multi port
- * devices. Fixed multi port problem for generic devices. Now the number
- * of ports is determined by the number of bulk out endpoints for the
- * generic device.
- *
- * (01/19/2000) gkh
- * Removed lots of cruft that was around from the old (pre urb) driver
- * interface.
- * Made the serial_table dynamic. This should save lots of memory when
- * the number of minor nodes goes up to 256.
- * Added initial support for devices that have more than one port.
- * Added more debugging comments for the Visor, and added a needed
- * set_configuration call.
- *
- * (01/17/2000) gkh
- * Fixed the WhiteHEAT firmware (my processing tool had a bug)
- * and added new debug loader firmware for it.
- * Removed the put_char function as it isn't really needed.
- * Added visor startup commands as found by the Win98 dump.
- *
- * (01/13/2000) gkh
- * Fixed the vendor id for the generic driver to the one I meant it to be.
- *
- * (01/12/2000) gkh
- * Forget the version numbering...that's pretty useless...
- * Made the driver able to be compiled so that the user can select which
- * converter they want to use. This allows people who only want the Visor
- * support to not pay the memory size price of the WhiteHEAT.
- * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
- * grabbed the root hub. Not good.
- *
- * version 0.4.0 (01/10/2000) gkh
- * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
- * device. Added startup function to allow firmware to be downloaded to
- * a device if it needs to be.
- * Added firmware download logic to the WhiteHEAT device.
- * Started to add #defines to split up the different drivers for potential
- * configuration option.
- *
- * version 0.3.1 (12/30/99) gkh
- * Fixed problems with urb for bulk out.
- * Added initial support for multiple sets of endpoints. This enables
- * the Handspring Visor to be attached successfully. Only the first
- * bulk in / bulk out endpoint pair is being used right now.
- *
- * version 0.3.0 (12/27/99) gkh
- * Added initial support for the Handspring Visor based on a patch from
- * Miles Lott (milos@sneety.insync.net)
- * Cleaned up the code a bunch and converted over to using urbs only.
- *
- * version 0.2.3 (12/21/99) gkh
- * Added initial support for the Connect Tech WhiteHEAT converter.
- * Incremented the number of ports in expectation of getting the
- * WhiteHEAT to work properly (4 ports per connection).
- * Added notification on insertion and removal of what port the
- * device is/was connected to (and what kind of device it was).
- *
- * version 0.2.2 (12/16/99) gkh
- * Changed major number to the new allocated number. We're legal now!
- *
- * version 0.2.1 (12/14/99) gkh
- * Fixed bug that happens when device node is opened when there isn't a
- * device attached to it. Thanks to marek@webdesign.no for noticing this.
- *
- * version 0.2.0 (11/10/99) gkh
- * Split up internals to make it easier to add different types of serial
- * converters to the code.
- * Added a "generic" driver that gets it's vendor and product id
- * from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
- * for the idea and sample code (from the usb scanner driver.)
- * Cleared up any licensing questions by releasing it under the GNU GPL.
- *
- * version 0.1.2 (10/25/99) gkh
- * Fixed bug in detecting device.
- *
- * version 0.1.1 (10/05/99) gkh
- * Changed the major number to not conflict with anything else.
- *
- * version 0.1 (09/28/99) gkh
- * Can recognize the two different devices and start up a read from
- * device when asked to. Writes also work. No control signals yet, this
- * all is vendor specific data (i.e. no spec), also no control for
- * different baud rates or other bit settings.
- * Currently we are using the same devid as the acm driver. This needs
- * to change.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/fcntl.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-#include "whiteheat.h" /* firmware for the ConnectTech WhiteHEAT device */
-#endif
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-struct ezusb_hex_record {
- __u16 address;
- __u8 data_size;
- __u8 data[16];
-};
-#include "keyspan_pda_fw.h"
-#endif
-
-#include "usb-serial.h"
-
-/* parity check flag */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-/* local function prototypes */
-static int serial_open (struct tty_struct *tty, struct file * filp);
-static void serial_close (struct tty_struct *tty, struct file * filp);
-static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
-static int serial_write_room (struct tty_struct *tty);
-static int serial_chars_in_buffer (struct tty_struct *tty);
-static void serial_throttle (struct tty_struct * tty);
-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);
-static void serial_set_termios (struct tty_struct *tty, struct termios * old);
-
-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 = {
- name: "serial",
- probe: usb_serial_probe,
- disconnect: usb_serial_disconnect,
-};
-
-static int serial_refcount;
-static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
-static struct termios * serial_termios[SERIAL_TTY_MINORS];
-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 inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
-{
- 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];
-}
-
-
-static struct usb_serial *get_free_serial (int num_ports, int *minor)
-{
- struct usb_serial *serial = NULL;
- int i, j;
- int good_spot;
-
- dbg("get_free_serial %d", num_ports);
-
- *minor = 0;
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
- if (serial_table[i])
- continue;
-
- good_spot = 1;
- for (j = 1; j <= num_ports-1; ++j)
- if (serial_table[i+j])
- good_spot = 0;
- if (good_spot == 0)
- continue;
-
- if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
- err("Out of memory");
- 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);
- for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
- serial_table[i] = serial;
- return serial;
- }
- return NULL;
-}
-
-
-static void return_serial (struct usb_serial *serial)
-{
- int i;
-
- dbg("return_serial");
-
- if (serial == NULL)
- return;
-
- for (i = 0; i < serial->num_ports; ++i) {
- serial_table[serial->minor + i] = NULL;
- }
-
- return;
-}
-
-
-#ifdef USES_EZUSB_FUNCTIONS
-/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
-#define CPUCS_REG 0x7F92
-
-static int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
-{
- int result;
- unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL);
-
-// dbg("ezusb_writememory %x, %d", address, length);
-
- if (!transfer_buffer) {
- err("ezusb_writememory: kmalloc(%d) failed.", length);
- return -ENOMEM;
- }
- memcpy (transfer_buffer, data, length);
- result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
- kfree (transfer_buffer);
- return result;
-}
-
-
-static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
-{
- int response;
- dbg("ezusb_set_reset: %d", reset_bit);
- response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
- if (response < 0) {
- err("ezusb_set_reset %d failed", reset_bit);
- }
- return response;
-}
-
-#endif /* USES_EZUSB_FUNCTIONS */
-
-
-/*****************************************************************************
- * Driver tty interface functions
- *****************************************************************************/
-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");
-
- /* initialize the pointer incase something fails */
- tty->driver_data = NULL;
-
- /* get the serial object associated with this tty pointer */
- serial = get_serial_by_minor (MINOR(tty->device));
-
- if (serial_paranoia_check (serial, "serial_open")) {
- return -ENODEV;
- }
-
- /* 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(port, filp));
- } else {
- return (generic_open(port, filp));
- }
-}
-
-
-static void serial_close(struct tty_struct *tty, struct file * filp)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_close");
-
- if (port_paranoia_check (port, "serial_close")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_close")) {
- return;
- }
-
- 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(port, filp);
- } else {
- generic_close(port, filp);
- }
-}
-
-
-static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write");
-
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
- return -ENODEV;
- }
-
- 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(port, from_user, buf, count));
- } else {
- return (generic_write(port, from_user, buf, count));
- }
-}
-
-
-static int serial_write_room (struct tty_struct *tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_write_room");
-
- if (port_paranoia_check (port, "serial_write")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_write")) {
- return -ENODEV;
- }
-
- 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(port));
- } else {
- return (generic_write_room(port));
- }
-}
-
-
-static int serial_chars_in_buffer (struct tty_struct *tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_chars_in_buffer");
-
- if (port_paranoia_check (port, "serial_chars_in_buffer")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
- return -ENODEV;
- }
-
- 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(port));
- } else {
- return (generic_chars_in_buffer(port));
- }
-}
-
-
-static void serial_throttle (struct tty_struct * tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_throttle");
-
- if (port_paranoia_check (port, "serial_throttle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_throttle")) {
- return;
- }
-
- 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(port);
- }
-
- return;
-}
-
-
-static void serial_unthrottle (struct tty_struct * tty)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_unthrottle");
-
- if (port_paranoia_check (port, "serial_unthrottle")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_unthrottle")) {
- return;
- }
-
- 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(port);
- }
-
- return;
-}
-
-
-static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_ioctl");
-
- if (port_paranoia_check (port, "serial_ioctl")) {
- return -ENODEV;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_ioctl")) {
- return -ENODEV;
- }
-
- 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(port, file, cmd, arg));
- } else {
- return -ENOIOCTLCMD;
- }
-}
-
-
-static void serial_set_termios (struct tty_struct *tty, struct termios * old)
-{
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial;
-
- dbg("serial_set_termios");
-
- if (port_paranoia_check (port, "serial_set_termios")) {
- return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_set_termios")) {
- return;
- }
-
- 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(port, old);
- }
-
- return;
-}
-
-
-static void serial_break (struct tty_struct *tty, int break_state)
-{
- 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;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "serial_break")) {
- return;
- }
-
- 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(port, break_state);
- }
-}
-
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-/*****************************************************************************
- * Connect Tech's White Heat specific driver functions
- *****************************************************************************/
-static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
-{
- dbg("whiteheat_open port %d", port->number);
-
- if (port->active) {
- dbg ("device already open");
- return -EINVAL;
- }
- port->active = 1;
-
- /*Start reading from the device*/
- 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.) */
- /* FIXME!!! */
-
- return (0);
-}
-
-
-static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
-{
- 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);
- port->active = 0;
-}
-
-
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{
- unsigned int cflag = port->tty->termios->c_cflag;
-
- 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(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("nothing to change...");
- return;
- }
- }
-
- /* do the parsing of the cflag to see what to set the line to */
- /* FIXME!! */
-
- return;
-}
-
-static void whiteheat_throttle (struct usb_serial_port *port)
-{
- dbg("whiteheat_throttle port %d", port->number);
-
- /* Change the control signals */
- /* FIXME!!! */
-
- return;
-}
-
-
-static void whiteheat_unthrottle (struct usb_serial_port *port)
-{
- dbg("whiteheat_unthrottle port %d", port->number);
-
- /* Change the control signals */
- /* FIXME!!! */
-
- return;
-}
-
-
-/* steps to download the firmware to the WhiteHEAT device:
- - hold the reset (by writing to the reset bit of the CPUCS register)
- - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
- - release the reset (by writing to the CPUCS register)
- - download the WH.HEX file for all addresses greater than 0x1b3f using
- VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
- - hold the reset
- - download the WH.HEX file for all addresses less than 0x1b40 using
- VENDOR_REQUEST_ANCHOR_LOAD
- - release the reset
- - device renumerated itself and comes up as new device id with all
- firmware download completed.
-*/
-static int whiteheat_startup (struct usb_serial *serial)
-{
- int response;
- const struct whiteheat_hex_record *record;
-
- dbg("whiteheat_startup");
-
- response = ezusb_set_reset (serial, 1);
-
- record = &whiteheat_loader[0];
- while (record->address != 0xffff) {
- response = ezusb_writememory (serial, record->address,
- (unsigned char *)record->data, record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for loader (%d %04X %p %d)",
- response, record->address, record->data, record->data_size);
- break;
- }
- ++record;
- }
-
- response = ezusb_set_reset (serial, 0);
-
- record = &whiteheat_firmware[0];
- while (record->address < 0x1b40) {
- ++record;
- }
- while (record->address != 0xffff) {
- response = ezusb_writememory (serial, record->address,
- (unsigned char *)record->data, record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for first firmware step (%d %04X %p %d)",
- response, record->address, record->data, record->data_size);
- break;
- }
- ++record;
- }
-
- response = ezusb_set_reset (serial, 1);
-
- record = &whiteheat_firmware[0];
- while (record->address < 0x1b40) {
- response = ezusb_writememory (serial, record->address,
- (unsigned char *)record->data, record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for second firmware step (%d %04X %p %d)",
- response, record->address, record->data, record->data_size);
- break;
- }
- ++record;
- }
-
- response = ezusb_set_reset (serial, 0);
-
- /* we want this device to fail to have a driver assigned to it. */
- return (1);
-}
-#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
-
-
-#ifdef CONFIG_USB_SERIAL_VISOR
-/******************************************************************************
- * Handspring Visor specific driver functions
- ******************************************************************************/
-static int visor_open (struct usb_serial_port *port, struct file *filp)
-{
- dbg("visor_open port %d", port->number);
-
- if (port->active) {
- dbg ("device already open");
- return -EINVAL;
- }
-
- port->active = 1;
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
-
- return (0);
-}
-
-
-static void visor_close (struct usb_serial_port *port, struct file * filp)
-{
- struct usb_serial *serial = port->serial;
- unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
-
- dbg("visor_close port %d", port->number);
-
- if (!transfer_buffer) {
- 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,
- 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
- }
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
-}
-
-
-static void visor_throttle (struct usb_serial_port *port)
-{
- dbg("visor_throttle port %d", port->number);
-
- usb_unlink_urb (port->read_urb);
-
- return;
-}
-
-
-static void visor_unthrottle (struct usb_serial_port *port)
-{
- dbg("visor_unthrottle port %d", port->number);
-
- if (usb_unlink_urb (port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
-
- return;
-}
-
-
-static int visor_startup (struct usb_serial *serial)
-{
- int response;
- int i;
- unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
-
- if (!transfer_buffer) {
- err("visor_startup: kmalloc(%d) failed.", 256);
- return -ENOMEM;
- }
-
- dbg("visor_startup");
-
- dbg("visor_setup: Set config to 1");
- usb_set_configuration (serial->dev, 1);
-
- /* send a get connection info request */
- response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
- 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
- if (response < 0) {
- err("visor_startup: error getting connection information");
- } else {
- struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
- char *string;
- info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
- for (i = 0; i < connection_info->num_ports; ++i) {
- switch (connection_info->connections[i].port_function_id) {
- case VISOR_FUNCTION_GENERIC:
- string = "Generic";
- break;
- case VISOR_FUNCTION_DEBUGGER:
- string = "Debugger";
- break;
- case VISOR_FUNCTION_HOTSYNC:
- string = "HotSync";
- break;
- case VISOR_FUNCTION_CONSOLE:
- string = "Console";
- break;
- case VISOR_FUNCTION_REMOTE_FILE_SYS:
- string = "Remote File System";
- break;
- default:
- string = "unknown";
- break;
- }
- info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
- }
- }
-
- /* ask for the number of bytes available, but ignore the response as it is broken */
- response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
- 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
- if (response < 0) {
- err("visor_startup: error getting bytes available request");
- }
-
- kfree (transfer_buffer);
-
- /* continue on with initialization */
- return (0);
-}
-
-
-#endif /* CONFIG_USB_SERIAL_VISOR*/
-
-
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-/******************************************************************************
- * FTDI SIO Serial Converter specific driver functions
- ******************************************************************************/
-
-/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
-/* Thanx to FTDI for so kindly providing details of the protocol required */
-/* to talk to the device */
-
-#include "ftdi_sio.h"
-
-static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
- char buf[1]; /* Needed for the usb_control_msg I think */
-
- dbg("ftdi_sio_open port %d", port->number);
-
- if (port->active) {
- dbg ("port already open");
- return -EINVAL;
- }
- port->active = 1;
-
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_SIO,
- 0, buf, 0, HZ * 5);
-
- /* FIXME - Should I really purge the buffers? */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_PURGE_RX,
- 0, buf, 0, HZ * 5);
-
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_PURGE_TX,
- 0, buf, 0, HZ * 5);
-
-
- /* As per usb_serial_init s/be CS8, B9600, 1 STOP BIT */
- if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_BAUDRATE_REQUEST,
- FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
- ftdi_sio_b9600, 0,
- buf, 0, HZ * 5) < 0){
- dbg("Error from baudrate urb");
- return(-EINVAL);
- }
-
- if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
- FTDI_SIO_SET_DATA_REQUEST_TYPE,
- 8 | FTDI_SIO_SET_DATA_PARITY_NONE |
- FTDI_SIO_SET_DATA_STOP_BITS_1, 0,
- buf, 0, HZ * 5) < 0){
- dbg("Error from cs8/noparity/1 stopbit urb");
- return(-EINVAL);
- }
-
- /* Disable flow control */
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
- FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("error from flowcontrol urb");
- return(-EINVAL);
- }
-
- /* Turn on RTS and DTR since we are not flow controlling*/
- /* FIXME - check for correct behaviour clocal vs non clocal */
- /* FIXME - might be able to do both simultaneously */
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_DTR_HIGH, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from DTR HIGH urb");
- }
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_RTS_HIGH, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from RTS HIGH urb");
- }
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
-
- return (0);
-}
-
-
-static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
- char buf[1];
-
- 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),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from DTR LOW urb");
- }
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
- buf, 0, HZ * 5) < 0) {
- dbg("Error from RTS LOW urb");
- }
-
- /* 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);
- port->active = 0;
-}
-
-
-
-/* The ftdi_sio requires the first byte to have:
- B0 1
- B1 0
- B2..7 length of message excluding byte 0
-*/
-static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
- const unsigned char *buf, int count)
-{
- struct usb_serial *serial = port->serial;
- const int data_offset = 1;
-
- dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
-
- if (count == 0) {
- dbg("write request of 0 bytes");
- return 0;
- }
-
- /* only do something if we have a bulk out endpoint */
- if (serial->num_bulk_out) {
- unsigned char *first_byte = port->write_urb->transfer_buffer;
-
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
- return 0;
- }
-
- count += data_offset;
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
- if (count == 0) {
- return 0;
- }
-
- /* Copy in the data to send */
- if (from_user) {
- copy_from_user(port->write_urb->transfer_buffer + data_offset ,
- buf, count - data_offset );
- }
- else {
- 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 = 1 | ((count-data_offset) << 2) ;
-
-#ifdef DEBUG
- dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
-
- if (count) {
- int i;
- printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
- for (i = 0; i < count; ++i) {
- printk ("0x%02x ", first_byte[i]);
- if (first_byte[i] > ' ' && first_byte[i] < '~') {
- printk("%c ", first_byte[i]);
- } else {
- printk(" ");
- }
- }
-
-
- printk ("\n");
- }
-
-#endif
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
-
- if (usb_submit_urb(port->write_urb))
- dbg("usb_submit_urb(write bulk) failed");
-
- dbg("write returning: %d", count - data_offset);
- return (count - data_offset);
- }
-
- /* no bulk out, so return 0 bytes written */
- return 0;
-}
-
-
-static void ftdi_sio_read_bulk_callback (struct urb *urb)
-{ /* ftdi_sio_serial_buld_callback */
- 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;
- }
-
-#ifdef DEBUG
- if (urb->actual_length > 2) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
- printk ("0x%.2x ", data[i]);
- if (data[i] > ' ' && data[i] < '~') {
- printk("%c ", data[i]);
- } else {
- printk(" ");
- }
- }
- printk ("\n");
- }
-#endif
-
-
- 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);
- }
- tty_flip_buffer_push(tty);
- }
-
- /* Continue trying to always read */
- if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
-
- return;
-} /* ftdi_sio_serial_read_bulk_callback */
-
-
-static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
-{
- 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->number);
-
- /* FIXME - we should keep the old termios really */
- /* FIXME -For this cut I don't care if the line is really changing or
- not - so just do the change regardless */
-
- /* Set number of data bits, parity, stop bits */
-
- urb_value = 0;
- urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
- FTDI_SIO_SET_DATA_STOP_BITS_1);
- urb_value |= (cflag & PARENB ?
- (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
- FTDI_SIO_SET_DATA_PARITY_EVEN) :
- FTDI_SIO_SET_DATA_PARITY_NONE);
- if (cflag & CSIZE) {
- switch (cflag & CSIZE) {
- case CS5: urb_value |= 5; dbg("Setting CS5"); break;
- case CS6: urb_value |= 6; dbg("Setting CS6"); break;
- case CS7: urb_value |= 7; dbg("Setting CS7"); break;
- case CS8: urb_value |= 8; dbg("Setting CS8"); break;
- default:
- dbg("CSIZE was set but not CS5-CS8");
- }
- }
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
- FTDI_SIO_SET_DATA_REQUEST_TYPE,
- urb_value , 0,
- buf, 0, 100) < 0) {
- dbg("FAILED to set databits/stopbits/parity");
- }
-
- /* Now do the baudrate */
- /* FIXME - should drop lines on B0 */
- /* FIXME Should also handle CLOCAL here */
-
- switch(cflag & CBAUD){
- case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
- case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
- case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
- case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
- case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
- case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
- case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
- case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
- case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
- case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
- default: dbg("FTDI_SIO does not support the baudrate requested");
- /* FIXME - how to return an error for this? */ break;
- }
- /* Send the URB */
- if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_BAUDRATE_REQUEST,
- FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
- urb_value, 0,
- buf, 0, 100) < 0) {
- dbg("urb failed to set baurdrate");
- }
- return;
-}
-
-
-/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
-static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
-{
- 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->number);
-
- /* Based on code from acm.c */
- switch (cmd) {
-
- case TIOCMGET:
- /* Request the status from the device */
- if ((ret = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
- FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, 0,
- buf, 1, HZ * 5)) < 0 ) {
- dbg("Get not get modem status of device");
- return(ret);
- }
-
- return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
- (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
- (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
- (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0),
- (unsigned long *) arg);
- break;
-
- case TIOCMSET:
- case TIOCMBIS:
- case TIOCMBIC:
- if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
-
- /* FIXME Need to remember if we have set DTR or RTS since we
- can't ask the device */
- /* FIXME - also need to find the meaning of TIOCMBIS/BIC/SET */
- if (mask & TIOCM_DTR) {
- switch(cmd) {
- case TIOCMSET:
- urb_value = FTDI_SIO_SET_DTR_HIGH | FTDI_SIO_SET_RTS_LOW;
- break;
-
- case TIOCMBIS:
- /* Will leave RTS alone and set DTR */
- urb_value = FTDI_SIO_SET_DTR_HIGH;
- break;
-
- case TIOCMBIC:
- urb_value = FTDI_SIO_SET_DTR_LOW;
- break;
- }
- }
-
- if (mask & TIOCM_RTS) {
- switch(cmd) {
- case TIOCMSET:
- urb_value = FTDI_SIO_SET_DTR_LOW | FTDI_SIO_SET_RTS_HIGH;
- break;
-
- case TIOCMBIS:
- /* Will leave DTR and set RTS */
- urb_value = FTDI_SIO_SET_RTS_HIGH;
- break;
-
- case TIOCMBIC:
- /* Will unset RTS */
- urb_value = FTDI_SIO_SET_RTS_LOW;
- break;
- }
- }
-
-
- return(usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
- FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
- urb_value , 0,
- buf, 0, HZ * 5));
- }
-
- return -ENOIOCTLCMD;
-}
-
-#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
-
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-/*****************************************************************************
- * Keyspan PDA specific driver functions
- *****************************************************************************/
-
-static void keyspan_pda_rx_interrupt (struct urb *urb)
-{
- 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;
-
- /* the urb might have been killed. */
- if (urb->status)
- return;
-
- 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);
- }
- tty_flip_buffer_push(tty);
- }
- break;
- case 1:
- /* status interrupt */
- dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
- switch (data[1]) {
- 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 */
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- /* INT urbs are automatically re-submitted */
-}
-
-
-static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
-{
- /* 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
- fills up. If we're doing XON/XOFF, this would be a good time to
- send an XOFF, although it might make sense to foist that off
- upon the device too. */
-
- dbg("keyspan_pda_rx_throttle port %d", port->number);
- usb_unlink_urb(port->read_urb);
-}
-
-
-static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
-{
- /* just restart the receive interrupt 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;
-}
-
-
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
-{
- int rc;
- int bindex;
-
- switch(baud) {
- case 110: bindex = 0; break;
- case 300: bindex = 1; break;
- case 1200: bindex = 2; break;
- case 2400: bindex = 3; break;
- case 4800: bindex = 4; break;
- case 9600: bindex = 5; break;
- case 19200: bindex = 6; break;
- case 38400: bindex = 7; break;
- case 57600: bindex = 8; break;
- case 115200: bindex = 9; break;
- default: return -EINVAL;
- }
-
- /* rather than figure out how to sleep while waiting for this
- to complete, I just use the "legacy" API. */
- rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 0, /* set baud */
- USB_TYPE_VENDOR
- | USB_RECIP_INTERFACE
- | USB_DIR_OUT, /* type */
- bindex, /* value */
- 0, /* index */
- NULL, /* &data */
- 0, /* size */
- 2*HZ); /* timeout */
- return(rc);
-}
-
-
-static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
-{
- struct usb_serial *serial = port->serial;
- int value;
- if (break_state == -1)
- value = 1; /* start break */
- else
- value = 0; /* clear break */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 4, /* set break */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
- value, 0, NULL, 0, 2*HZ);
- /* there is something funky about this.. the TCSBRK that 'cu' performs
- ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
- seconds apart, but it feels like the break sent isn't as long as it
- is on /dev/ttyS0 */
-}
-
-
-static void keyspan_pda_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
-{
- 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?:
- CSTOPB (1 stop bit or 2)
- PARENB (parity)
- CSIZE (5bit .. 8bit)
- There is minimal hw support for parity (a PSW bit seems to hold the
- parity of whatever is in the accumulator). The UART either deals
- with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
- 1 special, stop). So, with firmware changes, we could do:
- 8N1: 10 bit
- 8N2: 11 bit, extra bit always (mark?)
- 8[EOMS]1: 11 bit, extra bit is parity
- 7[EOMS]1: 10 bit, b0/b7 is parity
- 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
-
- HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
- bit.
-
- For now, just do baud. */
-
- switch (cflag & CBAUD) {
- /* we could support more values here, just need to calculate
- the necessary divisors in the firmware. <asm/termbits.h>
- has the Bnnn constants. */
- case B110: keyspan_pda_setbaud(serial, 110); break;
- case B300: keyspan_pda_setbaud(serial, 300); break;
- case B1200: keyspan_pda_setbaud(serial, 1200); break;
- case B2400: keyspan_pda_setbaud(serial, 2400); break;
- case B4800: keyspan_pda_setbaud(serial, 4800); break;
- case B9600: keyspan_pda_setbaud(serial, 9600); break;
- case B19200: keyspan_pda_setbaud(serial, 19200); break;
- case B38400: keyspan_pda_setbaud(serial, 38400); break;
- case B57600: keyspan_pda_setbaud(serial, 57600); break;
- case B115200: keyspan_pda_setbaud(serial, 115200); break;
- default: dbg("can't handle requested baud rate"); break;
- }
-}
-
-
-/* modem control pins: DTR and RTS are outputs and can be controlled.
- DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
- read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
-
-static int keyspan_pda_get_modem_info(struct usb_serial *serial,
- unsigned char *value)
-{
- int rc;
- unsigned char data;
- rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- 3, /* get pins */
- USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
- 0, 0, &data, 1, 2*HZ);
- if (rc > 0)
- *value = data;
- return rc;
-}
-
-
-static int keyspan_pda_set_modem_info(struct usb_serial *serial,
- unsigned char value)
-{
- int rc;
- rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 3, /* set pins */
- USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
- value, 0, NULL, 0, 2*HZ);
- return rc;
-}
-
-
-static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial *serial = port->serial;
- int rc;
- unsigned int value;
- unsigned char status, mask;
-
- switch (cmd) {
- case TIOCMGET: /* get modem pins state */
- rc = keyspan_pda_get_modem_info(serial, &status);
- if (rc < 0)
- return rc;
- value =
- ((status & (1<<7)) ? TIOCM_DTR : 0) |
- ((status & (1<<6)) ? TIOCM_CAR : 0) |
- ((status & (1<<5)) ? TIOCM_RNG : 0) |
- ((status & (1<<4)) ? TIOCM_DSR : 0) |
- ((status & (1<<3)) ? TIOCM_CTS : 0) |
- ((status & (1<<2)) ? TIOCM_RTS : 0);
- if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
- return -EFAULT;
- return 0;
- case TIOCMSET: /* set a state as returned by MGET */
- if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
- return -EFAULT;
- status =
- ((value & TIOCM_DTR) ? (1<<7) : 0) |
- ((value & TIOCM_CAR) ? (1<<6) : 0) |
- ((value & TIOCM_RNG) ? (1<<5) : 0) |
- ((value & TIOCM_DSR) ? (1<<4) : 0) |
- ((value & TIOCM_CTS) ? (1<<3) : 0) |
- ((value & TIOCM_RTS) ? (1<<2) : 0);
- rc = keyspan_pda_set_modem_info(serial, status);
- if (rc < 0)
- return rc;
- return 0;
- case TIOCMBIS: /* set bits in bitmask <arg> */
- case TIOCMBIC: /* clear bits from bitmask <arg> */
- if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
- return -EFAULT;
- rc = keyspan_pda_get_modem_info(serial, &status);
- if (rc < 0)
- return rc;
- mask =
- ((value & TIOCM_RTS) ? (1<<2) : 0) |
- ((value & TIOCM_DTR) ? (1<<7) : 0);
- if (cmd == TIOCMBIS)
- status |= mask;
- else
- status &= ~mask;
- rc = keyspan_pda_set_modem_info(serial, status);
- if (rc < 0)
- return rc;
- return 0;
- case TIOCMIWAIT:
- /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
- /* TODO */
- case TIOCGICOUNT:
- /* return count of modemline transitions */
- return 0; /* TODO */
- }
-
- return -ENOIOCTLCMD;
-}
-
-static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
- const unsigned char *buf, int count)
-{
- struct usb_serial *serial = port->serial;
- int request_unthrottle = 0;
- int rc = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- /* guess how much room is left in the device's ring buffer, and if we
- want to send more than that, check first, updating our notion of
- what is left. If our write will result in no room left, ask the
- device to give us an interrupt when the room available rises above
- a threshold, and hold off all writers (eventually, those using
- select() or poll() too) until we receive that unthrottle interrupt.
- Block if we can't write anything at all, otherwise write as much as
- we can. */
-
- if (count == 0) {
- dbg(" write request of 0 bytes");
- return (0);
- }
-
- /* we might block because of:
- the TX urb is in-flight (wait until it completes)
- the device is full (wait until it says there is room)
- */
- while (port->write_urb->status == -EINPROGRESS) {
- if (0 /* file->f_flags & O_NONBLOCK */) {
- rc = -EAGAIN;
- goto err;
- }
- interruptible_sleep_on(&serial->write_wait);
- if (signal_pending(current)) {
- rc = -ERESTARTSYS;
- goto err;
- }
- }
-
- /* at this point the URB is in our control, nobody else can submit it
- again (the only sudden transition was the one from EINPROGRESS to
- finished) */
-
- /* the next potential block is that our TX process might be throttled.
- The transition from throttled->not happens because of an Rx
- interrupt, and the wake_up occurs during the same interrupt, so we
- have to be careful to avoid a race that would cause us to sleep
- forever. */
-
- add_wait_queue(&serial->write_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- while (serial->tx_throttled) {
- /* device can't accomodate any more characters. Sleep until it
- can. Woken up by an Rx interrupt message, which clears
- tx_throttled first. */
- dbg(" tx_throttled, going to sleep");
- if (signal_pending(current)) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&serial->write_wait, &wait);
- dbg(" woke up because of signal");
- rc = -ERESTARTSYS;
- goto err;
- }
- schedule();
- dbg(" woke up");
- }
- remove_wait_queue(&serial->write_wait, &wait);
- set_current_state(TASK_RUNNING);
-
- 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
- how much room it really has */
- rc = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 0, /* value: 0 means "remaining room" */
- 0, /* index */
- &room,
- 1,
- 2*HZ);
- if (rc < 0) {
- dbg(" roomquery failed");
- return rc; /* failed */
- }
- if (rc == 0) {
- dbg(" roomquery returned 0 bytes");
- return -EIO; /* device didn't return any data */
- }
- dbg(" roomquery says %d", room);
- serial->tx_room = room;
- if (count > serial->tx_room) {
- /* we're about to completely fill the Tx buffer, so
- we'll be throttled afterwards. */
- count = serial->tx_room;
- request_unthrottle = 1;
- }
- }
- serial->tx_room -= count;
-
- if (count) {
- /* now transfer data */
- if (from_user) {
- copy_from_user(port->write_urb->transfer_buffer, buf, count);
- }
- else {
- memcpy (port->write_urb->transfer_buffer, buf, count);
- }
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
-
- if (usb_submit_urb(port->write_urb))
- dbg(" usb_submit_urb(write bulk) failed");
- }
- else {
- /* There wasn't any room left, so we are throttled until
- the buffer empties a bit */
- request_unthrottle = 1;
- }
-
- if (request_unthrottle) {
- dbg(" request_unthrottle");
- /* ask the device to tell us when the tx buffer becomes
- sufficiently empty */
- serial->tx_throttled = 1; /* block writers */
- rc = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- 7, /* request_unthrottle */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_OUT,
- 16, /* value: threshold */
- 0, /* index */
- NULL,
- 0,
- 2*HZ);
- }
-
- return (count);
- err:
- return (rc);
-}
-
-
-static void keyspan_pda_write_bulk_callback (struct urb *urb)
-{
- 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);
-
- wake_up_interruptible(&tty->write_wait);
-}
-
-
-static int keyspan_pda_write_room (struct usb_serial_port *port)
-{
- 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
- running a console through the device. */
-
- return (serial->tx_room);
-}
-
-
-static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
-{
- 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. */
- if (serial->tx_throttled)
- return 256;
- return 0;
-}
-
-
-static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
- unsigned char room;
- int rc;
-
- if (port->active) {
- return -EINVAL;
- }
- port->active = 1;
-
- /* find out how much room is in the Tx ring */
- rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 0, /* value */
- 0, /* index */
- &room,
- 1,
- 2*HZ);
- if (rc < 0) {
- dbg(" roomquery failed");
- return rc; /* failed */
- }
- if (rc == 0) {
- dbg(" roomquery returned 0 bytes");
- return -EIO; /* device didn't return any data */
- }
- serial->tx_room = room;
- serial->tx_throttled = room ? 0 : 1;
-
- /* the normal serial device seems to always turn on DTR and RTS here,
- so do the same */
- 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))
- dbg(" usb_submit_urb(read int) failed");
-
- return (0);
-}
-
-
-static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
-
- /* the normal serial device seems to always shut off DTR and RTS now */
- 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);
- port->active = 0;
-}
-
-
-/* download the firmware to a "fake" device (pre-renumeration) */
-static int keyspan_pda_fake_startup (struct usb_serial *serial)
-{
- int response;
- const struct ezusb_hex_record *record;
-
- /* download the firmware here ... */
- response = ezusb_set_reset(serial, 1);
-
- record = &keyspan_pda_firmware[0];
- while(record->address != 0xffff) {
- response = ezusb_writememory(serial, record->address,
- (unsigned char *)record->data,
- record->data_size, 0xa0);
- if (response < 0) {
- err("ezusb_writememory failed for Keyspan PDA "
- "firmware (%d %04X %p %d)",
- response,
- record->address, record->data, record->data_size);
- break;
- }
- record++;
- }
- /* bring device out of reset. Renumeration will occur in a moment
- and the new device will bind to the real driver */
- response = ezusb_set_reset(serial, 0);
-
- /* we want this device to fail to have a driver assigned to it. */
- return (1);
-}
-
-
-/* do some startup allocations not currently performed by usb_serial_probe() */
-static int keyspan_pda_startup (struct usb_serial *serial)
-{
- struct usb_endpoint_descriptor *intin;
- intin = serial->port[0].interrupt_in_endpoint;
-
- /* set up the receive interrupt urb */
- FILL_INT_URB(serial->port[0].read_urb, serial->dev,
- usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
- serial->port[0].interrupt_in_buffer,
- intin->wMaxPacketSize,
- keyspan_pda_rx_interrupt,
- serial,
- intin->bInterval);
-
- init_waitqueue_head(&serial->write_wait);
-
- return (0);
-}
-
-#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
-
-
-/*****************************************************************************
- * generic devices specific driver functions
- *****************************************************************************/
-static int generic_open (struct usb_serial_port *port, struct file *filp)
-{
- struct usb_serial *serial = port->serial;
-
- dbg("generic_open port %d", port->number);
-
- if (port->active) {
- dbg ("device already open");
- return -EINVAL;
- }
- port->active = 1;
-
- /* 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))
- dbg("usb_submit_urb(read bulk) failed");
- }
-
- return (0);
-}
-
-
-static void generic_close (struct usb_serial_port *port, struct file * filp)
-{
- struct usb_serial *serial = port->serial;
-
- 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);
- }
- if (serial->num_bulk_in) {
- usb_unlink_urb (port->read_urb);
- }
-
- port->active = 0;
-}
-
-
-static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
-{
- struct usb_serial *serial = port->serial;
-
- dbg("generic_serial_write port %d", port->number);
-
- if (count == 0) {
- dbg("write request of 0 bytes");
- return (0);
- }
-
- /* only do something if we have a bulk out endpoint */
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
- return (0);
- }
-
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
- if (from_user) {
- copy_from_user(port->write_urb->transfer_buffer, buf, count);
- }
- else {
- memcpy (port->write_urb->transfer_buffer, buf, count);
- }
-
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
-
- if (usb_submit_urb(port->write_urb))
- dbg("usb_submit_urb(write bulk) failed");
-
- return (count);
- }
-
- /* no bulk out, so return 0 bytes written */
- return (0);
-}
-
-
-static int generic_write_room (struct usb_serial_port *port)
-{
- struct usb_serial *serial = port->serial;
- int room;
-
- dbg("generic_write_room port %d", port->number);
-
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS)
- room = 0;
- else
- room = port->bulk_out_size;
- dbg("generic_write_room returns %d", room);
- return (room);
- }
-
- return (0);
-}
-
-
-static int generic_chars_in_buffer (struct usb_serial_port *port)
-{
- struct usb_serial *serial = port->serial;
-
- dbg("generic_chars_in_buffer port %d", port->number);
-
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
- return (port->bulk_out_size);
- }
- }
-
- return (0);
-}
-
-
-static void generic_read_bulk_callback (struct urb *urb)
-{
- 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;
- }
-
-#ifdef DEBUG
- if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
- printk ("%.2x ", data[i]);
- }
- 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);
- }
- tty_flip_buffer_push(tty);
- }
-
- /* Continue trying to always read */
- if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
-
- return;
-}
-
-
-static void generic_write_bulk_callback (struct urb *urb)
-{
- 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);
-
- wake_up_interruptible(&tty->write_wait);
-
- return;
-}
-
-
-static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_serial *serial = NULL;
- struct usb_serial_port *port;
- struct usb_interface_descriptor *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
- struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
- struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
- struct usb_serial_device_type *type;
- int device_num;
- int minor;
- int buffer_size;
- int i;
- char interrupt_pipe;
- char bulk_in_pipe;
- char bulk_out_pipe;
- int num_interrupt_in = 0;
- int num_bulk_in = 0;
- int num_bulk_out = 0;
- int num_ports;
-
- /* loop through our list of known serial converters, and see if this device matches */
- device_num = 0;
- while (usb_serial_devices[device_num] != NULL) {
- type = usb_serial_devices[device_num];
- dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
-
- /* look at the device descriptor */
- if ((dev->descriptor.idVendor == *(type->idVendor)) &&
- (dev->descriptor.idProduct == *(type->idProduct))) {
-
- dbg("descriptor matches...looking at the endpoints");
-
- /* descriptor matches, let's try to find the endpoints needed */
- interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
-
- /* check out the endpoints */
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- for (i = 0; i < interface->bNumEndpoints; ++i) {
- endpoint = &interface->endpoint[i];
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk in endpoint */
- dbg("found bulk in");
- bulk_in_pipe = HAS;
- bulk_in_endpoint[num_bulk_in] = endpoint;
- ++num_bulk_in;
- }
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk out endpoint */
- dbg("found bulk out");
- bulk_out_pipe = HAS;
- bulk_out_endpoint[num_bulk_out] = endpoint;
- ++num_bulk_out;
- }
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
- /* we found a interrupt in endpoint */
- dbg("found interrupt in");
- interrupt_pipe = HAS;
- interrupt_in_endpoint[num_interrupt_in] = endpoint;
- ++num_interrupt_in;
- }
-
- }
-
- /* verify that we found all of the endpoints that we need */
- if ((interrupt_pipe & type->needs_interrupt_in) &&
- (bulk_in_pipe & type->needs_bulk_in) &&
- (bulk_out_pipe & type->needs_bulk_out)) {
- /* found all that we need */
- info("%s converter detected", type->name);
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
- if (type == &generic_device)
- num_ports = num_bulk_out;
- else
-#endif
- num_ports = type->num_ports;
-
- serial = get_free_serial (num_ports, &minor);
- if (serial == NULL) {
- err("No more free serial devices");
- return NULL;
- }
-
- serial->dev = dev;
- serial->type = type;
- serial->minor = minor;
- serial->num_ports = num_ports;
- serial->num_bulk_in = num_bulk_in;
- serial->num_bulk_out = num_bulk_out;
- serial->num_interrupt_in = num_interrupt_in;
-
- /* collect interrupt_in endpoints now, because
- the keyspan_pda startup function needs
- to know about them */
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
- goto probe_error;
- }
- port->interrupt_in_endpoint = interrupt_in_endpoint[i];
- }
-
- /* if this device type has a startup function, call it */
- if (type->startup) {
- if (type->startup (serial)) {
- return_serial (serial);
- return NULL;
- }
- }
-
- /* 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) {
- err("Couldn't allocate bulk_in_buffer");
- 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, 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, 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) {
- err("Couldn't allocate bulk_out_buffer");
- 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, 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, 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;
- 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(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
-
- for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
- }
-
- MOD_INC_USE_COUNT;
-
- return serial;
- } else {
- info("descriptors matched, but endpoints did not");
- }
- }
-
- /* look at the next type in our list */
- ++device_num;
- }
-
-probe_error:
- if (serial) {
- 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) {
- 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) {
- 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);
-
- /* free up any memory that we allocated */
- kfree (serial);
- }
- return NULL;
-}
-
-
-static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
-{
- struct usb_serial *serial = (struct usb_serial *) ptr;
- struct usb_serial_port *port;
- int i;
-
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i)
- serial->port[i].active = 0;
-
- 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);
- }
-
- for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
- }
-
- /* return the minor range that this device had */
- return_serial (serial);
-
- /* free up any memory that we allocated */
- kfree (serial);
-
- } else {
- info("device disconnected");
- }
-
- MOD_DEC_USE_COUNT;
-}
-
-
-static struct tty_driver serial_tty_driver = {
- magic: TTY_DRIVER_MAGIC,
- driver_name: "usb",
- name: "ttyUSB%d",
- major: SERIAL_TTY_MAJOR,
- minor_start: 0,
- num: SERIAL_TTY_MINORS,
- type: TTY_DRIVER_TYPE_SERIAL,
- subtype: SERIAL_TYPE_NORMAL,
- flags: TTY_DRIVER_REAL_RAW,
- refcount: &serial_refcount,
- table: serial_tty,
- proc_entry: NULL,
- other: NULL,
- termios: serial_termios,
- termios_locked: serial_termios_locked,
-
- open: serial_open,
- close: serial_close,
- write: serial_write,
- put_char: NULL,
- flush_chars: NULL,
- write_room: serial_write_room,
- ioctl: serial_ioctl,
- set_termios: serial_set_termios,
- set_ldisc: NULL,
- throttle: serial_throttle,
- unthrottle: serial_unthrottle,
- stop: NULL,
- start: NULL,
- hangup: NULL,
- break_ctl: serial_break,
- wait_until_sent: NULL,
- send_xchar: NULL,
- read_proc: NULL,
- chars_in_buffer: serial_chars_in_buffer,
- flush_buffer: NULL
-};
-
-
-int usb_serial_init(void)
-{
- int i;
-
- /* Initalize our global data */
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
- serial_table[i] = NULL;
- }
-
- /* register the tty driver */
- serial_tty_driver.init_termios = tty_std_termios;
- serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- if (tty_register_driver (&serial_tty_driver)) {
- err("failed to register tty driver");
- return -EPERM;
- }
-
- /* register the USB driver */
- if (usb_register(&usb_serial_driver) < 0) {
- tty_unregister_driver(&serial_tty_driver);
- return -1;
- }
-
- info("support registered");
- return 0;
-}
-
-
-void usb_serial_exit(void)
-{
- tty_unregister_driver(&serial_tty_driver);
- usb_deregister(&usb_serial_driver);
-}
-
-
-module_init(usb_serial_init);
-module_exit(usb_serial_exit);
-
-
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 48082101a..6211a6309 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -19,47 +19,22 @@
#include <linux/config.h>
-/* Module information */
-MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
-MODULE_DESCRIPTION("USB Serial Driver");
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-static __u16 vendor = 0x05f9;
-static __u16 product = 0xffff;
-MODULE_PARM(vendor, "i");
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-MODULE_PARM(product, "i");
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-#endif
-
-
-/* USB Serial devices vendor ids and device ids that this driver supports */
-#define CONNECT_TECH_VENDOR_ID 0x0710
-#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
-#define CONNECT_TECH_WHITE_HEAT_ID 0x8001
-#define HANDSPRING_VENDOR_ID 0x082d
-#define HANDSPRING_VISOR_ID 0x0100
-#define FTDI_VENDOR_ID 0x0403
-#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372
-#define KEYSPAN_VENDOR_ID 0x06cd
-#define KEYSPAN_PDA_FAKE_ID 0x0103
-#define KEYSPAN_PDA_ID 0x0104 /* no clue */
-
#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
#define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */
-
-#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
+#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 */
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
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 */
+ struct tty_struct * tty; /* the coresponding tty for this port */
unsigned char minor;
unsigned char number;
char active; /* someone has this device open */
@@ -81,8 +56,9 @@ struct usb_serial_port {
struct usb_serial {
int magic;
struct usb_device * dev;
- struct usb_serial_device_type * type;
- unsigned char minor;
+ struct usb_serial_device_type * type; /* the type of usb serial device this is */
+ struct tty_driver * tty_driver; /* the tty_driver for this device */
+ unsigned char minor; /* the starting minor number for this device */
unsigned char num_ports; /* the number of ports this device has */
char num_interrupt_in; /* number of interrupt in endpoints we have */
char num_bulk_in; /* number of bulk in endpoints we have */
@@ -141,299 +117,67 @@ 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_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);
-
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-/* All of the device info needed for the Generic Serial Converter */
-static struct usb_serial_device_type generic_device = {
- name: "Generic",
- idVendor: &vendor, /* use the user specified vendor id */
- idProduct: &product, /* use the user specified product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
-/* function prototypes for the Connect Tech WhiteHEAT serial converter */
-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 */
-static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID;
-static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID;
-static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID;
-static struct usb_serial_device_type whiteheat_fake_device = {
- name: "Connect Tech - WhiteHEAT - (prerenumeration)",
- idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
- idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- 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 = {
- name: "Connect Tech - WhiteHEAT",
- idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
- idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 4,
- open: whiteheat_open,
- close: whiteheat_close,
- throttle: whiteheat_throttle,
- unthrottle: whiteheat_unthrottle,
- set_termios: whiteheat_set_termios,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_VISOR
-
-/****************************************************************************
- * Handspring Visor Vendor specific request codes (bRequest values)
- * A big thank you to Handspring for providing the following information.
- * If anyone wants the original file where these values and structures came
- * from, send email to <greg@kroah.com>.
- ****************************************************************************/
-
-/****************************************************************************
- * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
- * are available to be transfered to the host for the specified endpoint.
- * Currently this is not used, and always returns 0x0001
- ****************************************************************************/
-#define VISOR_REQUEST_BYTES_AVAILABLE 0x01
-
-/****************************************************************************
- * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
- * is now closing the pipe. An empty packet is sent in response.
- ****************************************************************************/
-#define VISOR_CLOSE_NOTIFICATION 0x02
-
-/****************************************************************************
- * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
- * get the endpoints used by the connection.
- ****************************************************************************/
-#define VISOR_GET_CONNECTION_INFORMATION 0x03
-
-
-/****************************************************************************
- * VISOR_GET_CONNECTION_INFORMATION returns data in the following format
- ****************************************************************************/
-struct visor_connection_info {
- __u16 num_ports;
- struct {
- __u8 port_function_id;
- __u8 port;
- } connections[2];
-};
-
-/* struct visor_connection_info.connection[x].port defines: */
-#define VISOR_ENDPOINT_1 0x01
-#define VISOR_ENDPOINT_2 0x02
-
-/* struct visor_connection_info.connection[x].port_function_id defines: */
-#define VISOR_FUNCTION_GENERIC 0x00
-#define VISOR_FUNCTION_DEBUGGER 0x01
-#define VISOR_FUNCTION_HOTSYNC 0x02
-#define VISOR_FUNCTION_CONSOLE 0x03
-#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04
-
-
-/* function prototypes for a handspring visor */
-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;
-static __u16 handspring_product_id = HANDSPRING_VISOR_ID;
-static struct usb_serial_device_type handspring_device = {
- name: "Handspring Visor",
- idVendor: &handspring_vendor_id, /* the Handspring vendor ID */
- idProduct: &handspring_product_id, /* the Handspring Visor product id */
- needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
- needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
- needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
- num_interrupt_in: 0,
- num_bulk_in: 2,
- num_bulk_out: 2,
- num_ports: 2,
- open: visor_open,
- close: visor_close,
- throttle: visor_throttle,
- unthrottle: visor_unthrottle,
- startup: visor_startup,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
-/* function prototypes for a FTDI serial converter */
-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 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;
-static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID;
-static struct usb_serial_device_type ftdi_sio_device = {
- name: "FTDI SIO",
- idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */
- idProduct: &ftdi_sio_product_id, /* the FTDI SIO product id */
- needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
- needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
- needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
- num_interrupt_in: 0,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- 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
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
-/* function prototypes for a Keyspan PDA serial converter */
-static int keyspan_pda_open (struct usb_serial_port *port,
- struct file *filp);
-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 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 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 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 usb_serial_port *port,
- struct termios *old);
-static void keyspan_pda_break_ctl (struct usb_serial_port *port,
- int break_state);
-static int keyspan_pda_fake_startup (struct usb_serial *serial);
-
-/* All of the device info needed for the Keyspan PDA serial converter */
-static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID;
-static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID;
-static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID;
-static struct usb_serial_device_type keyspan_pda_fake_device = {
- name: "Keyspan PDA - (prerenumeration)",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- startup: keyspan_pda_fake_startup
-};
-static struct usb_serial_device_type keyspan_pda_device = {
- name: "Keyspan PDA",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */
- needs_interrupt_in: MUST_HAVE,
- needs_bulk_in: DONT_CARE,
- needs_bulk_out: MUST_HAVE,
- num_interrupt_in: 1,
- num_bulk_in: 0,
- num_bulk_out: 1,
- num_ports: 1,
- 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,
- chars_in_buffer: keyspan_pda_chars_in_buffer,
- throttle: keyspan_pda_rx_throttle,
- unthrottle: keyspan_pda_rx_unthrottle,
- startup: keyspan_pda_startup,
- ioctl: keyspan_pda_ioctl,
- set_termios: keyspan_pda_set_termios,
- break_ctl: keyspan_pda_break_ctl,
-};
-#endif
-
-
-/* To add support for another serial converter, create a usb_serial_device_type
- structure for that device, and add it to this list, making sure that the
- last entry is NULL. */
-static struct usb_serial_device_type *usb_serial_devices[] = {
-#ifdef CONFIG_USB_SERIAL_GENERIC
- &generic_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_WHITEHEAT
- &whiteheat_fake_device,
- &whiteheat_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_VISOR
- &handspring_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_FTDI_SIO
- &ftdi_sio_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
- &keyspan_pda_fake_device,
- &keyspan_pda_device,
-#endif
- NULL
-};
+extern struct usb_serial_device_type handspring_device;
+extern struct usb_serial_device_type whiteheat_fake_device;
+extern struct usb_serial_device_type whiteheat_device;
+extern struct usb_serial_device_type ftdi_sio_device;
+extern struct usb_serial_device_type keyspan_pda_fake_device;
+extern struct usb_serial_device_type keyspan_pda_device;
/* determine if we should include the EzUSB loader functions */
#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_WHITEHEAT)
#define USES_EZUSB_FUNCTIONS
+ extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
+ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
#else
#undef USES_EZUSB_FUNCTIONS
#endif
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+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 inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
+{
+ 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;
+}
+
+
#endif /* ifdef __LINUX_USB_SERIAL_H */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
new file mode 100644
index 000000000..0c1972675
--- /dev/null
+++ b/drivers/usb/serial/usbserial.c
@@ -0,0 +1,1323 @@
+/*
+ * USB Serial Converter driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver was originally based on the ACM driver by Armin Fuerst (which was
+ * based on a driver by Brad Keryan)
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (04/03/2000) gkh
+ * Changed the probe process to remove the module unload races.
+ * Changed where the tty layer gets initialized to have devfs work nicer.
+ * Added initial devfs support.
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ * (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.
+ *
+ * (03/06/2000) gkh
+ * Added the keyspan pda code from Brian Warner <warner@lothar.com>
+ * Moved a bunch of the port specific stuff into its own structure. This
+ * is in anticipation of the true multiport devices (there's a bug if you
+ * try to access more than one port of any multiport device right now)
+ *
+ * (02/21/2000) gkh
+ * Made it so that any serial devices only have to specify which functions
+ * they want to overload from the generic function calls (great,
+ * inheritance in C, in a driver, just what I wanted...)
+ * Added support for set_termios and ioctl function calls. No drivers take
+ * advantage of this yet.
+ * Removed the #ifdef MODULE, now there is no module specific code.
+ * Cleaned up a few comments in usb-serial.h that were wrong (thanks again
+ * to Miles Lott).
+ * Small fix to get_free_serial.
+ *
+ * (02/14/2000) gkh
+ * Removed the Belkin and Peracom functionality from the driver due to
+ * the lack of support from the vendor, and me not wanting people to
+ * accidenatly buy the device, expecting it to work with Linux.
+ * Added read_bulk_callback and write_bulk_callback to the type structure
+ * for the needs of the FTDI and WhiteHEAT driver.
+ * Changed all reverences to FTDI to FTDI_SIO at the request of Bill
+ * Ryder.
+ * Changed the output urb size back to the max endpoint size to make
+ * the ftdi_sio driver have it easier, and due to the fact that it didn't
+ * really increase the speed any.
+ *
+ * (02/11/2000) gkh
+ * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
+ * patch from Miles Lott (milos@insync.net).
+ * Fixed bug with not restoring the minor range that a device grabs, if
+ * the startup function fails (thanks Miles for finding this).
+ *
+ * (02/05/2000) gkh
+ * Added initial framework for the Keyspan PDA serial converter so that
+ * Brian Warner has a place to put his code.
+ * Made the ezusb specific functions generic enough that different
+ * devices can use them (whiteheat and keyspan_pda both need them).
+ * Split out a whole bunch of structure and other stuff to a seperate
+ * usb-serial.h file.
+ * Made the Visor connection messages a little more understandable, now
+ * that Miles Lott (milos@insync.net) has gotten the Generic channel to
+ * work. Also made them always show up in the log file.
+ *
+ * (01/25/2000) gkh
+ * Added initial framework for FTDI serial converter so that Bill Ryder
+ * has a place to put his code.
+ * Added the vendor specific info from Handspring. Now we can print out
+ * informational debug messages as well as understand what is happening.
+ *
+ * (01/23/2000) gkh
+ * Fixed problem of crash when trying to open a port that didn't have a
+ * device assigned to it. Made the minor node finding a little smarter,
+ * now it looks to find a continous space for the new device.
+ *
+ * (01/21/2000) gkh
+ * Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
+ * Fixed get_serial_by_minor which was all messed up for multi port
+ * devices. Fixed multi port problem for generic devices. Now the number
+ * of ports is determined by the number of bulk out endpoints for the
+ * generic device.
+ *
+ * (01/19/2000) gkh
+ * Removed lots of cruft that was around from the old (pre urb) driver
+ * interface.
+ * Made the serial_table dynamic. This should save lots of memory when
+ * the number of minor nodes goes up to 256.
+ * Added initial support for devices that have more than one port.
+ * Added more debugging comments for the Visor, and added a needed
+ * set_configuration call.
+ *
+ * (01/17/2000) gkh
+ * Fixed the WhiteHEAT firmware (my processing tool had a bug)
+ * and added new debug loader firmware for it.
+ * Removed the put_char function as it isn't really needed.
+ * Added visor startup commands as found by the Win98 dump.
+ *
+ * (01/13/2000) gkh
+ * Fixed the vendor id for the generic driver to the one I meant it to be.
+ *
+ * (01/12/2000) gkh
+ * Forget the version numbering...that's pretty useless...
+ * Made the driver able to be compiled so that the user can select which
+ * converter they want to use. This allows people who only want the Visor
+ * support to not pay the memory size price of the WhiteHEAT.
+ * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
+ * grabbed the root hub. Not good.
+ *
+ * version 0.4.0 (01/10/2000) gkh
+ * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
+ * device. Added startup function to allow firmware to be downloaded to
+ * a device if it needs to be.
+ * Added firmware download logic to the WhiteHEAT device.
+ * Started to add #defines to split up the different drivers for potential
+ * configuration option.
+ *
+ * version 0.3.1 (12/30/99) gkh
+ * Fixed problems with urb for bulk out.
+ * Added initial support for multiple sets of endpoints. This enables
+ * the Handspring Visor to be attached successfully. Only the first
+ * bulk in / bulk out endpoint pair is being used right now.
+ *
+ * version 0.3.0 (12/27/99) gkh
+ * Added initial support for the Handspring Visor based on a patch from
+ * Miles Lott (milos@sneety.insync.net)
+ * Cleaned up the code a bunch and converted over to using urbs only.
+ *
+ * version 0.2.3 (12/21/99) gkh
+ * Added initial support for the Connect Tech WhiteHEAT converter.
+ * Incremented the number of ports in expectation of getting the
+ * WhiteHEAT to work properly (4 ports per connection).
+ * Added notification on insertion and removal of what port the
+ * device is/was connected to (and what kind of device it was).
+ *
+ * version 0.2.2 (12/16/99) gkh
+ * Changed major number to the new allocated number. We're legal now!
+ *
+ * version 0.2.1 (12/14/99) gkh
+ * Fixed bug that happens when device node is opened when there isn't a
+ * device attached to it. Thanks to marek@webdesign.no for noticing this.
+ *
+ * version 0.2.0 (11/10/99) gkh
+ * Split up internals to make it easier to add different types of serial
+ * converters to the code.
+ * Added a "generic" driver that gets it's vendor and product id
+ * from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
+ * for the idea and sample code (from the usb scanner driver.)
+ * Cleared up any licensing questions by releasing it under the GNU GPL.
+ *
+ * version 0.1.2 (10/25/99) gkh
+ * Fixed bug in detecting device.
+ *
+ * version 0.1.1 (10/05/99) gkh
+ * Changed the major number to not conflict with anything else.
+ *
+ * version 0.1 (09/28/99) gkh
+ * Can recognize the two different devices and start up a read from
+ * device when asked to. Writes also work. No control signals yet, this
+ * all is vendor specific data (i.e. no spec), also no control for
+ * different baud rates or other bit settings.
+ * Currently we are using the same devid as the acm driver. This needs
+ * to change.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+/* Module information */
+MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
+MODULE_DESCRIPTION("USB Serial Driver");
+
+#include "usb-serial.h"
+
+
+/* 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_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);
+
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+static __u16 vendor = 0x05f9;
+static __u16 product = 0xffff;
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+/* All of the device info needed for the Generic Serial Converter */
+static struct usb_serial_device_type generic_device = {
+ name: "Generic",
+ idVendor: &vendor, /* use the user specified vendor id */
+ idProduct: &product, /* use the user specified product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+};
+#endif
+
+
+/* To add support for another serial converter, create a usb_serial_device_type
+ structure for that device, and add it to this list, making sure that the
+ last entry is NULL. */
+static struct usb_serial_device_type *usb_serial_devices[] = {
+#ifdef CONFIG_USB_SERIAL_GENERIC
+ &generic_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
+ &whiteheat_fake_device,
+ &whiteheat_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_VISOR
+ &handspring_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
+ &ftdi_sio_device,
+#endif
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
+ &keyspan_pda_fake_device,
+ &keyspan_pda_device,
+#endif
+ NULL
+};
+
+
+/* variables needed for the tty_driver structure */
+static char *driver_name = "usb";
+static char *tty_driver_name = "usb/tty/%d";
+
+
+/* local function prototypes */
+static int serial_open (struct tty_struct *tty, struct file * filp);
+static void serial_close (struct tty_struct *tty, struct file * filp);
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static int serial_write_room (struct tty_struct *tty);
+static int serial_chars_in_buffer (struct tty_struct *tty);
+static void serial_throttle (struct tty_struct * tty);
+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);
+static void serial_set_termios (struct tty_struct *tty, struct termios * old);
+
+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 = {
+ name: "serial",
+ probe: usb_serial_probe,
+ disconnect: usb_serial_disconnect,
+};
+
+static int serial_refcount;
+static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
+static struct termios * serial_termios[SERIAL_TTY_MINORS];
+static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
+static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
+
+
+
+static struct usb_serial *get_serial_by_minor (int minor)
+{
+ return serial_table[minor];
+}
+
+
+static struct usb_serial *get_free_serial (int num_ports, int *minor)
+{
+ struct usb_serial *serial = NULL;
+ int i, j;
+ int good_spot;
+
+ dbg("get_free_serial %d", num_ports);
+
+ *minor = 0;
+ for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ if (serial_table[i])
+ continue;
+
+ good_spot = 1;
+ for (j = 1; j <= num_ports-1; ++j)
+ if (serial_table[i+j])
+ good_spot = 0;
+ if (good_spot == 0)
+ continue;
+
+ if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
+ err("Out of memory");
+ 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);
+ for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
+ serial_table[i] = serial;
+ return serial;
+ }
+ return NULL;
+}
+
+
+static void return_serial (struct usb_serial *serial)
+{
+ int i;
+
+ dbg("return_serial");
+
+ if (serial == NULL)
+ return;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ serial_table[serial->minor + i] = NULL;
+ }
+
+ return;
+}
+
+
+#ifdef USES_EZUSB_FUNCTIONS
+/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
+#define CPUCS_REG 0x7F92
+
+int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
+{
+ int result;
+ unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL);
+
+// dbg("ezusb_writememory %x, %d", address, length);
+
+ if (!transfer_buffer) {
+ err("ezusb_writememory: kmalloc(%d) failed.", length);
+ return -ENOMEM;
+ }
+ memcpy (transfer_buffer, data, length);
+ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
+ kfree (transfer_buffer);
+ return result;
+}
+
+
+int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
+{
+ int response;
+ dbg("ezusb_set_reset: %d", reset_bit);
+ response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
+ if (response < 0) {
+ err("ezusb_set_reset %d failed", reset_bit);
+ }
+ return response;
+}
+
+#endif /* USES_EZUSB_FUNCTIONS */
+
+
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
+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");
+
+ /* initialize the pointer incase something fails */
+ tty->driver_data = NULL;
+
+ /* get the serial object associated with this tty pointer */
+ serial = get_serial_by_minor (MINOR(tty->device));
+
+ if (serial_paranoia_check (serial, "serial_open")) {
+ return -ENODEV;
+ }
+
+ /* 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(port, filp));
+ } else {
+ return (generic_open(port, filp));
+ }
+}
+
+
+static void serial_close(struct tty_struct *tty, struct file * filp)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_close");
+
+ if (port_paranoia_check (port, "serial_close")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_close")) {
+ return;
+ }
+
+ 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(port, filp);
+ } else {
+ generic_close(port, filp);
+ }
+}
+
+
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_write");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
+ }
+
+ 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(port, from_user, buf, count));
+ } else {
+ return (generic_write(port, from_user, buf, count));
+ }
+}
+
+
+static int serial_write_room (struct tty_struct *tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_write_room");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
+ }
+
+ 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(port));
+ } else {
+ return (generic_write_room(port));
+ }
+}
+
+
+static int serial_chars_in_buffer (struct tty_struct *tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_chars_in_buffer");
+
+ if (port_paranoia_check (port, "serial_chars_in_buffer")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+ return -ENODEV;
+ }
+
+ 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(port));
+ } else {
+ return (generic_chars_in_buffer(port));
+ }
+}
+
+
+static void serial_throttle (struct tty_struct * tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_throttle");
+
+ if (port_paranoia_check (port, "serial_throttle")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_throttle")) {
+ return;
+ }
+
+ 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(port);
+ }
+
+ return;
+}
+
+
+static void serial_unthrottle (struct tty_struct * tty)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_unthrottle");
+
+ if (port_paranoia_check (port, "serial_unthrottle")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_unthrottle")) {
+ return;
+ }
+
+ 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(port);
+ }
+
+ return;
+}
+
+
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_ioctl");
+
+ if (port_paranoia_check (port, "serial_ioctl")) {
+ return -ENODEV;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_ioctl")) {
+ return -ENODEV;
+ }
+
+ 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(port, file, cmd, arg));
+ } else {
+ return -ENOIOCTLCMD;
+ }
+}
+
+
+static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_set_termios");
+
+ if (port_paranoia_check (port, "serial_set_termios")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_set_termios")) {
+ return;
+ }
+
+ 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(port, old);
+ }
+
+ return;
+}
+
+
+static void serial_break (struct tty_struct *tty, int break_state)
+{
+ 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;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_break")) {
+ return;
+ }
+
+ 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(port, break_state);
+ }
+}
+
+
+
+/*****************************************************************************
+ * generic devices specific driver functions
+ *****************************************************************************/
+static int generic_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+
+ dbg("generic_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ /* 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))
+ dbg("usb_submit_urb(read bulk) failed");
+ }
+
+ return (0);
+}
+
+
+static void generic_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial = port->serial;
+
+ 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);
+ }
+ if (serial->num_bulk_in) {
+ usb_unlink_urb (port->read_urb);
+ }
+
+ port->active = 0;
+}
+
+
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+
+ dbg("generic_serial_write port %d", port->number);
+
+ if (count == 0) {
+ dbg("write request of 0 bytes");
+ return (0);
+ }
+
+ /* only do something if we have a bulk out endpoint */
+ if (serial->num_bulk_out) {
+ if (port->write_urb->status == -EINPROGRESS) {
+ dbg ("already writing");
+ return (0);
+ }
+
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+ if (from_user) {
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
+ }
+ else {
+ memcpy (port->write_urb->transfer_buffer, buf, count);
+ }
+
+ /* send the data out the bulk port */
+ port->write_urb->transfer_buffer_length = count;
+
+ if (usb_submit_urb(port->write_urb))
+ dbg("usb_submit_urb(write bulk) failed");
+
+ return (count);
+ }
+
+ /* no bulk out, so return 0 bytes written */
+ return (0);
+}
+
+
+static int generic_write_room (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ int room;
+
+ dbg("generic_write_room port %d", port->number);
+
+ if (serial->num_bulk_out) {
+ if (port->write_urb->status == -EINPROGRESS)
+ room = 0;
+ else
+ room = port->bulk_out_size;
+ dbg("generic_write_room returns %d", room);
+ return (room);
+ }
+
+ return (0);
+}
+
+
+static int generic_chars_in_buffer (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+
+ dbg("generic_chars_in_buffer port %d", port->number);
+
+ if (serial->num_bulk_out) {
+ if (port->write_urb->status == -EINPROGRESS) {
+ return (port->bulk_out_size);
+ }
+ }
+
+ return (0);
+}
+
+
+static void generic_read_bulk_callback (struct urb *urb)
+{
+ 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;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("%.2x ", data[i]);
+ }
+ 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);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+
+ return;
+}
+
+
+static void generic_write_bulk_callback (struct urb *urb)
+{
+ 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);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ return;
+}
+
+
+static struct tty_driver * usb_serial_tty_driver_init (struct usb_serial *serial)
+{
+ struct tty_driver *serial_tty_driver;
+
+ if (!(serial_tty_driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL))) {
+ err("Out of memory");
+ return NULL;
+ }
+
+ memset (serial_tty_driver, 0x00, sizeof(struct tty_driver));
+
+ /* initialize the entries that we don't want to be NULL */
+ serial_tty_driver->magic = TTY_DRIVER_MAGIC;
+ serial_tty_driver->driver_name = driver_name;
+ serial_tty_driver->name = tty_driver_name;
+ serial_tty_driver->major = SERIAL_TTY_MAJOR;
+ serial_tty_driver->minor_start = serial->minor;
+ serial_tty_driver->num = serial->num_ports;
+ serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ serial_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+ serial_tty_driver->refcount = &serial_refcount;
+ serial_tty_driver->table = serial_tty;
+ serial_tty_driver->termios = serial_termios;
+ serial_tty_driver->termios_locked = serial_termios_locked;
+ serial_tty_driver->open = serial_open;
+ serial_tty_driver->close = serial_close;
+ serial_tty_driver->write = serial_write;
+ serial_tty_driver->write_room = serial_write_room;
+ serial_tty_driver->ioctl = serial_ioctl;
+ serial_tty_driver->set_termios = serial_set_termios;
+ serial_tty_driver->throttle = serial_throttle;
+ serial_tty_driver->unthrottle = serial_unthrottle;
+ serial_tty_driver->break_ctl = serial_break;
+ serial_tty_driver->chars_in_buffer = serial_chars_in_buffer;
+ serial_tty_driver->init_termios = tty_std_termios;
+ serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+ return serial_tty_driver;
+}
+
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_serial *serial = NULL;
+ struct usb_serial_port *port;
+ struct usb_interface_descriptor *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
+ struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
+ struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
+ struct usb_serial_device_type *type;
+ int device_num;
+ int minor;
+ int buffer_size;
+ int i;
+ char interrupt_pipe;
+ char bulk_in_pipe;
+ char bulk_out_pipe;
+ int num_interrupt_in = 0;
+ int num_bulk_in = 0;
+ int num_bulk_out = 0;
+ int num_ports;
+
+ /* loop through our list of known serial converters, and see if this device matches */
+ device_num = 0;
+ while (usb_serial_devices[device_num] != NULL) {
+ type = usb_serial_devices[device_num];
+ dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+
+ /* look at the device descriptor */
+ if ((dev->descriptor.idVendor == *(type->idVendor)) &&
+ (dev->descriptor.idProduct == *(type->idProduct))) {
+
+ dbg("descriptor matches...looking at the endpoints");
+
+ /* descriptor matches, let's try to find the endpoints needed */
+ interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+
+ /* check out the endpoints */
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ for (i = 0; i < interface->bNumEndpoints; ++i) {
+ endpoint = &interface->endpoint[i];
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in");
+ bulk_in_pipe = HAS;
+ bulk_in_endpoint[num_bulk_in] = endpoint;
+ ++num_bulk_in;
+ }
+
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out");
+ bulk_out_pipe = HAS;
+ bulk_out_endpoint[num_bulk_out] = endpoint;
+ ++num_bulk_out;
+ }
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x03)) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in");
+ interrupt_pipe = HAS;
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
+ ++num_interrupt_in;
+ }
+
+ }
+
+ /* verify that we found all of the endpoints that we need */
+ if ((interrupt_pipe & type->needs_interrupt_in) &&
+ (bulk_in_pipe & type->needs_bulk_in) &&
+ (bulk_out_pipe & type->needs_bulk_out)) {
+ /* found all that we need */
+ MOD_INC_USE_COUNT;
+ info("%s converter detected", type->name);
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+ if (type == &generic_device)
+ num_ports = num_bulk_out;
+ else
+#endif
+ num_ports = type->num_ports;
+
+ serial = get_free_serial (num_ports, &minor);
+ if (serial == NULL) {
+ err("No more free serial devices");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+
+ serial->dev = dev;
+ serial->type = type;
+ serial->minor = minor;
+ serial->num_ports = num_ports;
+ serial->num_bulk_in = num_bulk_in;
+ serial->num_bulk_out = num_bulk_out;
+ serial->num_interrupt_in = num_interrupt_in;
+
+ /* initialize a tty_driver for this device */
+ serial->tty_driver = usb_serial_tty_driver_init (serial);
+ if (serial->tty_driver == NULL) {
+ err("Can't create a tty_serial_driver");
+ goto probe_error;
+ }
+
+ if (tty_register_driver (serial->tty_driver)) {
+ err("failed to register tty driver");
+ goto probe_error;
+ }
+
+ /* collect interrupt_in endpoints now, because
+ the keyspan_pda startup function needs
+ to know about them */
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
+ port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->interrupt_in_buffer) {
+ err("Couldn't allocate interrupt_in_buffer");
+ goto probe_error;
+ }
+ port->interrupt_in_endpoint = interrupt_in_endpoint[i];
+ }
+
+ /* if this device type has a startup function, call it */
+ if (type->startup) {
+ if (type->startup (serial)) {
+ goto probe_error;
+ }
+ }
+
+ /* 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) {
+ err("Couldn't allocate bulk_in_buffer");
+ 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, 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, 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) {
+ err("Couldn't allocate bulk_out_buffer");
+ 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, 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, 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;
+ 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(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
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
+ }
+
+ return serial;
+ } else {
+ info("descriptors matched, but endpoints did not");
+ }
+ }
+
+ /* look at the next type in our list */
+ ++device_num;
+ }
+
+probe_error:
+ if (serial) {
+ 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) {
+ 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) {
+ 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);
+
+ /* if this device has a tty_driver, then unregister it and free it */
+ if (serial->tty_driver) {
+ tty_unregister_driver (serial->tty_driver);
+ kfree (serial->tty_driver);
+ serial->tty_driver = NULL;
+ }
+
+ /* free up any memory that we allocated */
+ kfree (serial);
+ MOD_DEC_USE_COUNT;
+ }
+ return NULL;
+}
+
+
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
+{
+ struct usb_serial *serial = (struct usb_serial *) ptr;
+ struct usb_serial_port *port;
+ int i;
+
+ if (serial) {
+ for (i = 0; i < serial->num_ports; ++i)
+ serial->port[i].active = 0;
+
+ 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);
+ }
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
+ }
+
+ /* return the minor range that this device had */
+ return_serial (serial);
+
+ /* if this device has a tty_driver, then unregister it and free it */
+ if (serial->tty_driver) {
+ tty_unregister_driver (serial->tty_driver);
+ kfree (serial->tty_driver);
+ serial->tty_driver = NULL;
+ }
+ /* free up any memory that we allocated */
+ kfree (serial);
+
+ } else {
+ info("device disconnected");
+ }
+
+ MOD_DEC_USE_COUNT;
+}
+
+
+int usb_serial_init(void)
+{
+ int i;
+
+ /* Initalize our global data */
+ for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+ serial_table[i] = NULL;
+ }
+
+ /* register the USB driver */
+ if (usb_register(&usb_serial_driver) < 0) {
+ return -1;
+ }
+
+ info("support registered");
+ return 0;
+}
+
+
+void usb_serial_exit(void)
+{
+ usb_deregister(&usb_serial_driver);
+}
+
+
+module_init(usb_serial_init);
+module_exit(usb_serial_exit);
+
+
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
new file mode 100644
index 000000000..6832814da
--- /dev/null
+++ b/drivers/usb/serial/visor.c
@@ -0,0 +1,209 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_VISOR
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "visor.h"
+
+
+/* function prototypes for a handspring visor */
+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;
+static __u16 handspring_product_id = HANDSPRING_VISOR_ID;
+struct usb_serial_device_type handspring_device = {
+ name: "Handspring Visor",
+ idVendor: &handspring_vendor_id, /* the Handspring vendor ID */
+ idProduct: &handspring_product_id, /* the Handspring Visor product id */
+ needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_interrupt_in: 0,
+ num_bulk_in: 2,
+ num_bulk_out: 2,
+ num_ports: 2,
+ open: visor_open,
+ close: visor_close,
+ throttle: visor_throttle,
+ unthrottle: visor_unthrottle,
+ startup: visor_startup,
+};
+
+
+/******************************************************************************
+ * Handspring Visor specific driver functions
+ ******************************************************************************/
+static int visor_open (struct usb_serial_port *port, struct file *filp)
+{
+ dbg("visor_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+
+ port->active = 1;
+
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg("usb_submit_urb(read bulk) failed");
+
+ return (0);
+}
+
+
+static void visor_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
+
+ dbg("visor_close port %d", port->number);
+
+ if (!transfer_buffer) {
+ 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,
+ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ }
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+}
+
+
+static void visor_throttle (struct usb_serial_port *port)
+{
+ dbg("visor_throttle port %d", port->number);
+
+ usb_unlink_urb (port->read_urb);
+
+ return;
+}
+
+
+static void visor_unthrottle (struct usb_serial_port *port)
+{
+ dbg("visor_unthrottle port %d", port->number);
+
+ if (usb_unlink_urb (port->read_urb))
+ dbg("usb_submit_urb(read bulk) failed");
+
+ return;
+}
+
+
+static int visor_startup (struct usb_serial *serial)
+{
+ int response;
+ int i;
+ unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
+
+ if (!transfer_buffer) {
+ err("visor_startup: kmalloc(%d) failed.", 256);
+ return -ENOMEM;
+ }
+
+ dbg("visor_startup");
+
+ dbg("visor_setup: Set config to 1");
+ usb_set_configuration (serial->dev, 1);
+
+ /* send a get connection info request */
+ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
+ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ if (response < 0) {
+ err("visor_startup: error getting connection information");
+ } else {
+ struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
+ char *string;
+ info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
+ for (i = 0; i < connection_info->num_ports; ++i) {
+ switch (connection_info->connections[i].port_function_id) {
+ case VISOR_FUNCTION_GENERIC:
+ string = "Generic";
+ break;
+ case VISOR_FUNCTION_DEBUGGER:
+ string = "Debugger";
+ break;
+ case VISOR_FUNCTION_HOTSYNC:
+ string = "HotSync";
+ break;
+ case VISOR_FUNCTION_CONSOLE:
+ string = "Console";
+ break;
+ case VISOR_FUNCTION_REMOTE_FILE_SYS:
+ string = "Remote File System";
+ break;
+ default:
+ string = "unknown";
+ break;
+ }
+ info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
+ }
+ }
+
+ /* ask for the number of bytes available, but ignore the response as it is broken */
+ response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
+ 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
+ if (response < 0) {
+ err("visor_startup: error getting bytes available request");
+ }
+
+ kfree (transfer_buffer);
+
+ /* continue on with initialization */
+ return (0);
+}
+
+
+#endif /* CONFIG_USB_SERIAL_VISOR*/
+
+
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
new file mode 100644
index 000000000..a1173697d
--- /dev/null
+++ b/drivers/usb/serial/visor.h
@@ -0,0 +1,74 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#ifndef __LINUX_USB_SERIAL_VISOR_H
+#define __LINUX_USB_SERIAL_VISOR_H
+
+
+#define HANDSPRING_VENDOR_ID 0x082d
+#define HANDSPRING_VISOR_ID 0x0100
+
+/****************************************************************************
+ * Handspring Visor Vendor specific request codes (bRequest values)
+ * A big thank you to Handspring for providing the following information.
+ * If anyone wants the original file where these values and structures came
+ * from, send email to <greg@kroah.com>.
+ ****************************************************************************/
+
+/****************************************************************************
+ * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
+ * are available to be transfered to the host for the specified endpoint.
+ * Currently this is not used, and always returns 0x0001
+ ****************************************************************************/
+#define VISOR_REQUEST_BYTES_AVAILABLE 0x01
+
+/****************************************************************************
+ * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
+ * is now closing the pipe. An empty packet is sent in response.
+ ****************************************************************************/
+#define VISOR_CLOSE_NOTIFICATION 0x02
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
+ * get the endpoints used by the connection.
+ ****************************************************************************/
+#define VISOR_GET_CONNECTION_INFORMATION 0x03
+
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION returns data in the following format
+ ****************************************************************************/
+struct visor_connection_info {
+ __u16 num_ports;
+ struct {
+ __u8 port_function_id;
+ __u8 port;
+ } connections[2];
+};
+
+
+/* struct visor_connection_info.connection[x].port defines: */
+#define VISOR_ENDPOINT_1 0x01
+#define VISOR_ENDPOINT_2 0x02
+
+/* struct visor_connection_info.connection[x].port_function_id defines: */
+#define VISOR_FUNCTION_GENERIC 0x00
+#define VISOR_FUNCTION_DEBUGGER 0x01
+#define VISOR_FUNCTION_HOTSYNC 0x02
+#define VISOR_FUNCTION_CONSOLE 0x03
+#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04
+
+#endif
+
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
new file mode 100644
index 000000000..aa6c14b0b
--- /dev/null
+++ b/drivers/usb/serial/whiteheat.c
@@ -0,0 +1,251 @@
+/*
+ * USB ConnectTech WhiteHEAT driver
+ *
+ * (C) Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (03/26/2000) gkh
+ * Split driver up into device specific pieces.
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_WHITEHEAT
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */
+
+
+#define CONNECT_TECH_VENDOR_ID 0x0710
+#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
+#define CONNECT_TECH_WHITE_HEAT_ID 0x8001
+
+/* function prototypes for the Connect Tech WhiteHEAT serial converter */
+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 */
+static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID;
+static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID;
+static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID;
+struct usb_serial_device_type whiteheat_fake_device = {
+ name: "Connect Tech - WhiteHEAT - (prerenumeration)",
+ idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
+ idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+ startup: whiteheat_startup
+};
+struct usb_serial_device_type whiteheat_device = {
+ name: "Connect Tech - WhiteHEAT",
+ idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */
+ idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */
+ needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
+ needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
+ needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 4,
+ open: whiteheat_open,
+ close: whiteheat_close,
+ throttle: whiteheat_throttle,
+ unthrottle: whiteheat_unthrottle,
+ set_termios: whiteheat_set_termios,
+};
+
+
+/*****************************************************************************
+ * Connect Tech's White Heat specific driver functions
+ *****************************************************************************/
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
+{
+ dbg("whiteheat_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ /*Start reading from the device*/
+ 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.) */
+ /* FIXME!!! */
+
+ return (0);
+}
+
+
+static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
+{
+ 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);
+ port->active = 0;
+}
+
+
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+ unsigned int cflag = port->tty->termios->c_cflag;
+
+ 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(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("nothing to change...");
+ return;
+ }
+ }
+
+ /* do the parsing of the cflag to see what to set the line to */
+ /* FIXME!! */
+
+ return;
+}
+
+static void whiteheat_throttle (struct usb_serial_port *port)
+{
+ dbg("whiteheat_throttle port %d", port->number);
+
+ /* Change the control signals */
+ /* FIXME!!! */
+
+ return;
+}
+
+
+static void whiteheat_unthrottle (struct usb_serial_port *port)
+{
+ dbg("whiteheat_unthrottle port %d", port->number);
+
+ /* Change the control signals */
+ /* FIXME!!! */
+
+ return;
+}
+
+
+/* steps to download the firmware to the WhiteHEAT device:
+ - hold the reset (by writing to the reset bit of the CPUCS register)
+ - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
+ - release the reset (by writing to the CPUCS register)
+ - download the WH.HEX file for all addresses greater than 0x1b3f using
+ VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
+ - hold the reset
+ - download the WH.HEX file for all addresses less than 0x1b40 using
+ VENDOR_REQUEST_ANCHOR_LOAD
+ - release the reset
+ - device renumerated itself and comes up as new device id with all
+ firmware download completed.
+*/
+static int whiteheat_startup (struct usb_serial *serial)
+{
+ int response;
+ const struct whiteheat_hex_record *record;
+
+ dbg("whiteheat_startup");
+
+ response = ezusb_set_reset (serial, 1);
+
+ record = &whiteheat_loader[0];
+ while (record->address != 0xffff) {
+ response = ezusb_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa0);
+ if (response < 0) {
+ err("ezusb_writememory failed for loader (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = ezusb_set_reset (serial, 0);
+
+ record = &whiteheat_firmware[0];
+ while (record->address < 0x1b40) {
+ ++record;
+ }
+ while (record->address != 0xffff) {
+ response = ezusb_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa3);
+ if (response < 0) {
+ err("ezusb_writememory failed for first firmware step (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = ezusb_set_reset (serial, 1);
+
+ record = &whiteheat_firmware[0];
+ while (record->address < 0x1b40) {
+ response = ezusb_writememory (serial, record->address,
+ (unsigned char *)record->data, record->data_size, 0xa0);
+ if (response < 0) {
+ err("ezusb_writememory failed for second firmware step (%d %04X %p %d)",
+ response, record->address, record->data, record->data_size);
+ break;
+ }
+ ++record;
+ }
+
+ response = ezusb_set_reset (serial, 0);
+
+ /* we want this device to fail to have a driver assigned to it. */
+ return (1);
+}
+
+#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
+
+
diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat_fw.h
index d7053e337..7d942ba00 100644
--- a/drivers/usb/serial/whiteheat.h
+++ b/drivers/usb/serial/whiteheat_fw.h
@@ -18,6 +18,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ * (04/09/2000) gkh
+ * Updated the firmware with the latest provided by ConnectTech.
+ *
* (01/16/2000) gkh
* Fixed my intel hex processing tool, so now the firmware actually
* matches the original file (this was causing a few problems...)
@@ -44,280 +47,271 @@ struct whiteheat_hex_record {
};
static const struct whiteheat_hex_record whiteheat_firmware[] = {
-{ 0x0000, 3, {0x02, 0x91, 0xc9} },
+{ 0x0000, 3, {0x02, 0x93, 0xa9} },
{ 0x0003, 3, {0x02, 0x13, 0x12} },
-{ 0x000b, 3, {0x02, 0x0a, 0x8d} },
-{ 0x0033, 3, {0x02, 0x07, 0x84} },
-{ 0x0043, 3, {0x02, 0x09, 0x00} },
-{ 0x0053, 3, {0x02, 0x0f, 0x6e} },
-{ 0x005b, 3, {0x02, 0x11, 0xb9} },
-{ 0x0300, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x03, 0x14, 0x70, 0x03, 0x02, 0x04, 0x77, 0x24} },
-{ 0x0310, 16, {0xfe, 0x70, 0x03, 0x02, 0x04, 0xca, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x03, 0xf4, 0x14, 0x70, 0x03} },
-{ 0x0320, 16, {0x02, 0x03, 0xe2, 0x14, 0x70, 0x03, 0x02, 0x03, 0xca, 0x14, 0x70, 0x03, 0x02, 0x03, 0xd9, 0x24} },
-{ 0x0330, 16, {0x05, 0x60, 0x03, 0x02, 0x05, 0x19, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
-{ 0x0340, 16, {0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
-{ 0x0350, 16, {0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x58, 0xea, 0x49, 0x60, 0x0d} },
-{ 0x0360, 16, {0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
-{ 0x0370, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08, 0xa9, 0xea} },
-{ 0x0380, 16, {0x49, 0x60, 0x33, 0x12, 0x9a, 0x48, 0xf5, 0x5e, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x5e, 0xd3} },
-{ 0x0390, 16, {0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x5e, 0x40} },
-{ 0x03a0, 16, {0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x5e, 0x12, 0x1b, 0x0c, 0x90, 0x7f, 0xb5} },
-{ 0x03b0, 16, {0xe5, 0x5e, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20} },
-{ 0x03c0, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
-{ 0x03d0, 16, {0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
-{ 0x03e0, 16, {0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
-{ 0x03f0, 16, {0xa8, 0x02, 0x05, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
-{ 0x0400, 16, {0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
-{ 0x0410, 16, {0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
-{ 0x0420, 16, {0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0xe4} },
-{ 0x0430, 16, {0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90} },
-{ 0x0440, 16, {0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
-{ 0x0450, 16, {0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
-{ 0x0460, 16, {0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xb4} },
-{ 0x0470, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
-{ 0x0480, 16, {0x02, 0x60, 0x03, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
-{ 0x0490, 16, {0x05, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x20, 0x90, 0x7f, 0xea, 0xe0} },
-{ 0x04a0, 16, {0x70, 0x1f, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54} },
-{ 0x04b0, 16, {0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x80} },
-{ 0x04c0, 16, {0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe} },
-{ 0x04d0, 16, {0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80} },
-{ 0x04e0, 16, {0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20} },
-{ 0x04f0, 16, {0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f} },
-{ 0x0500, 16, {0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10} },
-{ 0x0510, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0520, 7, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
-{ 0x0527, 1, {0x22} },
-{ 0x0528, 16, {0x75, 0x5a, 0xff, 0x75, 0x59, 0xff, 0x75, 0x58, 0x0f, 0x75, 0x57, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
-{ 0x0538, 16, {0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
-{ 0x0548, 16, {0x01, 0x5b, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
-{ 0x0558, 16, {0x0a, 0xfa, 0xe4, 0x90, 0x02, 0x4d, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x0568, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
-{ 0x0578, 16, {0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
-{ 0x0588, 16, {0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
-{ 0x0598, 16, {0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
-{ 0x05a8, 16, {0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
-{ 0x05b8, 16, {0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
-{ 0x05c8, 16, {0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
-{ 0x05d8, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
-{ 0x05e8, 16, {0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
-{ 0x05f8, 16, {0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
-{ 0x0608, 16, {0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x62, 0x10, 0x75, 0x63, 0x02, 0x75} },
-{ 0x0618, 16, {0x64, 0x12, 0x75, 0x65, 0xac, 0x12, 0x8e, 0x35, 0x75, 0x5c, 0x12, 0x75, 0x5d, 0xb2, 0x90, 0x01} },
-{ 0x0628, 16, {0x0d, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82} },
-{ 0x0638, 16, {0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70} },
-{ 0x0648, 16, {0x02, 0x05, 0x5c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
-{ 0x0658, 16, {0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x5d, 0xe5, 0x5d, 0xac, 0x5c, 0x70, 0x02, 0x05, 0x5c, 0x14} },
-{ 0x0668, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x5d, 0xe5, 0x5d, 0xae, 0x5c, 0x70, 0x02, 0x05, 0x5c} },
-{ 0x0678, 16, {0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
-{ 0x0688, 16, {0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9b, 0xfb, 0x7e, 0x01} },
-{ 0x0698, 16, {0x7f, 0x18, 0x12, 0x84, 0x61, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
-{ 0x06a8, 16, {0xa3, 0xe0, 0xff, 0x75, 0x62, 0x0a, 0x75, 0x63, 0x06, 0x75, 0x64, 0x12, 0x75, 0x65, 0xb8, 0x12} },
-{ 0x06b8, 16, {0x8e, 0x35, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
-{ 0x06c8, 16, {0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
-{ 0x06d8, 16, {0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xa7, 0x75, 0x56, 0x50} },
-{ 0x06e8, 16, {0x75, 0x55, 0x6d, 0x75, 0x54, 0x33, 0x75, 0x53, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
-{ 0x06f8, 16, {0x7d, 0xff, 0x7c, 0xff, 0x78, 0x53, 0x12, 0x9b, 0xe4, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
-{ 0x0708, 16, {0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x00, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x08, 0xfb, 0x50} },
-{ 0x0718, 16, {0x06, 0x12, 0x0a, 0x00, 0x12, 0x09, 0xf4, 0xc2, 0x06, 0x12, 0x90, 0x58, 0x12, 0x98, 0x7d, 0xe4} },
-{ 0x0728, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0x5b} },
-{ 0x0738, 16, {0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
-{ 0x0748, 16, {0x80, 0x02, 0x7e, 0x00, 0x8e, 0x5b, 0x80, 0x03, 0x75, 0x5b, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
-{ 0x0758, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x5b, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
-{ 0x0768, 16, {0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x90, 0x02} },
-{ 0x0778, 11, {0x4d, 0xe0, 0x64, 0x0f, 0x70, 0x8b, 0x12, 0x93, 0x50, 0x80, 0x86} },
-{ 0x0783, 1, {0x22} },
-{ 0x0784, 4, {0x53, 0xd8, 0xef, 0x32} },
-{ 0x0788, 16, {0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0x74, 0x89} },
-{ 0x0798, 16, {0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x08, 0x92, 0x90, 0x7f} },
-{ 0x07a8, 16, {0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff} },
-{ 0x07b8, 16, {0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
-{ 0x07c8, 16, {0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
-{ 0x07d8, 16, {0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
-{ 0x07e8, 16, {0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
-{ 0x07f8, 7, {0x32, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x22} },
-{ 0x07ff, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
-{ 0x080f, 16, {0x08, 0x92, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x11, 0x4b, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92} },
-{ 0x081f, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f} },
-{ 0x082f, 16, {0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0} },
-{ 0x083f, 16, {0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
-{ 0x084f, 12, {0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x12, 0x0a, 0x00, 0x22} },
-{ 0x085b, 16, {0x90, 0x11, 0xef, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
-{ 0x086b, 16, {0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
-{ 0x087b, 16, {0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x07, 0x88, 0x75, 0x82, 0xef} },
-{ 0x088b, 7, {0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
-{ 0x0892, 16, {0x8e, 0x6d, 0x8f, 0x6e, 0xe5, 0x6e, 0x15, 0x6e, 0xae, 0x6d, 0x70, 0x02, 0x15, 0x6d, 0x4e, 0x60} },
-{ 0x08a2, 7, {0x05, 0x12, 0x08, 0xea, 0x80, 0xee, 0x22} },
-{ 0x08a9, 2, {0x8f, 0x5f} },
-{ 0x08ab, 16, {0xe4, 0xf5, 0x60, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x6a, 0xab, 0x61, 0xaa, 0x62} },
-{ 0x08bb, 16, {0xa9, 0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x03, 0x1d, 0xaf, 0x60, 0x05, 0x60, 0xef} },
-{ 0x08cb, 16, {0xb5, 0x5f, 0x01, 0x22, 0x12, 0x9a, 0x48, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
-{ 0x08db, 14, {0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x08e9, 1, {0x22} },
-{ 0x08ea, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
-{ 0x08fa, 1, {0x22} },
-{ 0x08fb, 5, {0x12, 0x07, 0xff, 0xd3, 0x22} },
-{ 0x0900, 16, {0x02, 0x0b, 0x17, 0x00, 0x02, 0x0b, 0x4a, 0x00, 0x02, 0x0b, 0x2f, 0x00, 0x02, 0x0b, 0x89, 0x00} },
-{ 0x0910, 16, {0x02, 0x0b, 0x73, 0x00, 0x02, 0x09, 0xf9, 0x00, 0x02, 0x09, 0xfa, 0x00, 0x02, 0x09, 0xfb, 0x00} },
-{ 0x0920, 16, {0x02, 0x0b, 0xa4, 0x00, 0x02, 0x0c, 0x78, 0x00, 0x02, 0x0b, 0xd9, 0x00, 0x02, 0x0c, 0xc5, 0x00} },
-{ 0x0930, 16, {0x02, 0x0c, 0x0e, 0x00, 0x02, 0x0d, 0x12, 0x00, 0x02, 0x0c, 0x43, 0x00, 0x02, 0x0d, 0x5f, 0x00} },
-{ 0x0940, 16, {0x02, 0x09, 0xfc, 0x00, 0x02, 0x09, 0xfe, 0x00, 0x02, 0x09, 0xfd, 0x00, 0x02, 0x09, 0xff, 0x00} },
-{ 0x0950, 8, {0x02, 0x0d, 0xac, 0x00, 0x02, 0x0d, 0xc2, 0x00} },
-{ 0x0958, 16, {0xe4, 0xfe, 0x75, 0x61, 0xff, 0x75, 0x62, 0x12, 0x75, 0x63, 0x12, 0xab, 0x61, 0xaa, 0x62, 0xa9} },
-{ 0x0968, 16, {0x63, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
-{ 0x0978, 16, {0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9a, 0xba, 0x85, 0xf0, 0x5f, 0xf5, 0x60, 0x62, 0x5f} },
-{ 0x0988, 16, {0xe5, 0x5f, 0x62, 0x60, 0xe5, 0x60, 0x62, 0x5f, 0x29, 0xfd, 0xe5, 0x5f, 0x3a, 0xa9, 0x05, 0x75} },
-{ 0x0998, 14, {0x61, 0xff, 0xf5, 0x62, 0x89, 0x63, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
-{ 0x09a6, 1, {0x22} },
-{ 0x09a7, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
-{ 0x09b7, 16, {0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
-{ 0x09c7, 5, {0xe0, 0x44, 0x04, 0xf0, 0x22} },
-{ 0x09cc, 16, {0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
-{ 0x09dc, 16, {0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
-{ 0x09ec, 7, {0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
-{ 0x09f3, 1, {0x22} },
-{ 0x09f4, 5, {0x12, 0x07, 0x88, 0xd3, 0x22} },
-{ 0x09f9, 1, {0x32} },
-{ 0x09fa, 1, {0x32} },
-{ 0x09fb, 1, {0x32} },
-{ 0x09fc, 1, {0x32} },
-{ 0x09fd, 1, {0x32} },
-{ 0x09fe, 1, {0x32} },
-{ 0x09ff, 1, {0x32} },
-{ 0x0a00, 9, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
-{ 0x0a7d, 16, {0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
-{ 0x0a8d, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
-{ 0x0a9d, 1, {0x07} },
-{ 0x0a9e, 16, {0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
-{ 0x0aae, 16, {0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
-{ 0x0abe, 16, {0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x02, 0x9e} },
-{ 0x0ace, 16, {0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
-{ 0x0ade, 13, {0x01, 0x5f, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x34, 0xff, 0xf0} },
-{ 0x0aeb, 15, {0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0afa, 16, {0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x0f, 0x72, 0x12, 0x08, 0x5b} },
-{ 0x0b0a, 13, {0x12, 0x0e, 0x0f, 0x12, 0x8f, 0x06, 0x12, 0x11, 0x9c, 0x12, 0x09, 0xcc, 0x22} },
-{ 0x0b17, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
-{ 0x0b27, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b2f, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0b3f, 11, {0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b4a, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
-{ 0x0b5a, 16, {0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
-{ 0x0b6a, 9, {0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b73, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
-{ 0x0b83, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0b89, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
-{ 0x0b99, 11, {0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0ba4, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x02, 0xf0, 0xe5} },
-{ 0x0bb4, 16, {0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20, 0x04, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0bc4, 16, {0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0bd4, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0bd9, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0xe5} },
-{ 0x0be9, 16, {0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20, 0x0c, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0bf9, 16, {0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c09, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c0e, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x08, 0xf0, 0xe5} },
-{ 0x0c1e, 16, {0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20, 0x14, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0c2e, 16, {0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c3e, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c43, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x10, 0xf0, 0xe5} },
-{ 0x0c53, 16, {0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20, 0x1c, 0xe0, 0x44, 0x01, 0xf0} },
-{ 0x0c63, 16, {0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0x82} },
-{ 0x0c73, 5, {0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0c78, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0c88, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20, 0xe0, 0x06, 0x90, 0x7f, 0xc7} },
-{ 0x0c98, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0x90, 0x02, 0x96, 0xf0} },
-{ 0x0ca8, 16, {0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0cb8, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0cc5, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0cd5, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20, 0xe1, 0x06, 0x90, 0x7f, 0xc9} },
-{ 0x0ce5, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0x90, 0x02, 0x97, 0xf0} },
-{ 0x0cf5, 16, {0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d05, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d12, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0d22, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20, 0xe2, 0x06, 0x90, 0x7f, 0xcb} },
-{ 0x0d32, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0x90, 0x02, 0x98, 0xf0} },
-{ 0x0d42, 16, {0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d52, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0d5f, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
-{ 0x0d6f, 16, {0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20, 0xe3, 0x06, 0x90, 0x7f, 0xcd} },
-{ 0x0d7f, 16, {0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0x90, 0x02, 0x99, 0xf0} },
-{ 0x0d8f, 16, {0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b, 0x70, 0x03, 0x75, 0x2b, 0x14} },
-{ 0x0d9f, 13, {0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dac, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
-{ 0x0dbc, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x0dc2, 16, {0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0} },
-{ 0x0dd2, 16, {0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0x53, 0x91, 0xef} },
-{ 0x0de2, 16, {0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8c, 0xfb, 0x90, 0x7f, 0xd3} },
-{ 0x0df2, 16, {0xe4, 0xf0, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01} },
-{ 0x0e02, 13, {0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32} },
-{ 0x0e0f, 16, {0x90, 0x01, 0x20, 0x12, 0x9c, 0x07, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
-{ 0x0e1f, 16, {0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x0e2f, 16, {0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50} },
-{ 0x0e3f, 16, {0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x84, 0xf4, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0e4f, 16, {0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
-{ 0x0e5f, 16, {0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0x96, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4} },
-{ 0x0e6f, 16, {0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xdc, 0xe4} },
-{ 0x0e7f, 16, {0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0e8f, 16, {0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02} },
-{ 0x0e9f, 16, {0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x82, 0xea, 0x90, 0x01, 0x1e} },
-{ 0x0eaf, 16, {0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0ebf, 16, {0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54} },
-{ 0x0ecf, 16, {0xf0, 0xfe, 0x74, 0x63, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xee, 0xf0, 0x74, 0x36} },
-{ 0x0edf, 16, {0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c, 0x2f, 0xf8, 0xe4, 0xf6} },
-{ 0x0eef, 16, {0x74, 0x9a, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x01, 0x1e, 0xe0} },
-{ 0x0eff, 16, {0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0x5e, 0x60, 0x5e} },
-{ 0x0f0f, 16, {0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0xe7, 0x74} },
-{ 0x0f1f, 16, {0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x5e, 0x60, 0x38, 0x90, 0x01} },
-{ 0x0f2f, 1, {0x1e} },
-{ 0x0f30, 16, {0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
-{ 0x0f40, 16, {0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0} },
-{ 0x0f50, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe} },
-{ 0x0f60, 14, {0x7d, 0x06, 0x12, 0x82, 0x60, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xa7, 0x22} },
-{ 0x0f6e, 4, {0x53, 0x91, 0xbf, 0x32} },
-{ 0x0f72, 16, {0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0xfd, 0x8b, 0x60, 0x75} },
-{ 0x0f82, 16, {0x61, 0x12, 0x75, 0x62, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x5e} },
-{ 0x0f92, 16, {0xf5, 0x5f, 0x90, 0x02, 0x4c, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
-{ 0x0fa2, 16, {0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
-{ 0x0fb2, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
-{ 0x0fc2, 16, {0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0x38, 0xab, 0x60, 0xaa, 0x61, 0xa9, 0x62} },
-{ 0x0fd2, 16, {0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0x27, 0x90, 0x00, 0x03} },
-{ 0x0fe2, 16, {0x12, 0x9a, 0x61, 0x64, 0x01, 0x60, 0x03, 0x02, 0x10, 0xae, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61} },
-{ 0x0ff2, 16, {0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x10, 0x88, 0xec, 0xc3, 0x94, 0x10} },
-{ 0x1002, 16, {0x40, 0x03, 0x02, 0x10, 0x88, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x5f, 0xae, 0x5e, 0x78, 0x02, 0xce} },
-{ 0x1012, 16, {0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
-{ 0x1022, 16, {0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
-{ 0x1032, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0x4c, 0xe0} },
-{ 0x1042, 16, {0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x5f, 0xae, 0x5e, 0x78} },
-{ 0x1052, 16, {0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x1062, 16, {0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
-{ 0x1072, 16, {0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
-{ 0x1082, 16, {0x4c, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9a, 0x61, 0x25} },
-{ 0x1092, 16, {0x5f, 0xf5, 0x5f, 0xe4, 0x35, 0x5e, 0xf5, 0x5e, 0x90, 0x00, 0x05, 0x12, 0x9a, 0x61, 0xfe, 0xe4} },
-{ 0x10a2, 16, {0x25, 0x5f, 0xf5, 0x5f, 0xee, 0x35, 0x5e, 0xf5, 0x5e, 0x02, 0x11, 0x2a, 0xab, 0x60, 0xaa, 0x61} },
-{ 0x10b2, 16, {0xa9, 0x62, 0x90, 0x00, 0x03, 0x12, 0x9a, 0x61, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
-{ 0x10c2, 16, {0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9a, 0x61, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
-{ 0x10d2, 16, {0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
-{ 0x10e2, 16, {0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
-{ 0x10f2, 16, {0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
-{ 0x1102, 16, {0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
-{ 0x1112, 16, {0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
-{ 0x1122, 16, {0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35} },
-{ 0x1132, 16, {0x61, 0xf5, 0x61, 0x02, 0x0f, 0xc3, 0x20, 0x03, 0x0d, 0x90, 0x02, 0x4c, 0xe0, 0x60, 0x07, 0x90} },
-{ 0x1142, 8, {0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
-{ 0x114a, 1, {0x22} },
-{ 0x114b, 2, {0xae, 0x07} },
-{ 0x114d, 16, {0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
-{ 0x115d, 16, {0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
-{ 0x116d, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
-{ 0x117d, 16, {0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
-{ 0x118d, 14, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
-{ 0x119b, 1, {0x22} },
-{ 0x119c, 16, {0x7f, 0x05, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x7f, 0x05} },
-{ 0x11ac, 13, {0x7e, 0x00, 0x12, 0x08, 0x92, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x11, 0x4b, 0x22} },
-{ 0x11b9, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x02, 0x9e, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
-{ 0x11c9, 15, {0x53, 0x91, 0x7f, 0x90, 0x01, 0x62, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x11d8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
-{ 0x11e8, 7, {0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
-{ 0x11ef, 3, {0x00, 0x02, 0x28} },
+{ 0x000b, 3, {0x02, 0x0a, 0x80} },
+{ 0x0033, 3, {0x02, 0x08, 0x15} },
+{ 0x0043, 3, {0x02, 0x0a, 0x00} },
+{ 0x005b, 3, {0x02, 0x82, 0x31} },
+{ 0x0370, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x73, 0x14, 0x70, 0x03, 0x02, 0x04, 0xe7, 0x24} },
+{ 0x0380, 16, {0xfe, 0x70, 0x03, 0x02, 0x05, 0x45, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x64, 0x14, 0x70, 0x03} },
+{ 0x0390, 16, {0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x49, 0x24} },
+{ 0x03a0, 16, {0x05, 0x60, 0x03, 0x02, 0x05, 0x94, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
+{ 0x03b0, 16, {0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x03c0, 16, {0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x7b, 0xea, 0x49, 0x60, 0x0d} },
+{ 0x03d0, 16, {0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x03e0, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x3a, 0xea} },
+{ 0x03f0, 16, {0x49, 0x60, 0x33, 0x12, 0x9b, 0x72, 0xf5, 0x4b, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x4b, 0xd3} },
+{ 0x0400, 16, {0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x4b, 0x40} },
+{ 0x0410, 16, {0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x4b, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xb5} },
+{ 0x0420, 16, {0xe5, 0x4b, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b} },
+{ 0x0430, 16, {0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
+{ 0x0440, 16, {0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
+{ 0x0450, 16, {0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
+{ 0x0460, 16, {0xa8, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
+{ 0x0470, 16, {0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
+{ 0x0480, 16, {0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
+{ 0x0490, 16, {0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0xe4} },
+{ 0x04a0, 16, {0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90} },
+{ 0x04b0, 16, {0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
+{ 0x04c0, 16, {0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
+{ 0x04d0, 16, {0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x04e0, 16, {0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
+{ 0x04f0, 16, {0x02, 0x60, 0x03, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
+{ 0x0500, 16, {0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x0510, 16, {0x70, 0x2a, 0x90, 0x7f, 0xec, 0xe0, 0xff, 0xf4, 0x54, 0x80, 0xfe, 0xc4, 0x54, 0x0f, 0xfe, 0xef} },
+{ 0x0520, 16, {0x54, 0x07, 0xfd, 0x2e, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4} },
+{ 0x0530, 16, {0xf0, 0x90, 0x7f, 0xd7, 0xed, 0xf0, 0xef, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0540, 16, {0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70} },
+{ 0x0550, 16, {0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0560, 16, {0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4} },
+{ 0x0570, 16, {0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x0580, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x0590, 16, {0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x05a0, 2, {0x02, 0xf0} },
+{ 0x05a2, 1, {0x22} },
+{ 0x05a3, 16, {0x75, 0x47, 0xff, 0x75, 0x46, 0xff, 0x75, 0x45, 0x0f, 0x75, 0x44, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
+{ 0x05b3, 16, {0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
+{ 0x05c3, 16, {0x01, 0xbc, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0xc0, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
+{ 0x05d3, 16, {0x0b, 0x8d, 0xe4, 0x90, 0x02, 0xaf, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x05e3, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
+{ 0x05f3, 16, {0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x49, 0x12, 0x75, 0x4a, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
+{ 0x0603, 16, {0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x0613, 16, {0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x0623, 16, {0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
+{ 0x0633, 16, {0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x0643, 16, {0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x0653, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
+{ 0x0663, 16, {0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
+{ 0x0673, 16, {0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
+{ 0x0683, 16, {0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x4f, 0x10, 0x75, 0x50, 0x02, 0x75} },
+{ 0x0693, 16, {0x51, 0x12, 0x75, 0x52, 0xac, 0x12, 0x90, 0x15, 0x75, 0x49, 0x12, 0x75, 0x4a, 0xb2, 0x90, 0x01} },
+{ 0x06a3, 16, {0x0d, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82} },
+{ 0x06b3, 16, {0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x06c3, 16, {0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
+{ 0x06d3, 16, {0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x06e3, 16, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x4a, 0xe5, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x05, 0x49} },
+{ 0x06f3, 16, {0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
+{ 0x0703, 16, {0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9d, 0x25, 0x7e, 0x01} },
+{ 0x0713, 16, {0x7f, 0x18, 0x12, 0x85, 0x08, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x0723, 16, {0xa3, 0xe0, 0xff, 0x75, 0x4f, 0x0a, 0x75, 0x50, 0x06, 0x75, 0x51, 0x12, 0x75, 0x52, 0xb8, 0x12} },
+{ 0x0733, 16, {0x90, 0x15, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
+{ 0x0743, 16, {0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
+{ 0x0753, 16, {0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xca, 0x75, 0x43, 0x50} },
+{ 0x0763, 16, {0x75, 0x42, 0x6d, 0x75, 0x41, 0x33, 0x75, 0x40, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
+{ 0x0773, 16, {0x7d, 0xff, 0x7c, 0xff, 0x78, 0x40, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
+{ 0x0783, 16, {0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x70, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x0a, 0xed, 0x50} },
+{ 0x0793, 16, {0x06, 0x12, 0x0b, 0x00, 0x12, 0x0a, 0xf2, 0xc2, 0x06, 0x12, 0x92, 0x38, 0x90, 0x01, 0xbd, 0xe0} },
+{ 0x07a3, 16, {0x60, 0x10, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8e, 0xc1, 0xe4, 0x90, 0x01, 0xbd, 0xf0, 0x90, 0x7f} },
+{ 0x07b3, 16, {0xd3, 0xf0, 0x90, 0x02, 0xaf, 0xe0, 0xb4, 0x0f, 0x03, 0x12, 0x95, 0x30, 0x12, 0x99, 0xcc, 0xe4} },
+{ 0x07c3, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0xbc} },
+{ 0x07d3, 16, {0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
+{ 0x07e3, 16, {0x80, 0x02, 0x7e, 0x00, 0x8e, 0x48, 0x80, 0x03, 0x75, 0x48, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
+{ 0x07f3, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x48, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
+{ 0x0803, 16, {0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x02, 0x07} },
+{ 0x0813, 1, {0x84} },
+{ 0x0814, 1, {0x22} },
+{ 0x0815, 4, {0x53, 0xd8, 0xef, 0x32} },
+{ 0x0819, 16, {0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0829, 16, {0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x0839, 16, {0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff} },
+{ 0x0849, 16, {0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
+{ 0x0859, 16, {0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x0869, 16, {0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
+{ 0x0879, 16, {0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
+{ 0x0889, 7, {0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x22} },
+{ 0x0890, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
+{ 0x08a0, 16, {0x09, 0x23, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23} },
+{ 0x08b0, 16, {0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x08c0, 16, {0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x08d0, 16, {0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
+{ 0x08e0, 12, {0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x12, 0x0b, 0x00, 0x22} },
+{ 0x08ec, 16, {0x90, 0x11, 0xfc, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
+{ 0x08fc, 16, {0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
+{ 0x090c, 16, {0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x08, 0x19, 0x75, 0x82, 0xfc} },
+{ 0x091c, 7, {0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
+{ 0x0923, 16, {0x8e, 0x58, 0x8f, 0x59, 0xe5, 0x59, 0x15, 0x59, 0xae, 0x58, 0x70, 0x02, 0x15, 0x58, 0x4e, 0x60} },
+{ 0x0933, 7, {0x05, 0x12, 0x09, 0xef, 0x80, 0xee, 0x22} },
+{ 0x093a, 2, {0x8f, 0x4c} },
+{ 0x093c, 16, {0xe4, 0xf5, 0x4d, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x6a, 0xab, 0x4e, 0xaa, 0x4f} },
+{ 0x094c, 16, {0xa9, 0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x03, 0x1d, 0xaf, 0x4d, 0x05, 0x4d, 0xef} },
+{ 0x095c, 16, {0xb5, 0x4c, 0x01, 0x22, 0x12, 0x9b, 0x72, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x096c, 14, {0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x097a, 1, {0x22} },
+{ 0x097b, 16, {0xe4, 0xfe, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x12, 0xab, 0x4e, 0xaa, 0x4f, 0xa9} },
+{ 0x098b, 16, {0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x099b, 16, {0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9b, 0xe4, 0x85, 0xf0, 0x4c, 0xf5, 0x4d, 0x62, 0x4c} },
+{ 0x09ab, 16, {0xe5, 0x4c, 0x62, 0x4d, 0xe5, 0x4d, 0x62, 0x4c, 0x29, 0xfd, 0xe5, 0x4c, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x09bb, 14, {0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x09c9, 1, {0x22} },
+{ 0x09ca, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
+{ 0x09da, 16, {0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x09ea, 5, {0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x09ef, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x09ff, 1, {0x22} },
+{ 0x0a00, 16, {0x02, 0x0b, 0xaa, 0x00, 0x02, 0x0b, 0xdd, 0x00, 0x02, 0x0b, 0xc2, 0x00, 0x02, 0x0c, 0x1c, 0x00} },
+{ 0x0a10, 16, {0x02, 0x0c, 0x06, 0x00, 0x02, 0x0a, 0xf7, 0x00, 0x02, 0x0a, 0xf8, 0x00, 0x02, 0x0a, 0xf9, 0x00} },
+{ 0x0a20, 16, {0x02, 0x0c, 0x37, 0x00, 0x02, 0x0d, 0x27, 0x00, 0x02, 0x0c, 0x73, 0x00, 0x02, 0x0d, 0x7b, 0x00} },
+{ 0x0a30, 16, {0x02, 0x0c, 0xaf, 0x00, 0x02, 0x0d, 0xcf, 0x00, 0x02, 0x0c, 0xeb, 0x00, 0x02, 0x0e, 0x23, 0x00} },
+{ 0x0a40, 16, {0x02, 0x0a, 0xfa, 0x00, 0x02, 0x0a, 0xfc, 0x00, 0x02, 0x0a, 0xfb, 0x00, 0x02, 0x0a, 0xfd, 0x00} },
+{ 0x0a50, 8, {0x02, 0x0e, 0x77, 0x00, 0x02, 0x0e, 0x8d, 0x00} },
+{ 0x0a58, 16, {0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
+{ 0x0a68, 16, {0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
+{ 0x0a78, 7, {0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
+{ 0x0a7f, 1, {0x22} },
+{ 0x0a80, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
+{ 0x0a90, 1, {0x07} },
+{ 0x0a91, 16, {0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
+{ 0x0aa1, 16, {0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
+{ 0x0ab1, 16, {0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x03, 0x00} },
+{ 0x0ac1, 16, {0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
+{ 0x0ad1, 13, {0x01, 0xc1, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x34, 0xff, 0xf0} },
+{ 0x0ade, 15, {0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0aed, 5, {0x12, 0x08, 0x90, 0xd3, 0x22} },
+{ 0x0af2, 5, {0x12, 0x08, 0x19, 0xd3, 0x22} },
+{ 0x0af7, 1, {0x32} },
+{ 0x0af8, 1, {0x32} },
+{ 0x0af9, 1, {0x32} },
+{ 0x0afa, 1, {0x32} },
+{ 0x0afb, 1, {0x32} },
+{ 0x0afc, 1, {0x32} },
+{ 0x0afd, 1, {0x32} },
+{ 0x0b00, 9, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x0b7d, 16, {0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0b8d, 16, {0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x10, 0x0c, 0x12, 0x08, 0xec} },
+{ 0x0b9d, 13, {0x12, 0x0e, 0xa9, 0x12, 0x90, 0xe6, 0x12, 0x1b, 0x0c, 0x12, 0x0a, 0x58, 0x22} },
+{ 0x0baa, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0bba, 8, {0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bc2, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0bd2, 11, {0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bdd, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
+{ 0x0bed, 16, {0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
+{ 0x0bfd, 9, {0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c06, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0c16, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c1c, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c2c, 11, {0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c37, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c47, 16, {0xa9, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20} },
+{ 0x0c57, 16, {0x04, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0c67, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c73, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c83, 16, {0xa9, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20} },
+{ 0x0c93, 16, {0x0c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0ca3, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0caf, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cbf, 16, {0xa9, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20} },
+{ 0x0ccf, 16, {0x14, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0cdf, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ceb, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cfb, 16, {0xa9, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20} },
+{ 0x0d0b, 16, {0x1c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0d1b, 12, {0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d27, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d37, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d47, 16, {0xe0, 0x06, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7} },
+{ 0x0d57, 16, {0xe0, 0x90, 0x02, 0xf8, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0d67, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0d77, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d7b, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d8b, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d9b, 16, {0xe1, 0x06, 0x90, 0x7f, 0xc9, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9} },
+{ 0x0dab, 16, {0xe0, 0x90, 0x02, 0xf9, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0dbb, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0dcb, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dcf, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0ddf, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0def, 16, {0xe2, 0x06, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb} },
+{ 0x0dff, 16, {0xe0, 0x90, 0x02, 0xfa, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e0f, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e1f, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e23, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0e33, 16, {0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0e43, 16, {0xe3, 0x06, 0x90, 0x7f, 0xcd, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd} },
+{ 0x0e53, 16, {0xe0, 0x90, 0x02, 0xfb, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e63, 16, {0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e73, 4, {0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e77, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
+{ 0x0e87, 6, {0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e8d, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x90} },
+{ 0x0e9d, 12, {0x01, 0xbd, 0x74, 0xff, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ea9, 16, {0x90, 0x01, 0x20, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
+{ 0x0eb9, 16, {0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x13, 0xf0, 0xa3, 0x74} },
+{ 0x0ec9, 16, {0x11, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
+{ 0x0ed9, 16, {0xc3, 0x94, 0x04, 0x50, 0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x85, 0xe1} },
+{ 0x0ee9, 16, {0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90} },
+{ 0x0ef9, 16, {0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0f09, 16, {0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04} },
+{ 0x0f19, 16, {0xf0, 0x80, 0xdc, 0xe4, 0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0} },
+{ 0x0f29, 16, {0x90, 0x01, 0x1e, 0xe0, 0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8} },
+{ 0x0f39, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x83} },
+{ 0x0f49, 16, {0x5f, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0} },
+{ 0x0f59, 16, {0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x0f69, 16, {0xf5, 0x83, 0xe0, 0x54, 0xf0, 0xfe, 0x74, 0xc5, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83} },
+{ 0x0f79, 16, {0xee, 0xf0, 0x74, 0x36, 0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c} },
+{ 0x0f89, 16, {0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0xfc, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x0f99, 16, {0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f} },
+{ 0x0fa9, 16, {0xf5, 0x4b, 0x60, 0x5e, 0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94} },
+{ 0x0fb9, 16, {0x04, 0x50, 0xe7, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x4b} },
+{ 0x0fc9, 16, {0x60, 0x38, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4} },
+{ 0x0fd9, 16, {0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
+{ 0x0fe9, 16, {0x34, 0x20, 0xf5, 0x83, 0xe0, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0ff9, 16, {0x20, 0xf5, 0x83, 0xe0, 0xfe, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0} },
+{ 0x1009, 3, {0x80, 0xa7, 0x22} },
+{ 0x100c, 16, {0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0xfd, 0x8b, 0x4d, 0x75} },
+{ 0x101c, 16, {0x4e, 0x12, 0x75, 0x4f, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x4b} },
+{ 0x102c, 16, {0xf5, 0x4c, 0x90, 0x02, 0xae, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
+{ 0x103c, 16, {0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x104c, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
+{ 0x105c, 16, {0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0xd2, 0xab, 0x4d, 0xaa, 0x4e, 0xa9, 0x4f} },
+{ 0x106c, 16, {0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0xc1, 0x90, 0x00, 0x03} },
+{ 0x107c, 16, {0x12, 0x9b, 0x8b, 0x64, 0x01, 0x60, 0x03, 0x02, 0x11, 0x48, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b} },
+{ 0x108c, 16, {0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x11, 0x22, 0xec, 0xc3, 0x94, 0x10} },
+{ 0x109c, 16, {0x40, 0x03, 0x02, 0x11, 0x22, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x4c, 0xae, 0x4b, 0x78, 0x02, 0xce} },
+{ 0x10ac, 16, {0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
+{ 0x10bc, 16, {0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
+{ 0x10cc, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0xae, 0xe0} },
+{ 0x10dc, 16, {0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x4c, 0xae, 0x4b, 0x78} },
+{ 0x10ec, 16, {0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x10fc, 16, {0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
+{ 0x110c, 16, {0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
+{ 0x111c, 16, {0xae, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0x25} },
+{ 0x112c, 16, {0x4c, 0xf5, 0x4c, 0xe4, 0x35, 0x4b, 0xf5, 0x4b, 0x90, 0x00, 0x05, 0x12, 0x9b, 0x8b, 0xfe, 0xe4} },
+{ 0x113c, 16, {0x25, 0x4c, 0xf5, 0x4c, 0xee, 0x35, 0x4b, 0xf5, 0x4b, 0x02, 0x11, 0xc4, 0xab, 0x4d, 0xaa, 0x4e} },
+{ 0x114c, 16, {0xa9, 0x4f, 0x90, 0x00, 0x03, 0x12, 0x9b, 0x8b, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
+{ 0x115c, 16, {0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
+{ 0x116c, 16, {0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
+{ 0x117c, 16, {0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
+{ 0x118c, 16, {0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
+{ 0x119c, 16, {0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
+{ 0x11ac, 16, {0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
+{ 0x11bc, 16, {0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35} },
+{ 0x11cc, 16, {0x4e, 0xf5, 0x4e, 0x02, 0x10, 0x5d, 0x20, 0x03, 0x0d, 0x90, 0x02, 0xae, 0xe0, 0x60, 0x07, 0x90} },
+{ 0x11dc, 8, {0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
+{ 0x11e4, 1, {0x22} },
+{ 0x11e5, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
+{ 0x11f5, 7, {0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
+{ 0x11fc, 3, {0x00, 0x03, 0x15} },
{ 0x1200, 16, {0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0x10, 0x07, 0x01, 0x80, 0x42, 0x00, 0x01, 0x02} },
{ 0x1210, 16, {0x03, 0x01, 0x09, 0x02, 0x58, 0x00, 0x01, 0x01, 0x04, 0x80, 0x3c, 0x09, 0x04, 0x00, 0x00, 0x0a} },
{ 0x1220, 16, {0xff, 0xff, 0xff, 0x05, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40} },
@@ -455,40 +449,39 @@ static const struct whiteheat_hex_record whiteheat_firmware[] = {
{ 0x1a35, 16, {0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
{ 0x1a45, 16, {0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa1, 0x90, 0x7f, 0xa6} },
{ 0x1a55, 16, {0xf0, 0x19, 0x02, 0x1a, 0xdb, 0xeb, 0x64, 0x01, 0x4a, 0x70, 0x08, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x1a65, 16, {0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x69, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
+{ 0x1a65, 16, {0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x54, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
{ 0x1a75, 16, {0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x64, 0x02, 0x4e, 0x70, 0x08, 0x90, 0x7f} },
{ 0x1a85, 16, {0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xff, 0xed, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x1a95, 16, {0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x1a95, 16, {0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
{ 0x1aa5, 16, {0xef, 0xf0, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12} },
-{ 0x1ab5, 16, {0x9a, 0x8e, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
+{ 0x1ab5, 16, {0x9b, 0xb8, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
{ 0x1ac5, 16, {0xed, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xf5, 0x82, 0x8a} },
-{ 0x1ad5, 16, {0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x69, 0x30, 0xe0, 0xf7, 0x30} },
+{ 0x1ad5, 16, {0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x54, 0x30, 0xe0, 0xf7, 0x30} },
{ 0x1ae5, 16, {0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xe9, 0xd3, 0x94, 0x02, 0x50, 0x03, 0x02} },
-{ 0x1af5, 16, {0x19, 0xc7, 0xe5, 0x69, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
+{ 0x1af5, 16, {0x19, 0xc7, 0xe5, 0x54, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
{ 0x1b05, 6, {0xf0, 0x7f, 0x07, 0x22, 0x7f, 0x08} },
{ 0x1b0b, 1, {0x22} },
-{ 0x1b0c, 16, {0x8e, 0x5f, 0x8f, 0x60, 0x8c, 0x61, 0x8d, 0x62, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x60} },
-{ 0x1b1c, 16, {0xe5, 0x60, 0xae, 0x5f, 0x70, 0x02, 0x05, 0x5f, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
-{ 0x1b2c, 16, {0x62, 0xe5, 0x62, 0xac, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
-{ 0x1b3c, 3, {0x80, 0xd6, 0x22} },
-{ 0x8000, 4, {0x8e, 0x69, 0x8f, 0x6a} },
-{ 0x8004, 16, {0x75, 0x6b, 0x03, 0xe5, 0x6a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe0, 0xfe} },
-{ 0x8014, 16, {0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x6b, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
+{ 0x1b0c, 16, {0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x7f, 0x05} },
+{ 0x1b1c, 13, {0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x22} },
+{ 0x1b29, 16, {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
+{ 0x8000, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8004, 16, {0x75, 0x56, 0x03, 0xe5, 0x55, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xfe} },
+{ 0x8014, 16, {0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x56, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
{ 0x8024, 16, {0x60, 0x20, 0x14, 0x60, 0x03, 0x02, 0x80, 0xb2, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
-{ 0x8034, 16, {0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
-{ 0x8044, 16, {0x80, 0x6c, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
-{ 0x8054, 16, {0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x6b, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3} },
-{ 0x8064, 16, {0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x6a, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x8074, 16, {0xe4, 0x35, 0x69, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5} },
-{ 0x8084, 16, {0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x6a, 0x24} },
-{ 0x8094, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x69, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9a, 0x8e, 0x85} },
-{ 0x80a4, 16, {0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0x8e, 0x90, 0x7f} },
-{ 0x80b4, 16, {0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
-{ 0x80c4, 16, {0x22, 0xe5, 0x6c, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
-{ 0x80d4, 16, {0xe5, 0x6b, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x08, 0x92, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
-{ 0x80e4, 16, {0x80, 0xf0, 0x85, 0x6a, 0x82, 0x85, 0x69, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
-{ 0x80f4, 16, {0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x6c, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
-{ 0x8104, 12, {0x6b, 0x03, 0x02, 0x80, 0x07, 0x15, 0x6b, 0x02, 0x80, 0x07, 0x7f, 0x08} },
+{ 0x8034, 16, {0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8044, 16, {0x80, 0x6c, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
+{ 0x8054, 16, {0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x56, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8064, 16, {0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x8074, 16, {0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5} },
+{ 0x8084, 16, {0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x55, 0x24} },
+{ 0x8094, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9b, 0xb8, 0x85} },
+{ 0x80a4, 16, {0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xb8, 0x90, 0x7f} },
+{ 0x80b4, 16, {0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
+{ 0x80c4, 16, {0x22, 0xe5, 0x57, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
+{ 0x80d4, 16, {0xe5, 0x56, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x80e4, 16, {0x80, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
+{ 0x80f4, 16, {0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
+{ 0x8104, 12, {0x56, 0x03, 0x02, 0x80, 0x07, 0x15, 0x56, 0x02, 0x80, 0x07, 0x7f, 0x08} },
{ 0x8110, 1, {0x22} },
{ 0x8111, 2, {0xac, 0x07} },
{ 0x8113, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xec, 0x25, 0xe0, 0x44, 0x41, 0x90, 0x7f, 0xa6, 0xf0} },
@@ -505,476 +498,497 @@ static const struct whiteheat_hex_record whiteheat_firmware[] = {
{ 0x81c3, 16, {0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f, 0xfa, 0x22, 0xc2, 0xaf, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
{ 0x81d3, 12, {0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0xd2, 0xaf, 0xff, 0x7e, 0x00} },
{ 0x81df, 1, {0x22} },
-{ 0x81e0, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
-{ 0x81f0, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf9, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0} },
-{ 0x8200, 16, {0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83} },
-{ 0x8210, 16, {0xa3, 0xf0, 0xed, 0x60, 0x29, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33} },
-{ 0x8220, 16, {0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4, 0xef, 0x55, 0x3b, 0x60, 0x0a, 0x8b, 0x82, 0x8a, 0x83} },
-{ 0x8230, 16, {0xa3, 0x74, 0x01, 0xf0, 0x80, 0x08, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0x74, 0xad, 0xf0, 0x8b, 0x82} },
-{ 0x8240, 16, {0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54} },
-{ 0x8250, 15, {0xef, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe9, 0xf0} },
-{ 0x825f, 1, {0x22} },
-{ 0x8260, 4, {0x8f, 0x68, 0x8d, 0x69} },
-{ 0x8264, 16, {0xe4, 0xf5, 0x6a, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
-{ 0x8274, 16, {0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
-{ 0x8284, 16, {0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x50} },
-{ 0x8294, 16, {0x3c, 0xe5, 0x68, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0xa0, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
-{ 0x82a4, 16, {0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
-{ 0x82b4, 16, {0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75, 0x6a, 0x40, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76} },
-{ 0x82c4, 16, {0x10, 0x80, 0x0a, 0x75, 0x6a, 0x80, 0x74, 0x3c, 0x25, 0x68, 0xf8, 0x76, 0x38, 0xe5, 0x6a, 0x45} },
-{ 0x82d4, 16, {0x69, 0x44, 0x01, 0xff, 0xe5, 0x68, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x82e4, 5, {0x20, 0xf5, 0x83, 0xef, 0xf0} },
-{ 0x82e9, 1, {0x22} },
-{ 0x82ea, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x82fa, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xf5, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5} },
-{ 0x830a, 16, {0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82} },
-{ 0x831a, 16, {0x60, 0xaf, 0x5f, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3} },
-{ 0x832a, 16, {0xe0, 0x20, 0xe0, 0x28, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x61} },
-{ 0x833a, 16, {0xf5, 0x83, 0xe0, 0xf5, 0x60, 0xe5, 0x62, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83} },
-{ 0x834a, 16, {0xe0, 0xf5, 0x60, 0xaf, 0x5f, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x80, 0xcc, 0x74, 0x96, 0x25, 0x5f} },
-{ 0x835a, 16, {0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x5f, 0x25, 0xe0, 0xff, 0xc3, 0x74} },
-{ 0x836a, 16, {0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82} },
-{ 0x837a, 16, {0xfe, 0xe5, 0x5f, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0} },
-{ 0x838a, 16, {0xa3, 0xef, 0xf0, 0xaf, 0x5f, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc} },
-{ 0x839a, 4, {0x42, 0x30, 0x7f, 0x00} },
-{ 0x839e, 1, {0x22} },
-{ 0x839f, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x47, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x83af, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x49, 0x8f, 0x4a, 0x74, 0x96, 0x25, 0x47, 0xf5, 0x82, 0xe4} },
-{ 0x83bf, 16, {0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x4a, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5} },
-{ 0x83cf, 16, {0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf, 0x47, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0xaf, 0x47, 0x7d, 0x06} },
-{ 0x83df, 16, {0x12, 0x82, 0x60, 0xe5, 0x4a, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x49, 0xf5, 0x83, 0xe0, 0x30} },
-{ 0x83ef, 16, {0xe0, 0x0b, 0x85, 0x4a, 0x82, 0x85, 0x49, 0x83, 0xe0, 0xf5, 0x48, 0x80, 0xe6, 0xaf, 0x47, 0x74} },
-{ 0x83ff, 16, {0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x47, 0x25} },
-{ 0x840f, 13, {0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xff} },
-{ 0x841c, 1, {0x22} },
-{ 0x841d, 4, {0x8e, 0x47, 0x8f, 0x48} },
-{ 0x8421, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x49, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
-{ 0x8431, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x48, 0x82, 0x8e, 0x83, 0xa3} },
-{ 0x8441, 16, {0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x49, 0x7d, 0x02, 0x12, 0x82, 0x60, 0x85, 0x48, 0x82, 0x85, 0x47} },
-{ 0x8451, 15, {0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x49, 0x7d, 0x04, 0x12, 0x82, 0x60, 0x7f, 0x00} },
-{ 0x8460, 1, {0x22} },
-{ 0x8461, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
-{ 0x8471, 16, {0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
-{ 0x8481, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
-{ 0x8491, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
-{ 0x84a1, 16, {0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
-{ 0x84b1, 16, {0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
-{ 0x84c1, 16, {0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
-{ 0x84d1, 16, {0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
-{ 0x84e1, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
-{ 0x84f1, 3, {0x83, 0xf0, 0x22} },
-{ 0x84f4, 4, {0x8e, 0x5f, 0x8f, 0x60} },
-{ 0x84f8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x8508, 16, {0x1f, 0xad, 0x82, 0xf5, 0x66, 0x8d, 0x67, 0xaa, 0x5f, 0xa9, 0x60, 0x7b, 0x01, 0xc0, 0x03, 0xc0} },
-{ 0x8518, 16, {0x01, 0xef, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x92, 0xf9, 0x74, 0x02, 0x35, 0xf0, 0xa8, 0x01, 0xfc} },
-{ 0x8528, 16, {0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9a, 0x1f, 0x85, 0x60, 0x82} },
-{ 0x8538, 16, {0x85, 0x5f, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb, 0x7f} },
-{ 0x8548, 16, {0x00, 0x7e, 0x08, 0x7d, 0x07, 0x7c, 0x00, 0x12, 0x9b, 0x2e, 0x8f, 0x64, 0x8e, 0x63, 0x8d, 0x62} },
-{ 0x8558, 16, {0x8c, 0x61, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9b, 0xc0, 0x70, 0x09} },
-{ 0x8568, 16, {0x75, 0x64, 0x01, 0xf5, 0x63, 0xf5, 0x62, 0xf5, 0x61, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0x00, 0x7c} },
-{ 0x8578, 16, {0x00, 0xab, 0x64, 0xaa, 0x63, 0xa9, 0x62, 0xa8, 0x61, 0xd3, 0x12, 0x9b, 0xc0, 0x40, 0x0c, 0x75} },
-{ 0x8588, 16, {0x64, 0xff, 0x75, 0x63, 0xff, 0x75, 0x62, 0x00, 0x75, 0x61, 0x00, 0x85, 0x67, 0x82, 0x85, 0x66} },
-{ 0x8598, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xe5, 0x64} },
-{ 0x85a8, 16, {0xf0, 0xaf, 0x64, 0xae, 0x63, 0xad, 0x62, 0xac, 0x61, 0x78, 0x08, 0x12, 0x9b, 0xd1, 0x85, 0x67} },
-{ 0x85b8, 16, {0x82, 0x85, 0x66, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x85c8, 16, {0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x65, 0xe5, 0x60, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x5f} },
-{ 0x85d8, 16, {0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x65, 0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05} },
-{ 0x85e8, 16, {0x43, 0x65, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03, 0x43, 0x65, 0x02, 0xe5, 0x60, 0x24, 0x0b} },
-{ 0x85f8, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0x30, 0xe3, 0x03, 0x43, 0x65, 0x80, 0xef} },
-{ 0x8608, 16, {0x30, 0xe7, 0x12, 0x43, 0x65, 0x40, 0xe5, 0x67, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
-{ 0x8618, 16, {0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x60, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83} },
-{ 0x8628, 16, {0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x27, 0x85, 0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14} },
-{ 0x8638, 16, {0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x67} },
-{ 0x8648, 16, {0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x17, 0x85} },
-{ 0x8658, 16, {0x60, 0x82, 0x85, 0x5f, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3} },
-{ 0x8668, 16, {0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x3b, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0x74} },
-{ 0x8678, 16, {0xbf, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x65, 0xf0, 0xe5} },
-{ 0x8688, 16, {0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x04} },
-{ 0x8698, 16, {0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x0a, 0xf5, 0x82, 0xe4} },
-{ 0x86a8, 16, {0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5} },
-{ 0x86b8, 16, {0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff} },
-{ 0x86c8, 16, {0xe5, 0x67, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x60, 0x24} },
-{ 0x86d8, 16, {0x09, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x67, 0x24, 0x07, 0xf5, 0x82} },
-{ 0x86e8, 16, {0xe4, 0x35, 0x66, 0xf5, 0x83, 0xef, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x86f8, 16, {0xe4, 0xf0, 0x85, 0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x60, 0x82, 0x85, 0x5f} },
-{ 0x8708, 16, {0x83, 0xe0, 0x14, 0xff, 0x7d, 0x06, 0x12, 0x82, 0x60, 0x75, 0x65, 0x08, 0xe5, 0x60, 0x24, 0x0c} },
-{ 0x8718, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43, 0x65, 0x10, 0xe5, 0x67, 0x24} },
-{ 0x8728, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x66, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x45, 0x65, 0xf0, 0xe5, 0x60} },
-{ 0x8738, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x14, 0xff, 0x25, 0xe0, 0x25, 0xe0} },
-{ 0x8748, 16, {0xff, 0xe5, 0x60, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xfb, 0x4f} },
-{ 0x8758, 16, {0xf5, 0x65, 0xe5, 0x60, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5f, 0xf5, 0x83, 0xe0, 0x24, 0xd0} },
-{ 0x8768, 16, {0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a, 0x70, 0x12, 0x43, 0x65, 0x18} },
-{ 0x8778, 16, {0x80, 0x0d, 0x43, 0x65, 0x08, 0x80, 0x08, 0x43, 0x65, 0x38, 0x80, 0x03, 0x43, 0x65, 0x28, 0x85} },
-{ 0x8788, 13, {0x67, 0x82, 0x85, 0x66, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x65, 0xf0, 0x7f, 0x00} },
-{ 0x8795, 1, {0x22} },
-{ 0x8796, 4, {0x8e, 0x47, 0x8f, 0x48} },
-{ 0x879a, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x4a, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
-{ 0x87aa, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4d, 0x8f, 0x4e, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01} },
-{ 0x87ba, 16, {0xf5, 0x4c, 0xe4, 0x3e, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x08, 0xf0, 0xe5, 0x4a, 0x04} },
-{ 0x87ca, 16, {0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xf0, 0xa3, 0xe4, 0xf0, 0xe5, 0x4e, 0x24, 0x06, 0xf5, 0x82} },
-{ 0x87da, 16, {0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x85, 0x4c, 0x82, 0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xf0, 0xe5} },
-{ 0x87ea, 16, {0x4e, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4d, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x85, 0x4c, 0x82} },
-{ 0x87fa, 16, {0x85, 0x4b, 0x83, 0xa3, 0xa3, 0xa3, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x2b} },
-{ 0x880a, 16, {0xf8, 0xe6, 0xff, 0xe5, 0x4c, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0} },
-{ 0x881a, 16, {0xaf, 0x4a, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x49, 0x7f} },
-{ 0x882a, 16, {0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x49, 0x5f, 0xff} },
-{ 0x883a, 16, {0xe5, 0x4c, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4b, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xc3} },
-{ 0x884a, 5, {0x74, 0x07, 0xf0, 0x7f, 0x00} },
-{ 0x884f, 1, {0x22} },
-{ 0x8850, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x8860, 16, {0xaf, 0x82, 0xf5, 0x47, 0x8f, 0x48, 0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e} },
-{ 0x8870, 16, {0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0a, 0xf0, 0xe5, 0x48, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
-{ 0x8880, 16, {0x47, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x90, 0x7f, 0xc3, 0x74, 0x02, 0xf0, 0x7f} },
-{ 0x8890, 1, {0x00} },
-{ 0x8891, 1, {0x22} },
-{ 0x8892, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x88a2, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
-{ 0x88b2, 16, {0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
-{ 0x88c2, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
-{ 0x88cd, 1, {0x22} },
-{ 0x88ce, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x88de, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
-{ 0x88ee, 16, {0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
-{ 0x88fe, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
-{ 0x8909, 1, {0x22} },
-{ 0x890a, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
-{ 0x891a, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
-{ 0x892a, 16, {0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
-{ 0x893a, 7, {0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
-{ 0x8941, 1, {0x22} },
-{ 0x8942, 4, {0x8e, 0x47, 0x8f, 0x48} },
-{ 0x8946, 16, {0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x4b, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
-{ 0x8956, 16, {0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
-{ 0x8966, 16, {0x49, 0x7e, 0x75, 0x4a, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x49, 0x7e, 0x75, 0x4a} },
-{ 0x8976, 16, {0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x80, 0x80, 0x0a, 0x7e} },
-{ 0x8986, 16, {0x7d, 0x7f, 0x00, 0x75, 0x49, 0x7d, 0x75, 0x4a, 0x00, 0xe5, 0x4b, 0x70, 0x20, 0x85, 0x4a, 0x82} },
-{ 0x8996, 16, {0x85, 0x49, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
-{ 0x89a6, 16, {0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x3a, 0xe5, 0x48, 0x24} },
-{ 0x89b6, 16, {0x02, 0xff, 0xe4, 0x35, 0x47, 0xfe, 0xe5, 0x4b, 0x60, 0x10, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x85} },
-{ 0x89c6, 16, {0x4a, 0x82, 0x85, 0x49, 0x83, 0xf0, 0x15, 0x4b, 0x80, 0xec, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
-{ 0x89d6, 16, {0xa3, 0xe0, 0xff, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x25, 0xe0, 0x24, 0xb5, 0xf5, 0x82} },
-{ 0x89e6, 9, {0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
-{ 0x89ef, 1, {0x22} },
-{ 0x89f0, 16, {0xef, 0x24, 0x01, 0xf5, 0x48, 0xe4, 0x3e, 0xf5, 0x47, 0x7c, 0x7b, 0x7d, 0x80, 0x7e, 0x7b, 0x7f} },
-{ 0x8a00, 16, {0x80, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x07, 0xf0, 0xef, 0x24, 0x01, 0xff, 0xe4, 0x3e, 0x90, 0x01} },
-{ 0x8a10, 16, {0x31, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xfe} },
-{ 0x8a20, 16, {0xa3, 0xe0, 0x8e, 0x49, 0xf5, 0x4a, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x60} },
-{ 0x8a30, 16, {0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8a, 0xdd, 0x24, 0x14, 0x60, 0x03} },
-{ 0x8a40, 16, {0x02, 0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3} },
-{ 0x8a50, 16, {0xe4, 0x9f, 0xf5, 0x4c, 0x74, 0x01, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b} },
-{ 0x8a60, 16, {0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5} },
-{ 0x8a70, 16, {0x49, 0x95, 0x4b, 0x50, 0x03, 0x02, 0x8b, 0x30, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85} },
-{ 0x8a80, 16, {0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x02} },
-{ 0x8a90, 16, {0x8b, 0x30, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x74} },
-{ 0x8aa0, 16, {0x30, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e, 0xf5, 0x4b, 0xd3, 0xe5, 0x4c, 0x94, 0x40, 0xe5, 0x4b, 0x94} },
-{ 0x8ab0, 16, {0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5, 0x4a, 0x95, 0x4c, 0xe5, 0x49} },
-{ 0x8ac0, 16, {0x95, 0x4b, 0x40, 0x6c, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3} },
-{ 0x8ad0, 16, {0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a, 0x80, 0x53, 0x85, 0x48, 0x82} },
-{ 0x8ae0, 16, {0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x4c, 0xe4, 0x9e} },
-{ 0x8af0, 16, {0xf5, 0x4b, 0x45, 0x4c, 0x70, 0x07, 0xf5, 0x4b, 0x75, 0x4c, 0x40, 0x80, 0x11, 0xd3, 0xe5, 0x4c} },
-{ 0x8b00, 16, {0x94, 0x40, 0xe5, 0x4b, 0x94, 0x00, 0x40, 0x06, 0x75, 0x4b, 0x00, 0x75, 0x4c, 0x40, 0xd3, 0xe5} },
-{ 0x8b10, 16, {0x4a, 0x95, 0x4c, 0xe5, 0x49, 0x95, 0x4b, 0x40, 0x17, 0xae, 0x4b, 0xaf, 0x4c, 0x85, 0x48, 0x82} },
-{ 0x8b20, 16, {0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x49, 0xf5, 0x4a} },
-{ 0x8b30, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8b, 0xf0, 0x24, 0xf9} },
-{ 0x8b40, 16, {0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x40, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x84} },
-{ 0x8b50, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
-{ 0x8b60, 16, {0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a} },
-{ 0x8b70, 16, {0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2c, 0xe0} },
-{ 0x8b80, 16, {0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a} },
-{ 0x8b90, 16, {0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83} },
-{ 0x8ba0, 16, {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8c} },
-{ 0x8bb0, 16, {0x84, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8c, 0x84, 0x90, 0x01, 0x2d} },
-{ 0x8bc0, 16, {0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x70, 0x03, 0x02} },
-{ 0x8bd0, 16, {0x8c, 0x84, 0x90, 0x01, 0x2d, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
-{ 0x8be0, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
-{ 0x8bf0, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
-{ 0x8c00, 16, {0x94, 0x00, 0x50, 0x03, 0x02, 0x8c, 0x84, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
-{ 0x8c10, 16, {0x90, 0x01, 0x2e, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e} },
-{ 0x8c20, 16, {0x60, 0x62, 0x90, 0x01, 0x2e, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x31} },
-{ 0x8c30, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
-{ 0x8c40, 16, {0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x2f, 0xcf, 0xf0} },
-{ 0x8c50, 16, {0xa3, 0xef, 0xf0, 0xe5, 0x4a, 0x15, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x15, 0x49, 0x4e, 0x60, 0x24} },
-{ 0x8c60, 16, {0x90, 0x01, 0x2f, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
-{ 0x8c70, 16, {0xff, 0x90, 0x01, 0x31, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
-{ 0x8c80, 16, {0xef, 0xf0, 0x80, 0xcf, 0x85, 0x48, 0x82, 0x85, 0x47, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xa3, 0xe0} },
-{ 0x8c90, 6, {0x90, 0x7f, 0xc3, 0xf0, 0x7f, 0x00} },
-{ 0x8c96, 1, {0x22} },
-{ 0x8c97, 16, {0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xfd, 0xe4, 0x3e, 0xfc, 0x8f, 0x82, 0x8e, 0x83, 0x74} },
-{ 0x8ca7, 16, {0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f, 0x8d, 0x82, 0x8c, 0x83} },
-{ 0x8cb7, 16, {0xf0, 0x90, 0x11, 0xf0, 0xe4, 0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xf0, 0x90, 0x11, 0xf1, 0xe4} },
-{ 0x8cc7, 16, {0x93, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xf0, 0xe4, 0x90, 0x01, 0x33, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x8cd7, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xed, 0x24, 0x03, 0xfe, 0xe4, 0x3c, 0xa3} },
-{ 0x8ce7, 16, {0xf0, 0xa3, 0xce, 0xf0, 0x7e, 0x01, 0x7f, 0x33, 0x12, 0x19, 0xc1, 0x90, 0x7f, 0xc3, 0x74, 0x14} },
-{ 0x8cf7, 3, {0xf0, 0x7f, 0x00} },
-{ 0x8cfa, 1, {0x22} },
-{ 0x8cfb, 4, {0x8e, 0x40, 0x8f, 0x41} },
-{ 0x8cff, 16, {0x85, 0x40, 0x43, 0x85, 0x41, 0x44, 0x85, 0x44, 0x82, 0x85, 0x43, 0x83, 0xe0, 0x14, 0xb4, 0x0f} },
-{ 0x8d0f, 16, {0x00, 0x40, 0x03, 0x02, 0x8e, 0x32, 0x90, 0x8d, 0x1c, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8d, 0x49} },
-{ 0x8d1f, 16, {0x02, 0x8d, 0x5a, 0x02, 0x8d, 0x6b, 0x02, 0x8d, 0x8e, 0x02, 0x8d, 0x9f, 0x02, 0x8d, 0xb0, 0x02} },
-{ 0x8d2f, 16, {0x8d, 0xc0, 0x02, 0x8d, 0xcb, 0x02, 0x8d, 0xdb, 0x02, 0x8d, 0xeb, 0x02, 0x8d, 0xfb, 0x02, 0x8e} },
-{ 0x8d3f, 16, {0x02, 0x02, 0x8e, 0x32, 0x02, 0x8e, 0x12, 0x02, 0x8e, 0x22, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4} },
-{ 0x8d4f, 16, {0x35, 0x43, 0xfe, 0x12, 0x82, 0xea, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01, 0xff} },
-{ 0x8d5f, 16, {0xe4, 0x35, 0x43, 0xfe, 0x12, 0x83, 0x9f, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8d6f, 16, {0xf5, 0x46, 0xe4, 0x35, 0x43, 0xf5, 0x45, 0xe5, 0x46, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x45, 0xfe} },
-{ 0x8d7f, 16, {0x12, 0x84, 0x61, 0xaf, 0x46, 0xae, 0x45, 0x12, 0x84, 0xf4, 0x8f, 0x42, 0x02, 0x8e, 0x32, 0xe5} },
-{ 0x8d8f, 16, {0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x92, 0x8f, 0x42, 0x02, 0x8e, 0x32} },
-{ 0x8d9f, 16, {0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0xce, 0x8f, 0x42, 0x02, 0x8e} },
-{ 0x8daf, 16, {0x32, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x0a, 0x8f, 0x42, 0x80} },
-{ 0x8dbf, 16, {0x72, 0xaf, 0x41, 0xae, 0x40, 0x12, 0x89, 0xf0, 0x8f, 0x42, 0x80, 0x67, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8dcf, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x87, 0x96, 0x8f, 0x42, 0x80, 0x57, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8ddf, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x84, 0x1d, 0x8f, 0x42, 0x80, 0x47, 0xe5, 0x44, 0x24, 0x01} },
-{ 0x8def, 16, {0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x88, 0x50, 0x8f, 0x42, 0x80, 0x37, 0x12, 0x8c, 0x97, 0x8f} },
-{ 0x8dff, 16, {0x42, 0x80, 0x30, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x11, 0xd8, 0x8f} },
-{ 0x8e0f, 16, {0x42, 0x80, 0x20, 0xe5, 0x44, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x43, 0xfe, 0x12, 0x89, 0x42, 0x8f} },
-{ 0x8e1f, 16, {0x42, 0x80, 0x10, 0xaf, 0x41, 0xae, 0x40, 0x7c, 0x02, 0x7d, 0x4d, 0x7b, 0x40, 0x12, 0x1b, 0x0c} },
-{ 0x8e2f, 5, {0xe4, 0xf5, 0x42, 0xaf, 0x42} },
-{ 0x8e34, 1, {0x22} },
-{ 0x8e35, 8, {0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e} },
-{ 0x8e3d, 16, {0x75, 0x68, 0x01, 0x75, 0x69, 0x3b, 0xe4, 0xf5, 0x67, 0xaf, 0x63, 0x15, 0x63, 0xef, 0x70, 0x03} },
-{ 0x8e4d, 16, {0x02, 0x8e, 0xd3, 0xaf, 0x62, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x61} },
-{ 0x8e5d, 16, {0xae, 0x60, 0xad, 0x5f, 0xac, 0x5e, 0x12, 0x9b, 0x2e, 0xaf, 0x03, 0x8f, 0x66, 0xaf, 0x61, 0xae} },
-{ 0x8e6d, 16, {0x60, 0xad, 0x5f, 0xac, 0x5e, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x62, 0xe4} },
-{ 0x8e7d, 16, {0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
-{ 0x8e8d, 16, {0x12, 0x9b, 0x2e, 0x8f, 0x61, 0x8e, 0x60, 0x8d, 0x5f, 0x8c, 0x5e, 0xe5, 0x66, 0x24, 0x30, 0xf5} },
-{ 0x8e9d, 16, {0x66, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x66, 0xf5, 0x66, 0x05, 0x69, 0xe5, 0x69} },
-{ 0x8ead, 16, {0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x69, 0xe5} },
-{ 0x8ebd, 16, {0x69, 0xae, 0x68, 0x70, 0x02, 0x05, 0x68, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x66, 0xf0, 0x05} },
-{ 0x8ecd, 16, {0x67, 0x05, 0x67, 0x02, 0x8e, 0x46, 0xe5, 0x69, 0x15, 0x69, 0x70, 0x02, 0x15, 0x68, 0xaf, 0x67} },
-{ 0x8edd, 16, {0x15, 0x67, 0xef, 0x60, 0x23, 0xe5, 0x69, 0x15, 0x69, 0xae, 0x68, 0x70, 0x02, 0x15, 0x68, 0xf5} },
-{ 0x8eed, 16, {0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x65, 0xe5, 0x65, 0xac, 0x64, 0x70, 0x02, 0x05, 0x64, 0x14} },
-{ 0x8efd, 8, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
-{ 0x8f05, 1, {0x22} },
-{ 0x8f06, 16, {0xe4, 0x90, 0x01, 0x67, 0xf0, 0x7e, 0x01, 0x7f, 0x68, 0x90, 0x01, 0x5c, 0xee, 0xf0, 0xa3, 0xef} },
-{ 0x8f16, 10, {0xf0, 0x90, 0x01, 0x60, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
-{ 0x8f20, 16, {0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0x67, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
-{ 0x8f30, 16, {0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
-{ 0x8f40, 16, {0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0x60, 0xe0, 0xfc, 0xa3, 0xe0} },
-{ 0x8f50, 16, {0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
-{ 0x8f60, 16, {0xeb, 0xf0, 0x90, 0x01, 0x60, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
-{ 0x8f70, 16, {0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x60, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
-{ 0x8f80, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
-{ 0x8f90, 1, {0x22} },
-{ 0x8f91, 16, {0x90, 0x01, 0x67, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0x5c, 0xe0, 0xfc, 0xa3, 0xe0} },
-{ 0x8fa1, 16, {0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
-{ 0x8fb1, 16, {0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
-{ 0x8fc1, 16, {0x9a, 0x1f, 0x90, 0x01, 0x5c, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9a, 0x8e, 0xfc, 0xd3, 0xe5, 0xf0} },
-{ 0x8fd1, 16, {0x94, 0x25, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0x5c, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x68} },
-{ 0x8fe1, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0x67, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
-{ 0x8ff1, 1, {0x22} },
-{ 0x8ff2, 16, {0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x63, 0x7b, 0x75, 0x64} },
-{ 0x9002, 16, {0x80, 0xe5, 0x64, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x63, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x65, 0xf5} },
-{ 0x9012, 16, {0x66, 0x89, 0x67, 0xfe, 0x12, 0x8f, 0x91, 0xef, 0x60, 0x3b, 0xab, 0x65, 0xaa, 0x66, 0xa9, 0x67} },
-{ 0x9022, 16, {0x12, 0x9a, 0x48, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9a, 0x61, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
-{ 0x9032, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
-{ 0x9042, 16, {0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
-{ 0x9052, 5, {0x74, 0x04, 0xf0, 0xd2, 0xaf} },
-{ 0x9057, 1, {0x22} },
-{ 0x9058, 16, {0x12, 0x8f, 0xf2, 0xe4, 0xf5, 0x5e, 0x74, 0x36, 0x25, 0x5e, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x5f} },
-{ 0x9068, 16, {0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x5f, 0xff, 0xc4} },
-{ 0x9078, 16, {0x54, 0x0f, 0xf5, 0x60, 0x60, 0x22, 0x74, 0x63, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
-{ 0x9088, 16, {0x83, 0xe5, 0x5f, 0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0xe5, 0x5f, 0x45, 0x60, 0xfb, 0x12, 0x8f, 0x20} },
-{ 0x9098, 16, {0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40} },
-{ 0x90a8, 16, {0xb5, 0x12, 0x8f, 0xf2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8} },
-{ 0x90b8, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x5e} },
-{ 0x90c8, 16, {0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
-{ 0x90d8, 16, {0x16, 0xaf, 0x5e, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2} },
-{ 0x90e8, 16, {0x80, 0xef, 0xe5, 0x5f, 0xf4, 0x52, 0x3a, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
-{ 0x90f8, 16, {0x90, 0x02, 0x9e, 0xe0, 0x60, 0x03, 0x02, 0x91, 0xc5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
-{ 0x9108, 16, {0x11, 0x8e, 0x61, 0x8f, 0x62, 0xc3, 0xe5, 0x61, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
-{ 0x9118, 16, {0x5b, 0xe0, 0x65, 0x62, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x5e, 0xaf, 0x5e, 0x74, 0x01, 0xa8, 0x07} },
-{ 0x9128, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01, 0x5b, 0xe0, 0x55, 0x5f, 0x60} },
-{ 0x9138, 16, {0x14, 0xaf, 0x5e, 0x7d, 0x08, 0xe5, 0x5f, 0x55, 0x62, 0xfb, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05} },
-{ 0x9148, 16, {0x12, 0x8f, 0xf2, 0x80, 0xec, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
-{ 0x9158, 16, {0x5b, 0xe5, 0x62, 0xf0, 0xe4, 0xf5, 0x5e, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x5e, 0xf8, 0xe6, 0xf5} },
-{ 0x9168, 16, {0x5f, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x5f, 0x1e, 0xe5, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x02} },
-{ 0x9178, 16, {0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70, 0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
-{ 0x9188, 16, {0x5e, 0xf8, 0xe6, 0xf5, 0x5f, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
-{ 0x9198, 16, {0xe0, 0x65, 0x5f, 0x60, 0x11, 0xaf, 0x5e, 0x7d, 0x04, 0xab, 0x5f, 0x12, 0x8f, 0x20, 0xef, 0x70} },
-{ 0x91a8, 16, {0x05, 0x12, 0x8f, 0xf2, 0x80, 0xef, 0x74, 0x9a, 0x25, 0x5e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
-{ 0x91b8, 16, {0x83, 0xe5, 0x5f, 0xf0, 0x05, 0x5e, 0xe5, 0x5e, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x8f, 0xf2} },
-{ 0x91c8, 1, {0x22} },
-{ 0x91c9, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x6e, 0x02, 0x92, 0x10} },
-{ 0x91d5, 16, {0x02, 0x05, 0x28, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
-{ 0x91e5, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
-{ 0x91f5, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
-{ 0x9205, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x92, 0x55, 0xe4, 0x7e} },
-{ 0x9215, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
-{ 0x9225, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
-{ 0x9235, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
-{ 0x9245, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
-{ 0x9255, 16, {0x60, 0x24, 0x02, 0x28, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
-{ 0x9265, 16, {0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
-{ 0x9275, 8, {0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
-{ 0x927d, 1, {0x00} },
-{ 0x927e, 11, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
-{ 0x9289, 16, {0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
-{ 0x9299, 16, {0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
-{ 0x92a9, 16, {0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xb5, 0x1e} },
-{ 0x92b9, 10, {0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0x62, 0xee, 0xf0} },
-{ 0x92c3, 9, {0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
-{ 0x92cc, 2, {0xa9, 0x03} },
-{ 0x92ce, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
-{ 0x92de, 16, {0x6c, 0x45, 0x6d, 0xf5, 0x6e, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
-{ 0x92ee, 16, {0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
-{ 0x92fe, 16, {0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x6e, 0xeb} },
-{ 0x930e, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x6e, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
-{ 0x931e, 16, {0x05, 0x22, 0xe5, 0x6c, 0x5c, 0xfe, 0xe5, 0x6d, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
-{ 0x932e, 16, {0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
-{ 0x933e, 16, {0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x6c, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x6d, 0x22, 0x7f} },
-{ 0x934e, 1, {0x00} },
-{ 0x934f, 1, {0x22} },
-{ 0x9350, 16, {0x7e, 0x7b, 0x7f, 0x80, 0xef, 0x24, 0x01, 0xf5, 0x66, 0xe4, 0x3e, 0xf5, 0x65, 0x75, 0x63, 0x02} },
-{ 0x9360, 16, {0x75, 0x64, 0x4e, 0x8f, 0x82, 0x8e, 0x83, 0x74, 0x0f, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
-{ 0x9370, 16, {0xe0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xf0, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83, 0xa3, 0xe0} },
-{ 0x9380, 16, {0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xf0, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3} },
-{ 0x9390, 16, {0x74, 0xff, 0xf0, 0xe5, 0x66, 0x24, 0x03, 0xf5, 0x68, 0xe4, 0x35, 0x65, 0xf5, 0x67, 0x85, 0x64} },
-{ 0x93a0, 16, {0x82, 0x85, 0x63, 0x83, 0xe0, 0x14, 0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x98, 0x43, 0x90, 0x93} },
-{ 0x93b0, 16, {0xb5, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x93, 0xd6, 0x02, 0x94, 0x7c, 0x02, 0x95, 0xba, 0x02, 0x95} },
-{ 0x93c0, 16, {0xda, 0x02, 0x95, 0xda, 0x02, 0x96, 0x7f, 0x02, 0x96, 0xbd, 0x02, 0x96, 0xe4, 0x02, 0x97, 0xa6} },
-{ 0x93d0, 16, {0x02, 0x97, 0xda, 0x02, 0x98, 0x0b, 0xe4, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
-{ 0x93e0, 16, {0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xe4, 0xff, 0xe4, 0xfe} },
-{ 0x93f0, 16, {0xef, 0x60, 0x10, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5} },
-{ 0x9400, 16, {0x5f, 0x80, 0x0d, 0x74, 0x28, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x5f} },
-{ 0x9410, 16, {0xe5, 0x62, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe5, 0x5f, 0xf0, 0xe0, 0xf5} },
-{ 0x9420, 16, {0x60, 0x65, 0x5f, 0x60, 0x3d, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5} },
-{ 0x9430, 16, {0x5e, 0x04, 0xfd, 0x05, 0x68, 0xe5, 0x68, 0xaa, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82} },
-{ 0x9440, 16, {0x8a, 0x83, 0xed, 0xf0, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
-{ 0x9450, 16, {0x82, 0x8c, 0x83, 0xe5, 0x5f, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02} },
-{ 0x9460, 16, {0x98, 0x4e, 0x0e, 0xee, 0x64, 0x24, 0x70, 0x88, 0x0f, 0xef, 0x64, 0x02, 0x70, 0x80, 0x05, 0x5e} },
-{ 0x9470, 16, {0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03, 0x02, 0x93, 0xd9, 0x02, 0x98, 0x4e, 0x7e, 0x20, 0x7f, 0x00} },
-{ 0x9480, 16, {0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
-{ 0x9490, 16, {0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5} },
-{ 0x94a0, 16, {0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04, 0x74, 0x92, 0xf0, 0xa3, 0x74, 0x7e, 0xf0} },
-{ 0x94b0, 16, {0xe4, 0xf5, 0x60, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xf5, 0x5e, 0xaf} },
-{ 0x94c0, 16, {0x5e, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x5f, 0x90, 0x01} },
-{ 0x94d0, 16, {0x62, 0xf0, 0x90, 0x01, 0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
-{ 0x94e0, 16, {0x83, 0xa3, 0x74, 0x02, 0xf0, 0x90, 0x01, 0x62, 0xe0, 0x65, 0x5f, 0x70, 0x39, 0x90, 0x01, 0x5e} },
-{ 0x94f0, 16, {0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xee, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0} },
-{ 0x9500, 16, {0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5} },
-{ 0x9510, 16, {0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90} },
-{ 0x9520, 16, {0x01, 0x62, 0xf0, 0x75, 0x60, 0xff, 0x90, 0x01, 0x62, 0xe0, 0xff, 0x60, 0x3c, 0x85, 0x66, 0x82} },
-{ 0x9530, 16, {0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xfe, 0x05, 0x68, 0xe5, 0x68, 0xac} },
-{ 0x9540, 16, {0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x68, 0xe5, 0x68} },
-{ 0x9550, 16, {0xac, 0x67, 0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82} },
-{ 0x9560, 16, {0x85, 0x67, 0x83, 0xe5, 0x5f, 0xf0, 0x75, 0x60, 0xff, 0xe5, 0x60, 0x70, 0x16, 0x74, 0x08, 0x25} },
-{ 0x9570, 16, {0x62, 0xf5, 0x62, 0xe4, 0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0x64, 0x04, 0x60, 0x03} },
-{ 0x9580, 16, {0x02, 0x94, 0xbf, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe4, 0xf5, 0x5e} },
-{ 0x9590, 16, {0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0x74, 0x08, 0x25, 0x62, 0xf5, 0x62, 0xe4} },
-{ 0x95a0, 16, {0x35, 0x61, 0xf5, 0x61, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x40, 0xe3, 0x90, 0x00, 0x04} },
-{ 0x95b0, 16, {0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12, 0xf0, 0x02, 0x98, 0x4e, 0x85, 0x64, 0x82, 0x85, 0x63, 0x83} },
-{ 0x95c0, 16, {0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90} },
-{ 0x95d0, 16, {0x02, 0x95, 0xf0, 0x90, 0x01, 0x62, 0xf0, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0x74, 0x03, 0xf0} },
-{ 0x95e0, 16, {0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0, 0xff, 0x90, 0x01, 0x62, 0xe0} },
-{ 0x95f0, 16, {0xb5, 0x07, 0x1e, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x85, 0x66, 0x82} },
-{ 0x9600, 16, {0x85, 0x65, 0x83, 0xa3, 0xa3, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0x74, 0xff, 0xf0, 0xf5} },
-{ 0x9610, 16, {0x60, 0xe5, 0x60, 0x60, 0x03, 0x02, 0x98, 0x4e, 0x90, 0x01, 0x5e, 0xf0, 0xa3, 0x74, 0x96, 0xf0} },
-{ 0x9620, 16, {0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3} },
-{ 0x9630, 16, {0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5, 0x60, 0x90, 0x02, 0x95, 0xe0} },
-{ 0x9640, 16, {0x55, 0x60, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x5f, 0x85, 0x64, 0x82, 0x85} },
-{ 0x9650, 16, {0x63, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x5f, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00} },
-{ 0x9660, 16, {0x8f, 0x5f, 0xe5, 0x5f, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3} },
-{ 0x9670, 16, {0xa3, 0xe4, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67, 0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x7e} },
-{ 0x9680, 16, {0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xaf, 0x62, 0xae, 0x61, 0xe4, 0xfd, 0x12} },
-{ 0x9690, 16, {0x81, 0xe0, 0x85, 0x62, 0x82, 0x85, 0x61, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
-{ 0x96a0, 16, {0x62, 0x82, 0x85, 0x61, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x62, 0x82, 0x85, 0x61} },
-{ 0x96b0, 16, {0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x98, 0x4e, 0xc2, 0x04, 0x7e} },
-{ 0x96c0, 16, {0x20, 0x7f, 0x00, 0x75, 0x61, 0x20, 0x75, 0x62, 0x00, 0xe5, 0x62, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
-{ 0x96d0, 16, {0x35, 0x61, 0xf5, 0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xaf, 0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81} },
-{ 0x96e0, 16, {0xe0, 0x02, 0x98, 0x4e, 0xe4, 0xf5, 0x60, 0xf5, 0x5e, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24} },
-{ 0x96f0, 16, {0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x61, 0x8f, 0x62, 0xfe, 0xe4, 0xfd, 0x12} },
-{ 0x9700, 16, {0x81, 0xe0, 0xe5, 0x62, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x61, 0xf5, 0x83, 0xe0, 0x54, 0xfc} },
-{ 0x9710, 16, {0xf0, 0xaf, 0x5e, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc} },
-{ 0x9720, 16, {0x8f, 0x60, 0xe5, 0x60, 0x70, 0x11, 0xaf, 0x5e, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x6c, 0x10, 0x75} },
-{ 0x9730, 16, {0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf, 0x5e, 0x7d, 0x01, 0xfb} },
-{ 0x9740, 16, {0x75, 0x6c, 0x80, 0x75, 0x6d, 0x40, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xe5, 0x60, 0x70, 0x10, 0xaf} },
-{ 0x9750, 16, {0x5e, 0x7d, 0x02, 0xfb, 0x75, 0x6c, 0x10, 0x75, 0x6d, 0x20, 0x12, 0x92, 0xcc, 0x8f, 0x60, 0xaf} },
-{ 0x9760, 16, {0x62, 0xae, 0x61, 0x7d, 0x01, 0x12, 0x81, 0xe0, 0xe5, 0x60, 0x60, 0x2b, 0x85, 0x66, 0x82, 0x85} },
-{ 0x9770, 16, {0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5e, 0x04, 0xff, 0x05, 0x68, 0xe5, 0x68, 0xac, 0x67} },
-{ 0x9780, 16, {0x70, 0x02, 0x05, 0x67, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x68, 0x82, 0x85, 0x67} },
-{ 0x9790, 16, {0x83, 0xe5, 0x60, 0xf0, 0x02, 0x98, 0x4e, 0x05, 0x5e, 0xe5, 0x5e, 0xd3, 0x94, 0x03, 0x50, 0x03} },
-{ 0x97a0, 16, {0x02, 0x96, 0xe9, 0x02, 0x98, 0x4e, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
-{ 0x97b0, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x98, 0xf0, 0xa3, 0x74, 0x6d, 0xf0, 0x7e} },
-{ 0x97c0, 16, {0x02, 0x7f, 0xd3, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x70, 0x03, 0x02, 0x98, 0x4e, 0x85, 0x66} },
-{ 0x97d0, 16, {0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x74, 0xe4, 0x90, 0x02, 0xd3, 0xf0, 0xa3} },
-{ 0x97e0, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x67, 0xf0, 0xa3} },
-{ 0x97f0, 16, {0xe5, 0x68, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x4f, 0x85} },
-{ 0x9800, 16, {0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0x80, 0x43, 0xe4, 0x90, 0x02, 0xd3, 0xf0} },
-{ 0x9810, 16, {0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x64, 0x24, 0x02} },
-{ 0x9820, 16, {0x90, 0x02, 0xda, 0xf0, 0xe4, 0x35, 0x63, 0x90, 0x02, 0xd9, 0xf0, 0x7e, 0x02, 0x7f, 0xd3, 0x12} },
-{ 0x9830, 16, {0x80, 0x00, 0xef, 0x64, 0x08, 0x60, 0x17, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0xe4} },
-{ 0x9840, 16, {0xf0, 0x80, 0x0b, 0x85, 0x66, 0x82, 0x85, 0x65, 0x83, 0xa3, 0xa3, 0x74, 0x01, 0xf0, 0x90, 0x01} },
-{ 0x9850, 16, {0x5e, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0x5e, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
-{ 0x9860, 12, {0xf6, 0x90, 0x7f, 0xc3, 0x74, 0x24, 0xf0, 0xe4, 0x90, 0x02, 0x4d, 0xf0} },
-{ 0x986c, 1, {0x22} },
-{ 0x986d, 16, {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
-{ 0x987d, 16, {0xe4, 0xfd, 0x74, 0x01, 0x7e, 0x00, 0xa8, 0x05, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce} },
-{ 0x988d, 16, {0xd8, 0xf9, 0xff, 0xe5, 0x3b, 0xfb, 0xe4, 0xef, 0x5b, 0x70, 0x03, 0x02, 0x99, 0x45, 0xed, 0x75} },
-{ 0x989d, 16, {0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xfe, 0xf5, 0x83, 0xe5} },
-{ 0x98ad, 16, {0x82, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x60} },
-{ 0x98bd, 16, {0x03, 0x02, 0x99, 0x45, 0xef, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0xfc, 0x74} },
-{ 0x98cd, 16, {0x36, 0x2d, 0xf8, 0xec, 0xf6, 0x30, 0xe5, 0x70, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02} },
-{ 0x98dd, 16, {0xf5, 0x83, 0xe0, 0x60, 0x63, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
-{ 0x98ed, 16, {0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9a, 0xa4, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8f, 0x82} },
-{ 0x98fd, 16, {0x8e, 0x83, 0xf0, 0x74, 0x96, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0} },
-{ 0x990d, 16, {0x70, 0x36, 0xed, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0} },
-{ 0x991d, 16, {0xed, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c, 0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82} },
-{ 0x992d, 16, {0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe, 0xed, 0x25, 0xe0, 0x24, 0x8d, 0xf5, 0x82, 0xe4, 0x34} },
-{ 0x993d, 16, {0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x0d, 0xed, 0x64, 0x04, 0x60, 0x03, 0x02, 0x98} },
-{ 0x994d, 1, {0x7f} },
-{ 0x994e, 1, {0x22} },
-{ 0x994f, 16, {0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
-{ 0x995f, 16, {0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
-{ 0x996f, 16, {0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
-{ 0x997f, 16, {0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
-{ 0x998f, 16, {0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
-{ 0x999f, 16, {0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
-{ 0x99af, 16, {0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
-{ 0x99bf, 16, {0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
-{ 0x99cf, 16, {0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
-{ 0x99df, 16, {0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
-{ 0x99ef, 16, {0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
-{ 0x99ff, 16, {0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
-{ 0x9a0f, 16, {0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
-{ 0x9a1f, 16, {0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
-{ 0x9a2f, 16, {0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
-{ 0x9a3f, 9, {0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x99, 0x9f, 0x73} },
-{ 0x9a48, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
-{ 0x9a58, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x9a61, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
-{ 0x9a71, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
-{ 0x9a81, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
-{ 0x9a8e, 16, {0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
-{ 0x9a9e, 6, {0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
-{ 0x9aa4, 16, {0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
-{ 0x9ab4, 6, {0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
-{ 0x9aba, 16, {0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
-{ 0x9aca, 16, {0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
-{ 0x9ada, 16, {0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
-{ 0x9aea, 8, {0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
-{ 0x9af2, 16, {0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
-{ 0x9b02, 16, {0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
-{ 0x9b12, 16, {0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
-{ 0x9b22, 16, {0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
-{ 0x9b32, 16, {0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
-{ 0x9b42, 16, {0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
-{ 0x9b52, 16, {0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
-{ 0x9b62, 16, {0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
-{ 0x9b72, 16, {0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
-{ 0x9b82, 16, {0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
-{ 0x9b92, 16, {0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
-{ 0x9ba2, 16, {0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
-{ 0x9bb2, 14, {0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
-{ 0x9bc0, 16, {0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
-{ 0x9bd0, 1, {0x22} },
-{ 0x9bd1, 16, {0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
-{ 0x9be1, 3, {0xd8, 0xf1, 0x22} },
-{ 0x9be4, 16, {0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
-{ 0x9bf4, 7, {0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
-{ 0x9bfb, 12, {0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
-{ 0x9c07, 16, {0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0x12} },
-{ 0x9c17, 16, {0x9c, 0x1e, 0x12, 0x9c, 0x1e, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
-{ 0x9c27, 16, {0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
-{ 0x9c37, 1, {0x22} },
+{ 0x81e0, 2, {0xae, 0x07} },
+{ 0x81e2, 16, {0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
+{ 0x81f2, 16, {0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
+{ 0x8202, 16, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
+{ 0x8212, 16, {0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
+{ 0x8222, 14, {0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
+{ 0x8230, 1, {0x22} },
+{ 0x8231, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
+{ 0x8241, 15, {0x53, 0x91, 0x7f, 0x90, 0x01, 0xc4, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x8250, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
+{ 0x8260, 16, {0x83, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x5e, 0x74, 0xbf} },
+{ 0x8270, 16, {0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x8280, 16, {0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xf0, 0xf9, 0xed, 0x60, 0x1d, 0x74, 0x01} },
+{ 0x8290, 16, {0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4} },
+{ 0x82a0, 16, {0xef, 0x55, 0x3b, 0x60, 0x04, 0x79, 0x09, 0x80, 0x02, 0x79, 0x0d, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x82b0, 16, {0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54, 0xef, 0xf0, 0x8b} },
+{ 0x82c0, 16, {0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5e, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e} },
+{ 0x82d0, 4, {0x83, 0xa3, 0xe9, 0xf0} },
+{ 0x82d4, 1, {0x22} },
+{ 0x82d5, 4, {0x8f, 0x5e, 0x8d, 0x5f} },
+{ 0x82d9, 16, {0xe4, 0xf5, 0x60, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x82e9, 16, {0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x82f9, 16, {0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50} },
+{ 0x8309, 16, {0x3c, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83} },
+{ 0x8319, 16, {0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
+{ 0x8329, 16, {0x00, 0xc3, 0x12, 0x9c, 0xea, 0x40, 0x0c, 0x75, 0x60, 0x40, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76} },
+{ 0x8339, 16, {0x10, 0x80, 0x0a, 0x75, 0x60, 0x80, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76, 0x38, 0xe5, 0x60, 0x45} },
+{ 0x8349, 16, {0x5f, 0x44, 0x01, 0xff, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x8359, 5, {0x20, 0xf5, 0x83, 0xef, 0xf0} },
+{ 0x835e, 1, {0x22} },
+{ 0x835f, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x836f, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x55, 0x8f, 0x56, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc6, 0xf5} },
+{ 0x837f, 16, {0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc7} },
+{ 0x838f, 16, {0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x25, 0x54, 0xf8, 0xe4, 0xf6} },
+{ 0x839f, 16, {0xe5, 0x56, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf} },
+{ 0x83af, 16, {0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xaf, 0x54, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x85, 0x56, 0x82} },
+{ 0x83bf, 16, {0x85, 0x55, 0x83, 0xa3, 0xa3, 0xe0, 0x20, 0xe0, 0x22, 0xe0, 0xff, 0xe5, 0x56, 0x24, 0x05, 0xf5} },
+{ 0x83cf, 16, {0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0xe5, 0x56, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x55} },
+{ 0x83df, 16, {0xf5, 0x83, 0xe0, 0xff, 0xaf, 0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x74, 0xf8, 0x25, 0x54, 0xf5} },
+{ 0x83ef, 16, {0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c} },
+{ 0x83ff, 16, {0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe} },
+{ 0x840f, 16, {0xe5, 0x54, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3} },
+{ 0x841f, 16, {0xef, 0xf0, 0xaf, 0x54, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42} },
+{ 0x842f, 3, {0x30, 0x7f, 0x00} },
+{ 0x8432, 1, {0x22} },
+{ 0x8433, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0xff, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x74, 0xf8} },
+{ 0x8443, 16, {0x25, 0x54, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x75, 0xf0, 0x08} },
+{ 0x8453, 16, {0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x56, 0x8f, 0x57, 0xf5, 0x83} },
+{ 0x8463, 16, {0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x8473, 16, {0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xe5, 0x57, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x56, 0xf5} },
+{ 0x8483, 16, {0x83, 0xe0, 0x30, 0xe0, 0x09, 0x85, 0x57, 0x82, 0x85, 0x56, 0x83, 0xe0, 0xf5, 0x55, 0xaf, 0x54} },
+{ 0x8493, 16, {0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x54} },
+{ 0x84a3, 16, {0x25, 0xe0, 0x24, 0xc6, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5} },
+{ 0x84b3, 16, {0x54, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x7f, 0x00} },
+{ 0x84c3, 1, {0x22} },
+{ 0x84c4, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x84c8, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x56, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
+{ 0x84d8, 16, {0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x55, 0x82, 0x8e, 0x83, 0xa3} },
+{ 0x84e8, 16, {0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x56, 0x7d, 0x02, 0x12, 0x82, 0xd5, 0x85, 0x55, 0x82, 0x85, 0x54} },
+{ 0x84f8, 15, {0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x56, 0x7d, 0x04, 0x12, 0x82, 0xd5, 0x7f, 0x00} },
+{ 0x8507, 1, {0x22} },
+{ 0x8508, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
+{ 0x8518, 16, {0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8528, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
+{ 0x8538, 16, {0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
+{ 0x8548, 16, {0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
+{ 0x8558, 16, {0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
+{ 0x8568, 16, {0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
+{ 0x8578, 16, {0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8588, 16, {0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
+{ 0x8598, 3, {0x83, 0xf0, 0x22} },
+{ 0x859b, 16, {0x79, 0x0d, 0x8e, 0x54, 0x8f, 0x55, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x85ab, 16, {0xf4, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xaf, 0x82, 0xfe, 0xad, 0x01, 0x19, 0xed, 0x60, 0x24, 0x0f} },
+{ 0x85bb, 16, {0xef, 0xac, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x55, 0xe5} },
+{ 0x85cb, 16, {0x55, 0xaa, 0x54, 0x70, 0x02, 0x05, 0x54, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xe0, 0x6d, 0x60, 0xd9} },
+{ 0x85db, 5, {0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x85e0, 1, {0x22} },
+{ 0x85e1, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x85e5, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x85f5, 16, {0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x5c, 0x8f, 0x5d, 0xaa, 0x06, 0xa9, 0x55, 0x7b, 0x01, 0xc0} },
+{ 0x8605, 16, {0x03, 0xc0, 0x01, 0xe5, 0x5b, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x01, 0xf9, 0x74, 0x03, 0x35, 0xf0} },
+{ 0x8615, 16, {0xa8, 0x01, 0xfc, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9b, 0x49} },
+{ 0x8625, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8635, 16, {0xe0, 0xff, 0x7b, 0x08, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xd3, 0x12, 0x9c, 0xea, 0x40, 0x10} },
+{ 0x8645, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x00, 0x08, 0x80, 0x2e} },
+{ 0x8655, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8665, 16, {0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x08, 0x79, 0x07, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50, 0x0e} },
+{ 0x8675, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x07, 0x08, 0x00, 0x85, 0x55} },
+{ 0x8685, 16, {0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
+{ 0x8695, 16, {0x7f, 0x00, 0x7e, 0x50, 0x7d, 0x46, 0x7c, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d} },
+{ 0x86a5, 16, {0x57, 0x8c, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0x12, 0x9c, 0x58, 0xaf, 0x03} },
+{ 0x86b5, 16, {0x8f, 0x5a, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x86c5, 16, {0x78, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d, 0x57, 0x8c, 0x56, 0xe5, 0x5a, 0xc3} },
+{ 0x86d5, 16, {0x94, 0x05, 0x40, 0x15, 0xe5, 0x59, 0x24, 0x01, 0xf5, 0x59, 0xe4, 0x35, 0x58, 0xf5, 0x58, 0xe4} },
+{ 0x86e5, 16, {0x35, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3} },
+{ 0x86f5, 16, {0xe4, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x8705, 16, {0x5d, 0x82, 0x85, 0x5c, 0x83, 0xe5, 0x59, 0xf0, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56} },
+{ 0x8715, 16, {0x78, 0x08, 0x12, 0x9c, 0xfb, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x5d} },
+{ 0x8725, 16, {0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x5a, 0xe5, 0x55} },
+{ 0x8735, 16, {0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x5a} },
+{ 0x8745, 16, {0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05, 0x43, 0x5a, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03} },
+{ 0x8755, 16, {0x43, 0x5a, 0x02, 0xe5, 0x55, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x8765, 16, {0x30, 0xe3, 0x03, 0x43, 0x5a, 0x80, 0xef, 0x30, 0xe7, 0x12, 0x43, 0x5a, 0x40, 0xe5, 0x5d, 0x24} },
+{ 0x8775, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x55, 0x24, 0x0b} },
+{ 0x8785, 16, {0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x23, 0xaf} },
+{ 0x8795, 16, {0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x5d} },
+{ 0x87a5, 16, {0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0xe4, 0xf5, 0x5a} },
+{ 0x87b5, 16, {0x80, 0x10, 0xaf, 0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4} },
+{ 0x87c5, 16, {0x52, 0x3b, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x85, 0x5d} },
+{ 0x87d5, 16, {0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5} },
+{ 0x87e5, 16, {0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x87f5, 16, {0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83} },
+{ 0x8805, 16, {0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5} },
+{ 0x8815, 16, {0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x06} },
+{ 0x8825, 16, {0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4} },
+{ 0x8835, 16, {0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5} },
+{ 0x8845, 16, {0x83, 0xef, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x85, 0x5d} },
+{ 0x8855, 16, {0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xf0, 0xaf, 0x5b, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x75, 0x5a} },
+{ 0x8865, 16, {0x08, 0xe5, 0x55, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43} },
+{ 0x8875, 16, {0x5a, 0x10, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x54, 0x03} },
+{ 0x8885, 16, {0x45, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x14} },
+{ 0x8895, 16, {0xff, 0x25, 0xe0, 0x25, 0xe0, 0xff, 0xe5, 0x55, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5} },
+{ 0x88a5, 16, {0x83, 0xe0, 0x24, 0xfb, 0x4f, 0xf5, 0x5a, 0xe5, 0x55, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x54} },
+{ 0x88b5, 16, {0xf5, 0x83, 0xe0, 0x24, 0xd0, 0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a} },
+{ 0x88c5, 16, {0x70, 0x12, 0x43, 0x5a, 0x18, 0x80, 0x0d, 0x43, 0x5a, 0x08, 0x80, 0x08, 0x43, 0x5a, 0x38, 0x80} },
+{ 0x88d5, 16, {0x03, 0x43, 0x5a, 0x28, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5a, 0xf0} },
+{ 0x88e5, 9, {0xaf, 0x5b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x7f, 0x00} },
+{ 0x88ee, 1, {0x22} },
+{ 0x88ef, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4} },
+{ 0x88ff, 16, {0x34, 0x20, 0xad, 0x82, 0xfc, 0x90, 0x01, 0x2c, 0x74, 0x08, 0xf0, 0xef, 0x04, 0xa3, 0xf0, 0xe4} },
+{ 0x890f, 16, {0xa3, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5} },
+{ 0x891f, 16, {0x83, 0xe0, 0x90, 0x01, 0x2f, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0xf5, 0x82} },
+{ 0x892f, 16, {0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x90, 0x01, 0x30, 0xf0, 0x74, 0x2c, 0x2f, 0xf8} },
+{ 0x893f, 16, {0xe6, 0xa3, 0xf0, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x54} },
+{ 0x894f, 16, {0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x54, 0x5f} },
+{ 0x895f, 16, {0x90, 0x01, 0x32, 0xf0, 0x7e, 0x01, 0x7f, 0x2c, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e} },
+{ 0x896f, 11, {0x00, 0x75, 0x5d, 0x00, 0x7d, 0x07, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x897a, 1, {0x22} },
+{ 0x897b, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x898b, 16, {0xaf, 0x82, 0xfe, 0x90, 0x01, 0x33, 0x74, 0x0a, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x24} },
+{ 0x899b, 16, {0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x90, 0x01, 0x34, 0xf0, 0x7e, 0x01, 0x7f} },
+{ 0x89ab, 16, {0x33, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x02, 0x12} },
+{ 0x89bb, 4, {0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x89bf, 1, {0x22} },
+{ 0x89c0, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x89d0, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x89e0, 16, {0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x89f0, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
+{ 0x89fb, 1, {0x22} },
+{ 0x89fc, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a0c, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x8a1c, 16, {0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x8a2c, 11, {0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
+{ 0x8a37, 1, {0x22} },
+{ 0x8a38, 16, {0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a48, 16, {0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
+{ 0x8a58, 16, {0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
+{ 0x8a68, 7, {0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
+{ 0x8a6f, 1, {0x22} },
+{ 0x8a70, 4, {0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8a74, 16, {0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x58, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
+{ 0x8a84, 16, {0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
+{ 0x8a94, 16, {0x56, 0x7e, 0x75, 0x57, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x56, 0x7e, 0x75, 0x57} },
+{ 0x8aa4, 16, {0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x80, 0x80, 0x0a, 0x7e} },
+{ 0x8ab4, 16, {0x7d, 0x7f, 0x00, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x00, 0xe5, 0x58, 0x70, 0x20, 0x85, 0x57, 0x82} },
+{ 0x8ac4, 16, {0x85, 0x56, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8ad4, 16, {0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x4d, 0xe5, 0x55, 0x24} },
+{ 0x8ae4, 16, {0x02, 0xff, 0xe4, 0x35, 0x54, 0xfe, 0xe5, 0x58, 0x60, 0x23, 0x0f, 0xef, 0xac, 0x06, 0x70, 0x01} },
+{ 0x8af4, 16, {0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x57, 0xe5, 0x57, 0xaa, 0x56, 0x70, 0x02} },
+{ 0x8b04, 16, {0x05, 0x56, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x15, 0x58, 0x80, 0xd9, 0x85, 0x55, 0x82} },
+{ 0x8b14, 16, {0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8b24, 12, {0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
+{ 0x8b30, 1, {0x22} },
+{ 0x8b31, 16, {0xef, 0x24, 0x05, 0xf5, 0x55, 0xe4, 0x3e, 0xf5, 0x54, 0x90, 0x01, 0x35, 0x74, 0x07, 0xf0, 0x90} },
+{ 0x8b41, 16, {0x01, 0x7a, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x36, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8b51, 16, {0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x8e, 0x56, 0xf5, 0x57, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8b61, 16, {0xe0, 0x24, 0x9e, 0x60, 0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x12} },
+{ 0x8b71, 16, {0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x5e, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe} },
+{ 0x8b81, 16, {0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x59, 0x74, 0x01, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59} },
+{ 0x8b91, 16, {0x94, 0x40, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5} },
+{ 0x8ba1, 16, {0x57, 0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x50, 0x03, 0x02, 0x8c, 0x61, 0xae, 0x58, 0xaf, 0x59} },
+{ 0x8bb1, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e} },
+{ 0x8bc1, 16, {0x56, 0xf5, 0x57, 0x02, 0x8c, 0x61, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8bd1, 16, {0xe0, 0xff, 0xc3, 0x74, 0x30, 0x9f, 0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59, 0x94} },
+{ 0x8be1, 16, {0x10, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x10, 0xd3, 0xe5, 0x57} },
+{ 0x8bf1, 16, {0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x40, 0x68, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85} },
+{ 0x8c01, 16, {0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x80} },
+{ 0x8c11, 16, {0x4f, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f} },
+{ 0x8c21, 16, {0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0x45, 0x59, 0x60, 0x0b, 0xd3, 0xe5, 0x59, 0x94, 0x40, 0xe5} },
+{ 0x8c31, 16, {0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5, 0x57, 0x95, 0x59} },
+{ 0x8c41, 16, {0xe5, 0x56, 0x95, 0x58, 0x40, 0x17, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8c51, 16, {0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x7f, 0x01, 0x22} },
+{ 0x8c61, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8d, 0x21, 0x24, 0xf9} },
+{ 0x8c71, 16, {0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8d, 0x71, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8d, 0xb5} },
+{ 0x8c81, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
+{ 0x8c91, 16, {0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57} },
+{ 0x8ca1, 16, {0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xe0} },
+{ 0x8cb1, 16, {0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b} },
+{ 0x8cc1, 16, {0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8cd1, 16, {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8d} },
+{ 0x8ce1, 16, {0xb5, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x76} },
+{ 0x8cf1, 16, {0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02} },
+{ 0x8d01, 16, {0x8d, 0xb5, 0x90, 0x01, 0x76, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d11, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
+{ 0x8d21, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
+{ 0x8d31, 16, {0x94, 0x00, 0x50, 0x03, 0x02, 0x8d, 0xb5, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
+{ 0x8d41, 16, {0x90, 0x01, 0x77, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e} },
+{ 0x8d51, 16, {0x60, 0x62, 0x90, 0x01, 0x77, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d61, 16, {0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
+{ 0x8d71, 16, {0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x78, 0xcf, 0xf0} },
+{ 0x8d81, 16, {0xa3, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x60, 0x24} },
+{ 0x8d91, 16, {0x90, 0x01, 0x78, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
+{ 0x8da1, 16, {0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x8db1, 16, {0xef, 0xf0, 0x80, 0xcf, 0x7e, 0x01, 0x7f, 0x35, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3} },
+{ 0x8dc1, 16, {0xa3, 0xe0, 0xa3, 0xe0, 0x04, 0xfd, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75} },
+{ 0x8dd1, 7, {0x5d, 0x00, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8dd8, 1, {0x22} },
+{ 0x8dd9, 16, {0x8e, 0x61, 0x8f, 0x62, 0x8c, 0x63, 0x8d, 0x64, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x62} },
+{ 0x8de9, 16, {0xe5, 0x62, 0xae, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
+{ 0x8df9, 16, {0x64, 0xe5, 0x64, 0xac, 0x63, 0x70, 0x02, 0x05, 0x63, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x8e09, 3, {0x80, 0xd6, 0x22} },
+{ 0x8e0c, 16, {0x8d, 0x5c, 0xab, 0x07, 0xaa, 0x06, 0xaf, 0x60, 0xae, 0x5f, 0xad, 0x5e, 0xac, 0x5d, 0xec, 0x4d} },
+{ 0x8e1c, 16, {0x4e, 0x4f, 0x60, 0x1c, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x1c, 0x7f, 0xff, 0x7e, 0xff, 0x7d} },
+{ 0x8e2c, 16, {0xff, 0x7c, 0xff, 0x78, 0x5d, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0x09, 0x80, 0xe4} },
+{ 0x8e3c, 16, {0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0xf9, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x16, 0xaf, 0x03} },
+{ 0x8e4c, 16, {0xae, 0x02, 0x7c, 0x7b, 0x7d, 0x80, 0xab, 0x5c, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xc3, 0xe5, 0x5c} },
+{ 0x8e5c, 7, {0xf0, 0x7f, 0x01, 0x22, 0x7f, 0x00, 0x22} },
+{ 0x8e63, 16, {0x90, 0x01, 0x84, 0x74, 0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f} },
+{ 0x8e73, 16, {0x90, 0x01, 0x85, 0xf0, 0x90, 0x11, 0xfd, 0xe4, 0x93, 0x90, 0x01, 0x86, 0xf0, 0x90, 0x11, 0xfe} },
+{ 0x8e83, 16, {0xe4, 0x93, 0x90, 0x01, 0x87, 0xf0, 0xe4, 0x90, 0x01, 0x7c, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x8e93, 16, {0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x88, 0xf0, 0x7e} },
+{ 0x8ea3, 16, {0x01, 0x7f, 0x7c, 0x12, 0x19, 0xc1, 0x7e, 0x01, 0x7f, 0x84, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x8eb3, 13, {0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x14, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8ec0, 1, {0x22} },
+{ 0x8ec1, 4, {0x8e, 0x4b, 0x8f, 0x4c} },
+{ 0x8ec5, 16, {0x85, 0x4b, 0x4e, 0x85, 0x4c, 0x4f, 0xe5, 0x4f, 0x24, 0x01, 0xf5, 0x53, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x8ed5, 16, {0x52, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0x14, 0xb4, 0x0f, 0x00, 0x40, 0x03, 0x02, 0x8f} },
+{ 0x8ee5, 16, {0xd6, 0x90, 0x8e, 0xed, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8f, 0x1a, 0x02, 0x8f, 0x26, 0x02, 0x8f} },
+{ 0x8ef5, 16, {0x32, 0x02, 0x8f, 0x5c, 0x02, 0x8f, 0x67, 0x02, 0x8f, 0x72, 0x02, 0x8f, 0x7d, 0x02, 0x8f, 0x88} },
+{ 0x8f05, 16, {0x02, 0x8f, 0x93, 0x02, 0x8f, 0x9e, 0x02, 0x8f, 0xa9, 0x02, 0x8f, 0xb0, 0x02, 0x8f, 0xd6, 0x02} },
+{ 0x8f15, 16, {0x8f, 0xbb, 0x02, 0x8f, 0xc6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x83, 0x5f, 0x8f, 0x4d, 0x02, 0x8f} },
+{ 0x8f25, 16, {0xd6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x84, 0x33, 0x8f, 0x4d, 0x02, 0x8f, 0xd6, 0x85, 0x52, 0x50} },
+{ 0x8f35, 16, {0x85, 0x53, 0x51, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xfe, 0x12, 0x85, 0x08, 0xaf} },
+{ 0x8f45, 16, {0x51, 0xae, 0x50, 0x12, 0x85, 0x9b, 0xef, 0x70, 0x03, 0x02, 0x8f, 0xd6, 0xaf, 0x51, 0xae, 0x50} },
+{ 0x8f55, 16, {0x12, 0x85, 0xe1, 0x8f, 0x4d, 0x80, 0x7a, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xc0, 0x8f, 0x4d} },
+{ 0x8f65, 16, {0x80, 0x6f, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xfc, 0x8f, 0x4d, 0x80, 0x64, 0xaf, 0x53, 0xae} },
+{ 0x8f75, 16, {0x52, 0x12, 0x8a, 0x38, 0x8f, 0x4d, 0x80, 0x59, 0xaf, 0x4c, 0xae, 0x4b, 0x12, 0x8b, 0x31, 0x8f} },
+{ 0x8f85, 16, {0x4d, 0x80, 0x4e, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x88, 0xef, 0x8f, 0x4d, 0x80, 0x43, 0xaf, 0x53} },
+{ 0x8f95, 16, {0xae, 0x52, 0x12, 0x84, 0xc4, 0x8f, 0x4d, 0x80, 0x38, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0x7b} },
+{ 0x8fa5, 16, {0x8f, 0x4d, 0x80, 0x2d, 0x12, 0x8e, 0x63, 0x8f, 0x4d, 0x80, 0x26, 0xaf, 0x53, 0xae, 0x52, 0x12} },
+{ 0x8fb5, 16, {0x11, 0xe5, 0x8f, 0x4d, 0x80, 0x1b, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x8a, 0x70, 0x8f, 0x4d, 0x80} },
+{ 0x8fc5, 16, {0x10, 0xaf, 0x4c, 0xae, 0x4b, 0x7c, 0x02, 0x7d, 0xaf, 0x7b, 0x40, 0x12, 0x8d, 0xd9, 0xe4, 0xf5} },
+{ 0x8fd5, 16, {0x4d, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0xff, 0x14, 0x24, 0xfa, 0x50, 0x04, 0x24, 0xfe} },
+{ 0x8fe5, 16, {0x70, 0x2b, 0x90, 0x01, 0x98, 0x74, 0x10, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x8ff5, 16, {0x83, 0xe0, 0x90, 0x01, 0x9a, 0xf0, 0x7e, 0x01, 0x7f, 0x98, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x9005, 15, {0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x03, 0x12, 0x8e, 0x0c, 0x8f, 0x4d, 0xaf, 0x4d} },
+{ 0x9014, 1, {0x22} },
+{ 0x9015, 8, {0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b} },
+{ 0x901d, 16, {0x75, 0x55, 0x01, 0x75, 0x56, 0x9c, 0xe4, 0xf5, 0x54, 0xaf, 0x50, 0x15, 0x50, 0xef, 0x70, 0x03} },
+{ 0x902d, 16, {0x02, 0x90, 0xb3, 0xaf, 0x4f, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x4e} },
+{ 0x903d, 16, {0xae, 0x4d, 0xad, 0x4c, 0xac, 0x4b, 0x12, 0x9c, 0x58, 0xaf, 0x03, 0x8f, 0x53, 0xaf, 0x4e, 0xae} },
+{ 0x904d, 16, {0x4d, 0xad, 0x4c, 0xac, 0x4b, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x4f, 0xe4} },
+{ 0x905d, 16, {0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
+{ 0x906d, 16, {0x12, 0x9c, 0x58, 0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b, 0xe5, 0x53, 0x24, 0x30, 0xf5} },
+{ 0x907d, 16, {0x53, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x53, 0xf5, 0x53, 0x05, 0x56, 0xe5, 0x56} },
+{ 0x908d, 16, {0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x56, 0xe5} },
+{ 0x909d, 16, {0x56, 0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x53, 0xf0, 0x05} },
+{ 0x90ad, 16, {0x54, 0x05, 0x54, 0x02, 0x90, 0x26, 0xe5, 0x56, 0x15, 0x56, 0x70, 0x02, 0x15, 0x55, 0xaf, 0x54} },
+{ 0x90bd, 16, {0x15, 0x54, 0xef, 0x60, 0x23, 0xe5, 0x56, 0x15, 0x56, 0xae, 0x55, 0x70, 0x02, 0x15, 0x55, 0xf5} },
+{ 0x90cd, 16, {0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x52, 0xe5, 0x52, 0xac, 0x51, 0x70, 0x02, 0x05, 0x51, 0x14} },
+{ 0x90dd, 8, {0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
+{ 0x90e5, 1, {0x22} },
+{ 0x90e6, 16, {0xe4, 0x90, 0x01, 0xc9, 0xf0, 0x7e, 0x01, 0x7f, 0xca, 0x90, 0x01, 0xbe, 0xee, 0xf0, 0xa3, 0xef} },
+{ 0x90f6, 10, {0xf0, 0x90, 0x01, 0xc2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9100, 16, {0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0xc9, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
+{ 0x9110, 16, {0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
+{ 0x9120, 16, {0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0xc2, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9130, 16, {0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x9140, 16, {0xeb, 0xf0, 0x90, 0x01, 0xc2, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x9150, 16, {0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xc2, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x9160, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x9170, 1, {0x22} },
+{ 0x9171, 16, {0x90, 0x01, 0xc9, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0xbe, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9181, 16, {0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
+{ 0x9191, 16, {0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
+{ 0x91a1, 16, {0x9b, 0x49, 0x90, 0x01, 0xbe, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x91b1, 16, {0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xbe, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x91c1, 16, {0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x91d1, 1, {0x22} },
+{ 0x91d2, 16, {0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x50, 0x7b, 0x75, 0x51} },
+{ 0x91e2, 16, {0x80, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x52, 0xf5} },
+{ 0x91f2, 16, {0x53, 0x89, 0x54, 0xfe, 0x12, 0x91, 0x71, 0xef, 0x60, 0x3b, 0xab, 0x52, 0xaa, 0x53, 0xa9, 0x54} },
+{ 0x9202, 16, {0x12, 0x9b, 0x72, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
+{ 0x9212, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
+{ 0x9222, 16, {0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
+{ 0x9232, 5, {0x74, 0x04, 0xf0, 0xd2, 0xaf} },
+{ 0x9237, 1, {0x22} },
+{ 0x9238, 16, {0x12, 0x91, 0xd2, 0xe4, 0xf5, 0x4b, 0x74, 0x36, 0x25, 0x4b, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x4c} },
+{ 0x9248, 16, {0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x4c, 0xff, 0xc4} },
+{ 0x9258, 16, {0x54, 0x0f, 0xf5, 0x4d, 0x60, 0x22, 0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
+{ 0x9268, 16, {0x83, 0xe5, 0x4c, 0xf0, 0xaf, 0x4b, 0x7d, 0x01, 0xe5, 0x4c, 0x45, 0x4d, 0xfb, 0x12, 0x91, 0x00} },
+{ 0x9278, 16, {0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40} },
+{ 0x9288, 16, {0xb5, 0x12, 0x91, 0xd2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9298, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x4b} },
+{ 0x92a8, 16, {0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
+{ 0x92b8, 16, {0x16, 0xaf, 0x4b, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2} },
+{ 0x92c8, 16, {0x80, 0xef, 0xe5, 0x4c, 0xf4, 0x52, 0x3a, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
+{ 0x92d8, 16, {0x90, 0x03, 0x00, 0xe0, 0x60, 0x03, 0x02, 0x93, 0xa5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
+{ 0x92e8, 16, {0x11, 0x8e, 0x4e, 0x8f, 0x4f, 0xc3, 0xe5, 0x4e, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
+{ 0x92f8, 16, {0xbc, 0xe0, 0x65, 0x4f, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8, 0x07} },
+{ 0x9308, 16, {0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xbc, 0xe0, 0x55, 0x4c, 0x60} },
+{ 0x9318, 16, {0x14, 0xaf, 0x4b, 0x7d, 0x08, 0xe5, 0x4c, 0x55, 0x4f, 0xfb, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05} },
+{ 0x9328, 16, {0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
+{ 0x9338, 16, {0xbc, 0xe5, 0x4f, 0xf0, 0xe4, 0xf5, 0x4b, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x4b, 0xf8, 0xe6, 0xf5} },
+{ 0x9348, 16, {0x4c, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x4c, 0x1e, 0xe5, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x02} },
+{ 0x9358, 16, {0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
+{ 0x9368, 16, {0x4b, 0xf8, 0xe6, 0xf5, 0x4c, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
+{ 0x9378, 16, {0xe0, 0x65, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x04, 0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70} },
+{ 0x9388, 16, {0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
+{ 0x9398, 16, {0x83, 0xe5, 0x4c, 0xf0, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x91, 0xd2} },
+{ 0x93a8, 1, {0x22} },
+{ 0x93a9, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x64, 0x02, 0x93, 0xf0} },
+{ 0x93b5, 16, {0x02, 0x05, 0xa3, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x93c5, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x93d5, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x93e5, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x94, 0x35, 0xe4, 0x7e} },
+{ 0x93f5, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x9405, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x9415, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x9425, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x9435, 16, {0x60, 0x24, 0x02, 0x8a, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
+{ 0x9445, 16, {0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
+{ 0x9455, 8, {0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
+{ 0x945d, 1, {0x00} },
+{ 0x945e, 11, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
+{ 0x9469, 16, {0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
+{ 0x9479, 16, {0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
+{ 0x9489, 16, {0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x1e} },
+{ 0x9499, 10, {0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0xc4, 0xee, 0xf0} },
+{ 0x94a3, 9, {0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x94ac, 2, {0xa9, 0x03} },
+{ 0x94ae, 16, {0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
+{ 0x94be, 16, {0x57, 0x45, 0x58, 0xf5, 0x59, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
+{ 0x94ce, 16, {0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
+{ 0x94de, 16, {0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x59, 0xeb} },
+{ 0x94ee, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x59, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
+{ 0x94fe, 16, {0x05, 0x22, 0xe5, 0x57, 0x5c, 0xfe, 0xe5, 0x58, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
+{ 0x950e, 16, {0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
+{ 0x951e, 16, {0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x57, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x58, 0x22, 0x7f} },
+{ 0x952e, 1, {0x00} },
+{ 0x952f, 1, {0x22} },
+{ 0x9530, 16, {0x75, 0x50, 0x02, 0x75, 0x51, 0xb0, 0x90, 0x03, 0x35, 0x74, 0x0f, 0xf0, 0x85, 0x51, 0x82, 0x85} },
+{ 0x9540, 16, {0x50, 0x83, 0xe0, 0xff, 0x90, 0x03, 0x36, 0xf0, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0} },
+{ 0x9550, 16, {0x90, 0x03, 0x37, 0xf0, 0xa3, 0x74, 0xff, 0xf0, 0x75, 0x52, 0x03, 0x75, 0x53, 0x39, 0xef, 0x14} },
+{ 0x9560, 16, {0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x99, 0x98, 0x90, 0x95, 0x6f, 0xf8, 0x28, 0x28, 0x73, 0x02} },
+{ 0x9570, 16, {0x95, 0x90, 0x02, 0x96, 0x2f, 0x02, 0x97, 0x34, 0x02, 0x97, 0x54, 0x02, 0x97, 0x54, 0x02, 0x97} },
+{ 0x9580, 16, {0xef, 0x02, 0x98, 0x2a, 0x02, 0x98, 0x4f, 0x02, 0x99, 0x0d, 0x02, 0x99, 0x39, 0x02, 0x99, 0x65} },
+{ 0x9590, 16, {0xe4, 0xf5, 0x4b, 0xe5, 0x4b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x95a0, 16, {0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xe4, 0xff, 0xe4, 0xfe, 0xef, 0x60, 0x10, 0x74, 0x8a, 0x2e} },
+{ 0x95b0, 16, {0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5, 0x4c, 0x80, 0x0d, 0x74, 0x8a, 0x2e} },
+{ 0x95c0, 16, {0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x4c, 0xe5, 0x4f, 0x24, 0x07, 0xf5, 0x82} },
+{ 0x95d0, 16, {0xe4, 0x35, 0x4e, 0xf5, 0x83, 0xe5, 0x4c, 0xf0, 0xe0, 0xf5, 0x4d, 0x65, 0x4c, 0x60, 0x38, 0xe4} },
+{ 0x95e0, 16, {0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfd, 0x05, 0x53, 0xe5, 0x53, 0xaa, 0x52, 0x70, 0x02} },
+{ 0x95f0, 16, {0x05, 0x52, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70} },
+{ 0x9600, 16, {0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe5, 0x4c, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9610, 16, {0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x0e, 0xbe, 0x24, 0x8f, 0x0f, 0xef, 0x64, 0x02, 0x70} },
+{ 0x9620, 16, {0x87, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60, 0x03, 0x02, 0x95, 0x93, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9630, 16, {0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x05, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x03} },
+{ 0x9640, 16, {0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x94, 0xf0, 0xa3, 0x74, 0x5e, 0xf0, 0xe4, 0xf5, 0x4d, 0x7e} },
+{ 0x9650, 16, {0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9660, 16, {0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xc4, 0xf0, 0x90, 0x01} },
+{ 0x9670, 16, {0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0x74, 0x02} },
+{ 0x9680, 16, {0xf0, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x4c, 0x34, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0} },
+{ 0x9690, 16, {0x70, 0xef, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52} },
+{ 0x96a0, 16, {0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x96b0, 16, {0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x01, 0xc4, 0xf0, 0x75, 0x4d, 0xff, 0x90, 0x01, 0xc4, 0xe0} },
+{ 0x96c0, 16, {0xff, 0x60, 0x37, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfe, 0x05, 0x53, 0xe5, 0x53} },
+{ 0x96d0, 16, {0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x53, 0xe5} },
+{ 0x96e0, 16, {0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53} },
+{ 0x96f0, 16, {0x82, 0x85, 0x52, 0x83, 0xe5, 0x4c, 0xf0, 0x75, 0x4d, 0xff, 0xe5, 0x4d, 0x70, 0x16, 0x74, 0x08} },
+{ 0x9700, 16, {0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35, 0x4e, 0xf5, 0x4e, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60} },
+{ 0x9710, 16, {0x03, 0x02, 0x96, 0x5b, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x05, 0x4b} },
+{ 0x9720, 16, {0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12} },
+{ 0x9730, 16, {0xf0, 0x02, 0x99, 0x9e, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01} },
+{ 0x9740, 16, {0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90, 0x02, 0xf7, 0xf0, 0x90, 0x01, 0xc4} },
+{ 0x9750, 16, {0xf0, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0, 0x74, 0x03, 0xf0, 0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5} },
+{ 0x9760, 16, {0x4d, 0x90, 0x02, 0xf7, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x07, 0x19, 0x90, 0x01, 0xc0} },
+{ 0x9770, 16, {0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x90, 0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9780, 16, {0x83, 0x74, 0xff, 0xf0, 0xf5, 0x4d, 0xe5, 0x4d, 0x60, 0x03, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0} },
+{ 0x9790, 16, {0xf0, 0xa3, 0x74, 0x96, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f} },
+{ 0x97a0, 16, {0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5} },
+{ 0x97b0, 16, {0x4d, 0x90, 0x02, 0xf7, 0xe0, 0x55, 0x4d, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f} },
+{ 0x97c0, 16, {0x4c, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x4c, 0x70, 0x04, 0x7f} },
+{ 0x97d0, 16, {0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x4c, 0xe5, 0x4c, 0x70, 0x03, 0x02, 0x99, 0x9e, 0xe4, 0x90} },
+{ 0x97e0, 16, {0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x97f0, 16, {0xff, 0xfd, 0x12, 0x82, 0x50, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0x85} },
+{ 0x9800, 16, {0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x4f, 0x82, 0x85} },
+{ 0x9810, 16, {0x4e, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3} },
+{ 0x9820, 16, {0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x99, 0x9e, 0xc2, 0x04, 0x7e, 0x20, 0x7f, 0x00} },
+{ 0x9830, 16, {0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xe5, 0x4f, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x9840, 16, {0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xe4, 0xff, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9850, 16, {0xf5, 0x4d, 0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0xe5, 0x4b, 0x75, 0xf0, 0x08} },
+{ 0x9860, 16, {0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xf5, 0x83} },
+{ 0x9870, 16, {0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x9880, 16, {0x4b, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x57, 0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d} },
+{ 0x9890, 16, {0xe5, 0x4d, 0x70, 0x11, 0xaf, 0x4b, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20} },
+{ 0x98a0, 16, {0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d, 0x01, 0xfb, 0x75, 0x57} },
+{ 0x98b0, 16, {0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d} },
+{ 0x98c0, 16, {0x02, 0xfb, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xaf, 0x4b, 0x7d} },
+{ 0x98d0, 16, {0x01, 0x12, 0x82, 0x50, 0xe5, 0x4d, 0x60, 0x26, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04} },
+{ 0x98e0, 16, {0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x98f0, 16, {0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x05, 0x4b} },
+{ 0x9900, 16, {0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x50, 0x03, 0x02, 0x98, 0x54, 0x02, 0x99, 0x9e, 0xe4, 0x90, 0x03} },
+{ 0x9910, 16, {0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74} },
+{ 0x9920, 16, {0x1b, 0xf0, 0xa3, 0x74, 0x29, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08} },
+{ 0x9930, 16, {0x60, 0x6c, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x65, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0} },
+{ 0x9940, 16, {0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x52, 0xf0, 0xa3, 0xe5} },
+{ 0x9950, 16, {0x53, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x40, 0xe4, 0x90} },
+{ 0x9960, 16, {0x03, 0x38, 0xf0, 0x80, 0x39, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0} },
+{ 0x9970, 16, {0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x51, 0x24, 0x02, 0x90, 0x03, 0x60, 0xf0, 0xe4, 0x35} },
+{ 0x9980, 16, {0x50, 0x90, 0x03, 0x5f, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x60} },
+{ 0x9990, 16, {0x0d, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x06, 0x90, 0x03, 0x38, 0x74, 0x01, 0xf0, 0x90, 0x01} },
+{ 0x99a0, 16, {0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
+{ 0x99b0, 16, {0xf6, 0x7e, 0x03, 0x7f, 0x35, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d} },
+{ 0x99c0, 11, {0x00, 0x7d, 0x24, 0x12, 0x8e, 0x0c, 0xe4, 0x90, 0x02, 0xaf, 0xf0} },
+{ 0x99cb, 1, {0x22} },
+{ 0x99cc, 16, {0xe4, 0xff, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02} },
+{ 0x99dc, 16, {0x9a, 0x6f, 0x74, 0x36, 0x2f, 0xf8, 0xe6, 0x20, 0xe5, 0x03, 0x02, 0x9a, 0x6f, 0xef, 0x75, 0xf0} },
+{ 0x99ec, 16, {0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xad, 0x82, 0xfc, 0xf5, 0x83, 0xe5, 0x82} },
+{ 0x99fc, 16, {0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x70, 0x63} },
+{ 0x9a0c, 16, {0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01} },
+{ 0x9a1c, 16, {0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x74, 0xf8} },
+{ 0x9a2c, 16, {0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0, 0x70, 0x36, 0xef, 0x25, 0xe0} },
+{ 0x9a3c, 16, {0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xef, 0x25, 0xe0, 0xfe, 0xc3} },
+{ 0x9a4c, 16, {0x74, 0x0c, 0x9e, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xad} },
+{ 0x9a5c, 16, {0x82, 0xfc, 0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xec, 0xf0} },
+{ 0x9a6c, 12, {0xa3, 0xed, 0xf0, 0x0f, 0xef, 0x64, 0x04, 0x60, 0x03, 0x02, 0x99, 0xce} },
+{ 0x9a78, 1, {0x22} },
+{ 0x9a79, 16, {0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
+{ 0x9a89, 16, {0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
+{ 0x9a99, 16, {0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
+{ 0x9aa9, 16, {0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
+{ 0x9ab9, 16, {0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
+{ 0x9ac9, 16, {0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
+{ 0x9ad9, 16, {0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
+{ 0x9ae9, 16, {0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
+{ 0x9af9, 16, {0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
+{ 0x9b09, 16, {0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
+{ 0x9b19, 16, {0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
+{ 0x9b29, 16, {0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
+{ 0x9b39, 16, {0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
+{ 0x9b49, 16, {0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
+{ 0x9b59, 16, {0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
+{ 0x9b69, 9, {0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x9a, 0xc9, 0x73} },
+{ 0x9b72, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x9b82, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9b8b, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x9b9b, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x9bab, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9bb8, 16, {0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
+{ 0x9bc8, 6, {0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
+{ 0x9bce, 16, {0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
+{ 0x9bde, 6, {0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
+{ 0x9be4, 16, {0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x9bf4, 16, {0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x9c04, 16, {0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x9c14, 8, {0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x9c1c, 16, {0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
+{ 0x9c2c, 16, {0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
+{ 0x9c3c, 16, {0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
+{ 0x9c4c, 16, {0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
+{ 0x9c5c, 16, {0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
+{ 0x9c6c, 16, {0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
+{ 0x9c7c, 16, {0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
+{ 0x9c8c, 16, {0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
+{ 0x9c9c, 16, {0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
+{ 0x9cac, 16, {0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
+{ 0x9cbc, 16, {0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
+{ 0x9ccc, 16, {0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
+{ 0x9cdc, 14, {0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
+{ 0x9cea, 16, {0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x9cfa, 1, {0x22} },
+{ 0x9cfb, 16, {0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
+{ 0x9d0b, 3, {0xd8, 0xf1, 0x22} },
+{ 0x9d0e, 16, {0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
+{ 0x9d1e, 7, {0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
+{ 0x9d25, 12, {0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9d31, 16, {0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9d, 0x48, 0x12, 0x9d, 0x48, 0x12} },
+{ 0x9d41, 16, {0x9d, 0x48, 0x12, 0x9d, 0x48, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
+{ 0x9d51, 16, {0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
+{ 0x9d61, 1, {0x22} },
{ 0xffff, 0, {0x00} }
};
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 9927b5382..2fa4e30b6 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -56,11 +56,11 @@ static kmem_cache_t *uhci_up_cachep; /* urb_priv */
static LIST_HEAD(uhci_list);
-static int rh_submit_urb(urb_t *urb);
-static int rh_unlink_urb(urb_t *urb);
+static int rh_submit_urb(struct urb *urb);
+static int rh_unlink_urb(struct urb *urb);
static int uhci_get_current_frame_number(struct usb_device *dev);
-static int uhci_unlink_generic(urb_t *urb);
-static int uhci_unlink_urb(urb_t *urb);
+static int uhci_unlink_generic(struct urb *urb);
+static int uhci_unlink_urb(struct urb *urb);
#define min(a,b) (((a)<(b))?(a):(b))
@@ -77,9 +77,8 @@ static int uhci_alloc_dev(struct usb_device *dev)
static int uhci_free_dev(struct usb_device *dev)
{
- urb_t *u;
struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
- struct list_head *tmp, *next, *head = &uhci->urb_list;
+ struct list_head *tmp, *head = &uhci->urb_list;
unsigned long flags;
/* Walk through the entire URB list and forcefully remove any */
@@ -87,14 +86,12 @@ static int uhci_free_dev(struct usb_device *dev)
nested_lock(&uhci->urblist_lock, flags);
tmp = head->next;
while (tmp != head) {
- u = list_entry(tmp, urb_t, urb_list);
+ struct urb *u = list_entry(tmp, struct urb, urb_list);
- next = tmp->next;
+ tmp = tmp->next;
if (u->dev == dev)
uhci_unlink_urb(u);
-
- tmp = next;
}
nested_unlock(&uhci->urblist_lock, flags);
@@ -115,13 +112,31 @@ static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
unsigned long flags;
nested_lock(&uhci->urblist_lock, flags);
- if (urb->urb_list.next != &urb->urb_list) {
+ if (!list_empty(&urb->urb_list)) {
list_del(&urb->urb_list);
INIT_LIST_HEAD(&urb->urb_list);
}
nested_unlock(&uhci->urblist_lock, flags);
}
+void uhci_set_next_interrupt(struct uhci *uhci)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+ uhci->skel_term_td.status |= TD_CTRL_IOC;
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+void uhci_clear_next_interrupt(struct uhci *uhci)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+ uhci->skel_term_td.status &= ~TD_CTRL_IOC;
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
{
struct uhci_td *td;
@@ -135,8 +150,8 @@ static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
td->frameptr = NULL;
td->nexttd = td->prevtd = NULL;
- td->list.next = td->list.prev = NULL;
td->dev = dev;
+ INIT_LIST_HEAD(&td->list);
usb_inc_dev_use(dev);
@@ -235,23 +250,32 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
*/
static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_td *td, *prevtd;
if (!urbp)
return;
- td = urbp->list.begin;
- if (!td)
+ head = &urbp->list;
+ tmp = head->next;
+ if (head == tmp)
return;
+ td = list_entry(tmp, struct uhci_td, list);
+
/* Add the first TD to the QH element pointer */
qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
prevtd = td;
/* Then link the rest of the TD's */
- for (td = td->list.next; td; td = td->list.next) {
+ tmp = tmp->next;
+ while (tmp != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
prevtd = td;
@@ -260,9 +284,45 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int bread
prevtd->link = UHCI_PTR_TERM;
}
+/* This function will append one URB's QH to another URB's QH. This is for */
+/* USB_QUEUE_BULK support */
+static void uhci_append_urb_qh(struct uhci *uhci, struct urb *eurb, struct urb *urb)
+{
+ struct urb *nurb;
+ struct urb_priv *eurbp, *urbp, *nurbp;
+ struct list_head *tmp;
+ struct uhci_td *td, *ntd;
+ unsigned long flags;
+
+ eurbp = eurb->hcpriv;
+ urbp = urb->hcpriv;
+
+ spin_lock_irqsave(&eurb->lock, flags);
+
+ /* Grab the last URB in the queue */
+ tmp = eurbp->urb_queue_list.prev;
+
+ /* Add this one to the end */
+ list_add_tail(&urbp->urb_queue_list, &eurbp->urb_queue_list);
+
+ spin_unlock_irqrestore(&eurb->lock, flags);
+
+ nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+ nurb = nurbp->urb;
+
+ tmp = nurbp->list.prev;
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = urbp->list.next;
+ ntd = list_entry(tmp, struct uhci_td, list);
+
+ /* No breadth since this will only be called for bulk transfers */
+ td->link = virt_to_bus(ntd);
+}
+
static void uhci_free_td(struct uhci_td *td)
{
- if (td->list.next || td->list.prev)
+ if (!list_empty(&td->list))
dbg("td is still in URB list!");
kmem_cache_free(uhci_td_cachep, td);
@@ -322,6 +382,10 @@ static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhc
static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
{
unsigned long flags;
+ int delayed;
+
+ /* If the QH isn't queued, then we don't need to delay unlink it */
+ delayed = (qh->prevqh || qh->nextqh);
spin_lock_irqsave(&uhci->framelist_lock, flags);
if (qh->prevqh) {
@@ -333,9 +397,20 @@ static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
qh->prevqh = qh->nextqh = NULL;
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
- spin_lock_irqsave(&uhci->qh_remove_lock, flags);
- list_add(&qh->remove_list, &uhci->qh_remove_list);
- spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+ if (delayed) {
+ spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+
+ /* Check to see if the remove list is empty */
+ /* Set the IOC bit to force an interrupt so we can remove the QH */
+ if (list_empty(&uhci->qh_remove_list))
+ uhci_set_next_interrupt(uhci);
+
+ /* Add it */
+ list_add(&qh->remove_list, &uhci->qh_remove_list);
+
+ spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+ } else
+ uhci_free_qh(qh);
}
struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
@@ -348,91 +423,86 @@ struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
memset((void *)urbp, 0, sizeof(*urbp));
- urbp->list.begin = urbp->list.end = NULL;
+ urbp->inserttime = jiffies;
+ urbp->urb = urb;
+
+ INIT_LIST_HEAD(&urbp->list);
+ INIT_LIST_HEAD(&urbp->urb_queue_list);
urb->hcpriv = urbp;
- urbp->inserttime = jiffies;
-
usb_inc_dev_use(urb->dev);
return urbp;
}
-static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
td->urb = urb;
- if (!urbp->list.begin)
- urbp->list.begin = td;
-
- if (urbp->list.end) {
- urbp->list.end->list.next = td;
- td->list.prev = urbp->list.end;
- }
- urbp->list.end = td;
+ list_add_tail(&td->list, &urbp->list);
}
-static void uhci_remove_td_from_urb(urb_t *urb, struct uhci_td *td)
+static void uhci_remove_td_from_urb(struct urb *urb, struct uhci_td *td)
{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ urb = NULL; /* No warnings */
- if (!urbp->list.begin && !urbp->list.end)
+ if (list_empty(&td->list))
return;
- if (td->list.prev)
- td->list.prev->list.next = td->list.next;
- else
- urbp->list.begin = td->list.next;
-
- if (td->list.next)
- td->list.next->list.prev = td->list.prev;
- else
- urbp->list.end = td->list.prev;
+ list_del(&td->list);
+ INIT_LIST_HEAD(&td->list);
- td->list.next = td->list.prev = NULL;
td->urb = NULL;
}
-static void uhci_destroy_urb_priv(urb_t *urb)
+static void uhci_destroy_urb_priv(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp;
struct uhci *uhci;
- struct uhci_td *td, *nexttd;
+ struct uhci_td *td;
unsigned long flags;
spin_lock_irqsave(&urb->lock, flags);
urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp)
- return;
+ goto unlock;
if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
- return;
+ goto unlock;
uhci = urb->dev->bus->hcpriv;
- td = urbp->list.begin;
- while (td) {
- nexttd = td->list.next;
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
uhci_remove_td_from_urb(urb, td);
uhci_remove_td(uhci, td);
uhci_free_td(td);
-
- td = nexttd;
+ }
+
+ if (!list_empty(&urbp->urb_queue_list)) {
+ list_del(&urbp->urb_queue_list);
+ INIT_LIST_HEAD(&urbp->urb_queue_list);
}
urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp);
- spin_unlock_irqrestore(&urb->lock, flags);
-
usb_dec_dev_use(urb->dev);
+
+unlock:
+ spin_unlock_irqrestore(&urb->lock, flags);
}
static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
@@ -448,7 +518,7 @@ static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
if (!urbp->fsbr) {
urbp->fsbr = 1;
if (!uhci->fsbr++)
- uhci->skel_term_td.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+ uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
}
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
@@ -467,7 +537,7 @@ static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
if (urbp->fsbr) {
urbp->fsbr = 0;
if (!--uhci->fsbr)
- uhci->skel_term_td.link = UHCI_PTR_TERM;
+ uhci->skel_term_qh.link = UHCI_PTR_TERM;
}
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
@@ -508,7 +578,7 @@ static int uhci_map_status(int status, int dir_out)
/*
* Control transfers
*/
-static int uhci_submit_control(urb_t *urb)
+static int uhci_submit_control(struct urb *urb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -602,10 +672,12 @@ static int uhci_submit_control(urb_t *urb)
if (urb->pipe & TD_CTRL_LS) {
uhci_insert_tds_in_qh(qh, urb, 0);
uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
+ urbp->queued = 0;
} else {
uhci_insert_tds_in_qh(qh, urb, 1);
uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
uhci_inc_fsbr(uhci, urb);
+ urbp->queued = 0;
}
urbp->qh = qh;
@@ -617,10 +689,11 @@ static int uhci_submit_control(urb_t *urb)
return -EINPROGRESS;
}
-static int usb_control_retrigger_status(urb_t *urb);
+static int usb_control_retrigger_status(struct urb *urb);
-static int uhci_result_control(urb_t *urb)
+static int uhci_result_control(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td;
unsigned int status;
@@ -628,13 +701,16 @@ static int uhci_result_control(urb_t *urb)
if (!urbp)
return -EINVAL;
- td = urbp->list.begin;
- if (!td)
+ head = &urbp->list;
+ tmp = head->next;
+ if (head == tmp)
return -EINVAL;
if (urbp->short_control_packet)
goto status_phase;
+ td = list_entry(tmp, struct uhci_td, list);
+
/* The first TD is the SETUP phase, check the status, but skip */
/* the count */
status = uhci_status_bits(td->status);
@@ -646,10 +722,13 @@ static int uhci_result_control(urb_t *urb)
urb->actual_length = 0;
- td = td->list.next;
-
/* The rest of the TD's (but the last) are data */
- while (td && td->list.next) {
+ tmp = tmp->next;
+ while (tmp != head && tmp->next != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -664,18 +743,18 @@ static int uhci_result_control(urb_t *urb)
if (status)
goto td_error;
-
- td = td->list.next;
}
status_phase:
+ td = list_entry(tmp, struct uhci_td, list);
+
/* Control status phase */
status = uhci_status_bits(td->status);
/* APC BackUPS Pro kludge */
/* It tries to send all of the descriptor instead of the amount */
/* we requested */
- if (td->status & TD_CTRL_IOC &&
+ if (td->status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */
status & TD_CTRL_ACTIVE &&
status & TD_CTRL_NAK)
return 0;
@@ -704,34 +783,37 @@ td_error:
return uhci_map_status(status, uhci_packetout(td->info));
}
-static int usb_control_retrigger_status(urb_t *urb)
+static int usb_control_retrigger_status(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci *uhci = urb->dev->bus->hcpriv;
- struct uhci_td *td, *nexttd;
urbp->short_control_packet = 1;
+ /* Create a new QH to avoid pointer overwriting problems */
+ uhci_remove_qh(uhci, urbp->qh);
+
/* Delete all of the TD's except for the status TD at the end */
- td = urbp->list.begin;
- while (td && td->list.next) {
- nexttd = td->list.next;
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head && tmp->next != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
uhci_remove_td_from_urb(urb, td);
uhci_remove_td(uhci, td);
uhci_free_td(td);
-
- td = nexttd;
}
- /* Create a new QH to avoid pointer overwriting problems */
- uhci_remove_qh(uhci, urbp->qh);
-
urbp->qh = uhci_alloc_qh(urb->dev);
- if (!urbp->qh)
+ if (!urbp->qh) {
+ err("unable to allocate new QH for control retrigger");
return -ENOMEM;
+ }
/* One TD, who cares about Breadth first? */
uhci_insert_tds_in_qh(urbp->qh, urb, 0);
@@ -741,6 +823,7 @@ static int usb_control_retrigger_status(urb_t *urb)
uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh);
else
uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh);
+ urbp->queued = 0;
return -EINPROGRESS;
}
@@ -748,7 +831,7 @@ static int usb_control_retrigger_status(urb_t *urb)
/*
* Interrupt transfers
*/
-static int uhci_submit_interrupt(urb_t *urb)
+static int uhci_submit_interrupt(struct urb *urb)
{
struct uhci_td *td;
unsigned long destination, status;
@@ -782,18 +865,25 @@ static int uhci_submit_interrupt(urb_t *urb)
return -EINPROGRESS;
}
-static int uhci_result_interrupt(urb_t *urb)
+static int uhci_result_interrupt(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = urb->hcpriv;
- struct uhci_td *td;
unsigned int status;
+ struct uhci_td *td;
if (!urbp)
return -EINVAL;
urb->actual_length = 0;
- for (td = urbp->list.begin; td; td = td->list.next) {
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -836,15 +926,17 @@ td_error:
return uhci_map_status(status, uhci_packetout(td->info));
}
-static void uhci_reset_interrupt(urb_t *urb)
+static void uhci_reset_interrupt(struct urb *urb)
{
+ struct list_head *tmp;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_td *td;
if (!urbp)
return;
- td = urbp->list.begin;
+ tmp = urbp->list.next;
+ td = list_entry(tmp, struct uhci_td, list);
if (!td)
return;
@@ -859,7 +951,7 @@ static void uhci_reset_interrupt(urb_t *urb)
/*
* Bulk transfers
*/
-static int uhci_submit_bulk(urb_t *urb)
+static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
{
struct uhci_td *td;
struct uhci_qh *qh;
@@ -881,14 +973,14 @@ static int uhci_submit_bulk(urb_t *urb)
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
/* 3 errors */
- status = TD_CTRL_ACTIVE | (3 << 27);
+ status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
if (!(urb->transfer_flags & USB_DISABLE_SPD))
status |= TD_CTRL_SPD;
/*
* Build the DATA TD's
*/
- while (len > 0) {
+ do { /* Allow zero length packets */
int pktsze = len;
if (pktsze > maxsze)
@@ -912,16 +1004,24 @@ static int uhci_submit_bulk(urb_t *urb)
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
- }
+ } while (len > 0);
qh = uhci_alloc_qh(urb->dev);
if (!qh)
return -ENOMEM;
+ urbp->qh = qh;
+
+ /* Always assume depth first */
uhci_insert_tds_in_qh(qh, urb, 1);
- uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
- urbp->qh = qh;
+ if (urb->transfer_flags & USB_QUEUE_BULK && eurb) {
+ uhci_append_urb_qh(uhci, eurb, urb);
+ urbp->queued = 1;
+ } else {
+ uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
+ urbp->queued = 0;
+ }
uhci_add_urb_list(uhci, urb);
@@ -936,9 +1036,9 @@ static int uhci_submit_bulk(urb_t *urb)
/*
* Isochronous transfers
*/
-static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int *end)
+static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
{
- urb_t *u, *last_urb = NULL;
+ struct urb *last_urb = NULL;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
struct list_head *tmp, *head = &uhci->urb_list;
int ret = 0;
@@ -947,7 +1047,7 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
nested_lock(&uhci->urblist_lock, flags);
tmp = head->next;
while (tmp != head) {
- u = list_entry(tmp, urb_t, urb_list);
+ struct urb *u = list_entry(tmp, struct urb, urb_list);
/* look for pending URB's with identical pipe handle */
if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
@@ -970,7 +1070,7 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
return ret;
}
-static int isochronous_find_start(urb_t *urb)
+static int isochronous_find_start(struct urb *urb)
{
int limits;
unsigned int start = 0, end = 0;
@@ -996,7 +1096,7 @@ static int isochronous_find_start(urb_t *urb)
return 0;
}
-static int uhci_submit_isochronous(urb_t *urb)
+static int uhci_submit_isochronous(struct urb *urb)
{
struct uhci_td *td;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1034,10 +1134,10 @@ static int uhci_submit_isochronous(urb_t *urb)
return -EINPROGRESS;
}
-static int uhci_result_isochronous(urb_t *urb)
+static int uhci_result_isochronous(struct urb *urb)
{
+ struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
int status;
int i, ret = 0;
@@ -1046,9 +1146,15 @@ static int uhci_result_isochronous(urb_t *urb)
urb->actual_length = 0;
- for (i = 0, td = urbp->list.begin; td; i++, td = td->list.next) {
+ i = 0;
+ head = &urbp->list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
int actlength;
+ tmp = tmp->next;
+
if (td->status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -1062,16 +1168,47 @@ static int uhci_result_isochronous(urb_t *urb)
urb->error_count++;
ret = status;
}
+
+ i++;
}
return ret;
}
-static int uhci_submit_urb(urb_t *urb)
+static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
+{
+ struct list_head *tmp, *head = &uhci->urb_list;
+ unsigned long flags;
+ struct urb *u = NULL;
+
+ if (usb_pipeisoc(urb->pipe))
+ return NULL;
+
+ nested_lock(&uhci->urblist_lock, flags);
+ tmp = head->next;
+ while (tmp != head) {
+ u = list_entry(tmp, struct urb, urb_list);
+
+ tmp = tmp->next;
+
+ if (u->dev == urb->dev &&
+ u->pipe == urb->pipe)
+ goto found;
+ }
+ u = NULL;
+
+found:
+ nested_unlock(&uhci->urblist_lock, flags);
+
+ return u;
+}
+
+static int uhci_submit_urb(struct urb *urb)
{
int ret = -EINVAL;
struct uhci *uhci;
unsigned long flags;
+ struct urb *u;
if (!urb)
return -EINVAL;
@@ -1085,6 +1222,10 @@ static int uhci_submit_urb(urb_t *urb)
if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
return rh_submit_urb(urb);
+ u = uhci_find_urb_ep(uhci, urb);
+ if (u && !(urb->transfer_flags & USB_QUEUE_BULK))
+ return -ENXIO;
+
spin_lock_irqsave(&urb->lock, flags);
if (!uhci_alloc_urb_priv(urb)) {
@@ -1100,7 +1241,7 @@ static int uhci_submit_urb(urb_t *urb)
ret = uhci_submit_interrupt(urb);
break;
case PIPE_BULK:
- ret = uhci_submit_bulk(urb);
+ ret = uhci_submit_bulk(urb, u);
break;
case PIPE_ISOCHRONOUS:
ret = uhci_submit_isochronous(urb);
@@ -1124,9 +1265,9 @@ static int uhci_submit_urb(urb_t *urb)
*
* Must be called with urblist_lock acquired
*/
-static void uhci_transfer_result(urb_t *urb)
+static void uhci_transfer_result(struct urb *urb)
{
- urb_t *turb;
+ struct urb *turb;
int proceed = 0, is_ring = 0;
int ret = -EINVAL;
unsigned long flags;
@@ -1206,7 +1347,7 @@ static void uhci_transfer_result(urb_t *urb)
}
}
-static int uhci_unlink_generic(urb_t *urb)
+static int uhci_unlink_generic(struct urb *urb)
{
struct urb_priv *urbp = urb->hcpriv;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1222,12 +1363,21 @@ static int uhci_unlink_generic(urb_t *urb)
/* The interrupt loop will reclaim the QH's */
uhci_remove_qh(uhci, urbp->qh);
+ if (!list_empty(&urbp->urb_queue_list)) {
+ struct list_head *tmp = urbp->urb_queue_list.next;
+ struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+ if (nurbp->queued) {
+ uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
+ nurbp->queued = 0;
+ }
+ }
+
uhci_destroy_urb_priv(urb);
return 0;
}
-static int uhci_unlink_urb(urb_t *urb)
+static int uhci_unlink_urb(struct urb *urb)
{
struct uhci *uhci;
int ret = 0;
@@ -1252,7 +1402,13 @@ static int uhci_unlink_urb(urb_t *urb)
urb->status = -ECONNABORTED;
spin_lock_irqsave(&uhci->urb_remove_lock, flags);
+
+ /* Check to see if the remove list is empty */
+ if (list_empty(&uhci->urb_remove_list))
+ uhci_set_next_interrupt(uhci);
+
list_add(&urb->urb_list, &uhci->urb_remove_list);
+
spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
} else {
urb->status = -ENOENT;
@@ -1372,7 +1528,7 @@ static __u8 root_hub_hub_des[] =
/*-------------------------------------------------------------------------*/
/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-static int rh_send_irq(urb_t *urb)
+static int rh_send_irq(struct urb *urb)
{
int i, len = 1;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1399,11 +1555,11 @@ static int rh_send_irq(urb_t *urb)
/*-------------------------------------------------------------------------*/
/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-static int rh_init_int_timer(urb_t *urb);
+static int rh_init_int_timer(struct urb *urb);
static void rh_int_timer_do(unsigned long ptr)
{
- urb_t *urb = (urb_t *)ptr, *u;
+ struct urb *urb = (struct urb *)ptr;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
struct list_head *tmp, *head = &uhci->urb_list;
struct urb_priv *urbp;
@@ -1422,15 +1578,22 @@ static void rh_int_timer_do(unsigned long ptr)
nested_lock(&uhci->urblist_lock, flags);
tmp = head->next;
while (tmp != head) {
- u = list_entry(tmp, urb_t, urb_list);
+ struct urb *u = list_entry(tmp, urb_t, urb_list);
+
+ tmp = tmp->next;
urbp = (struct urb_priv *)u->hcpriv;
if (urbp) {
- if (urbp->fsbr && time_after(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+ /* Check if the FSBR timed out */
+ if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
uhci_dec_fsbr(uhci, u);
- }
- tmp = tmp->next;
+ /* Check if the URB timed out */
+ if (u->timeout && time_after(u->timeout, jiffies)) {
+ u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+ uhci_unlink_urb(u);
+ }
+ }
}
nested_unlock(&uhci->urblist_lock, flags);
@@ -1439,7 +1602,7 @@ static void rh_int_timer_do(unsigned long ptr)
/*-------------------------------------------------------------------------*/
/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer(urb_t *urb)
+static int rh_init_int_timer(struct urb *urb)
{
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1472,7 +1635,7 @@ static int rh_init_int_timer(urb_t *urb)
** Root Hub Control Pipe
*************************/
-static int rh_submit_urb(urb_t *urb)
+static int rh_submit_urb(struct urb *urb)
{
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
unsigned int pipe = urb->pipe;
@@ -1588,7 +1751,7 @@ static int rh_submit_urb(urb_t *urb)
OK(0);
case RH_PORT_RESET:
SET_RH_PORTSTAT(USBPORTSC_PR);
- wait_ms(10);
+ wait_ms(50); /* USB v1.1 7.1.7.3 */
uhci->rh.c_p_r[wIndex - 1] = 1;
CLR_RH_PORTSTAT(USBPORTSC_PR);
udelay(10);
@@ -1636,6 +1799,11 @@ static int rh_submit_urb(urb_t *urb)
OK(1);
case RH_SET_CONFIGURATION:
OK(0);
+ case RH_GET_INTERFACE | RH_INTERFACE:
+ *(__u8 *)data = 0x00;
+ OK(1);
+ case RH_SET_INTERFACE | RH_INTERFACE:
+ OK(0);
default:
stat = -EPIPE;
}
@@ -1649,7 +1817,7 @@ static int rh_submit_urb(urb_t *urb)
}
/*-------------------------------------------------------------------------*/
-static int rh_unlink_urb(urb_t *urb)
+static int rh_unlink_urb(struct urb *urb)
{
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
@@ -1728,6 +1896,8 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
}
spin_unlock(&uhci->urb_remove_lock);
+ uhci_clear_next_interrupt(uhci);
+
/* Walk the list of pending TD's to see which ones completed */
nested_lock(&uhci->urblist_lock, flags);
head = &uhci->urb_list;
@@ -2137,7 +2307,7 @@ int uhci_init(void)
/* We only want to return an error code if ther was an error */
/* and we didn't find a UHCI controller */
- if (retval && uhci_list.next == &uhci_list)
+ if (retval && list_empty(&uhci_list))
goto init_failed;
return 0;
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
index 9f4c45e96..83992bb6a 100644
--- a/drivers/usb/uhci.h
+++ b/drivers/usb/uhci.h
@@ -97,6 +97,10 @@ struct s_nested_lock {
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
+struct uhci_framelist {
+ __u32 frame[UHCI_NUMFRAMES];
+} __attribute__((aligned(4096)));
+
struct uhci_td;
struct uhci_qh {
@@ -106,22 +110,19 @@ struct uhci_qh {
/* Software fields */
/* Can't use list_head since we want a specific order */
- struct uhci_qh *prevqh, *nextqh;
-
struct usb_device *dev; /* The owning device */
+ struct uhci_qh *prevqh, *nextqh;
+
struct list_head remove_list;
} __attribute__((aligned(16)));
-struct uhci_framelist {
- __u32 frame[UHCI_NUMFRAMES];
-} __attribute__((aligned(4096)));
-
/*
* for TD <status>:
*/
#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT 27
#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
@@ -184,10 +185,8 @@ struct uhci_td {
struct usb_device *dev;
struct urb *urb; /* URB this TD belongs to */
- /* We can't use list_head since we need a specific order */
- struct ut_list {
- struct uhci_td *prev, *next;
- } list;
+
+ struct list_head list;
} __attribute__((aligned(16)));
/*
@@ -336,9 +335,12 @@ struct uhci {
};
struct urb_priv {
+ struct urb *urb;
+
struct uhci_qh *qh; /* QH for this URB */
- int fsbr; /* Did this URB turn on FSBR? */
+ int fsbr : 1; /* Did this URB turn on FSBR? */
+ int queued : 1; /* 0 if QH was linked in */
char short_control_packet; /* If we get a short packet during */
/* a control transfer, retrigger */
@@ -346,15 +348,16 @@ struct urb_priv {
unsigned long inserttime; /* In jiffies */
- struct up_list {
- struct uhci_td *begin, *end;
- } list;
+ struct list_head list;
+
+ struct list_head urb_queue_list; /* URB's linked together */
};
/* -------------------------------------------------------------------------
Virtual Root HUB
------------------------------------------------------------------------- */
/* destination of request */
+#define RH_DEVICE 0x00
#define RH_INTERFACE 0x01
#define RH_ENDPOINT 0x02
#define RH_OTHER 0x03
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index cb6a70621..f42b96f61 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -29,10 +29,10 @@ void usb_major_cleanup(void);
*/
int usb_audio_init(void);
-int usb_cpia_init(void);
int usb_ibmcam_init(void);
int dabusb_init(void);
int plusb_init(void);
+int dsbr100_init(void);
/*
* HCI drivers
@@ -71,9 +71,6 @@ int usb_init(void)
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
-#ifdef CONFIG_USB_CPIA
- usb_cpia_init();
-#endif
#ifdef CONFIG_USB_IBMCAM
usb_ibmcam_init();
#endif
diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c
index bc04d1fca..e8da9e376 100644
--- a/drivers/usb/usb-debug.c
+++ b/drivers/usb/usb-debug.c
@@ -4,11 +4,16 @@
* I just want these out of the way where they aren't in your
* face, but so that you can still use them..
*/
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index b134107da..7c4a72c6d 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -49,7 +49,7 @@
#include <asm/system.h>
#include <asm/unaligned.h>
-#define OHCI_USE_NPS
+#define OHCI_USE_NPS // force NoPowerSwitching mode
#include "usb-ohci.h"
@@ -61,6 +61,12 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
#include <linux/pmu.h>
#endif
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) \
+ | OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
static DECLARE_WAIT_QUEUE_HEAD (op_wakeup);
static LIST_HEAD (ohci_hcd_list);
static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
@@ -143,16 +149,18 @@ static void urb_print (urb_t * urb, char * str, int small)
printk ("%s stat:%d\n", i < len? "...": "", urb->status);
}
}
-
}
-/* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
void ep_print_int_eds (ohci_t * ohci, char * str) {
int i, j;
__u32 * ed_p;
for (i= 0; i < 32; i++) {
j = 5;
- printk (KERN_DEBUG __FILE__ " %s branch int %2d(%2x):", str, i, i);
ed_p = &(ohci->hcca.int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
while (*ed_p != 0 && j--) {
ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
printk (" ed: %4x;", ed->hwINFO);
@@ -161,7 +169,161 @@ void ep_print_int_eds (ohci_t * ohci, char * str) {
printk ("\n");
}
}
-
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ if (value)
+ dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (&regs->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (&regs->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (&regs->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+ // intrdisable always same as intrenable
+ // ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp, ndp, i;
+
+ temp = readl (&regs->roothub.a);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = readl (&regs->roothub.b);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = readl (&regs->roothub.status);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = readl (&regs->roothub.portstatus [i]);
+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+ dbg ("OHCI controller %p state", controller->regs);
+
+ // dumps some of the state we know about
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca.frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
#endif
@@ -365,12 +527,12 @@ static int sohci_unlink_urb (urb_t * urb)
if (!urb) /* just to be sure */
return -EINVAL;
+ ohci = (ohci_t *) urb->dev->bus->hcpriv;
+
#ifdef DEBUG
urb_print (urb, "UNLINK", 1);
#endif
- ohci = (ohci_t *) urb->dev->bus->hcpriv;
-
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb); /* a request to the virtual root hub */
@@ -448,8 +610,8 @@ static int sohci_free_dev (struct usb_device * usb_dev)
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
- if (cnt > 0) {
- dev->wait = &wait;
+ if (cnt > 0) {
+ dev->wait = &wait;
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout (HZ / 10);
remove_wait_queue (&op_wakeup, &wait);
@@ -673,10 +835,12 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
}
}
}
- for (i = int_branch; i < 32; i += interval) ohci->ohci_int_load[i] -= ed->int_load;
+ for (i = int_branch; i < 32; i += interval)
+ ohci->ohci_int_load[i] -= ed->int_load;
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_INT");
-#endif break;
+#endif
+ break;
case ISO:
if (ohci->ed_isotail == ed)
@@ -787,10 +951,10 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
switch (ed->type) {
case CTRL: /* stop CTRL list */
- writel (ohci->hc_control &= ~(0x01 << 4), &ohci->regs->control);
+ writel (ohci->hc_control &= ~OHCI_CTRL_CLE, &ohci->regs->control);
break;
case BULK: /* stop BULK list */
- writel (ohci->hc_control &= ~(0x01 << 5), &ohci->regs->control);
+ writel (ohci->hc_control &= ~OHCI_CTRL_BLE, &ohci->regs->control);
break;
}
}
@@ -1012,8 +1176,10 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
if (bulk) writel (0, &ohci->regs->ed_bulkcurrent); /* reset BULK list */
- if (!ohci->ed_rm_list[!frame]) /* start CTRL u. BULK list */
- writel (ohci->hc_control |= (0x03<<4), &ohci->regs->control);
+ if (!ohci->ed_rm_list[!frame]) { /* enable CTRL and BULK lists */
+ ohci->hc_control |= OHCI_CTRL_CLE | OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
ohci->ed_rm_list[frame] = NULL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
@@ -1112,6 +1278,7 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
* Virtual Root Hub
*-------------------------------------------------------------------------*/
+/* Device descriptor */
static __u8 root_hub_dev_des[] =
{
0x12, /* __u8 bLength; */
@@ -1170,23 +1337,8 @@ static __u8 root_hub_config_des[] =
0xff /* __u8 ep_bInterval; 255 ms */
};
-/*
-For OHCI we need just the 2nd Byte, so we
-don't need this constant byte-array
+/* Hub class-specific descriptor is constructed dynamically */
-static __u8 root_hub_hub_des[] =
-{
- 0x00, * __u8 bLength; *
- 0x29, * __u8 bDescriptorType; Hub-descriptor *
- 0x02, * __u8 bNbrPorts; *
- 0x00, * __u16 wHubCharacteristics; *
- 0x00,
- 0x01, * __u8 bPwrOn2pwrGood; 2ms *
- 0x00, * __u8 bHubContrCurrent; 0 mA *
- 0x00, * __u8 DeviceRemovable; *** 8 Ports max *** *
- 0xff * __u8 PortPwrCtrlMask; *** 8 ports max *** *
-};
-*/
/*-------------------------------------------------------------------------*/
@@ -1201,13 +1353,16 @@ static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
__u8 data[8];
- num_ports = readl (&ohci->regs->roothub.a) & 0xff;
- *(__u8 *) data = (readl (&ohci->regs->roothub.status) & 0x00030000) > 0? 1: 0;
+ num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP;
+ *(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
+ ? 1: 0;
ret = *(__u8 *) data;
for ( i = 0; i < num_ports; i++) {
*(__u8 *) (data + (i + 1) / 8) |=
- ((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);
+ ((readl (&ohci->regs->roothub.portstatus[i]) &
+ (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
+ ? 1: 0) << ((i + 1) % 8);
ret += *(__u8 *) (data + (i + 1) / 8);
}
len = i/8 + 1;
@@ -1221,7 +1376,7 @@ static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
/*-------------------------------------------------------------------------*/
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
static void rh_int_timer_do (unsigned long ptr)
{
@@ -1267,10 +1422,10 @@ static int rh_init_int_timer (urb_t * urb)
/*-------------------------------------------------------------------------*/
-#define OK(x) len = (x); break
+#define OK(x) len = (x); break
#define WR_RH_STAT(x) writel((x), &ohci->regs->roothub.status)
#define WR_RH_PORTSTAT(x) writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT readl(&ohci->regs->roothub.status)
+#define RD_RH_STAT readl(&ohci->regs->roothub.status)
#define RD_RH_PORTSTAT readl(&ohci->regs->roothub.portstatus[wIndex-1])
/* request to virtual root hub */
@@ -1309,6 +1464,10 @@ static int rh_submit_urb (urb_t * urb)
wValue = le16_to_cpu (cmd->value);
wIndex = le16_to_cpu (cmd->index);
wLength = le16_to_cpu (cmd->length);
+
+ dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
+ bmRType_bReq, wLength);
+
switch (bmRType_bReq) {
/* Request Destination:
without flags: Device,
@@ -1325,7 +1484,9 @@ static int rh_submit_urb (urb_t * urb)
case RH_GET_STATUS | RH_ENDPOINT:
*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
case RH_GET_STATUS | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32 (RD_RH_STAT & 0x7fff7fff); OK (4);
+ *(__u32 *) data_buf = cpu_to_le32 (
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK (4);
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
@@ -1370,11 +1531,15 @@ static int rh_submit_urb (urb_t * urb)
case (RH_PORT_SUSPEND):
WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
- if((RD_RH_PORTSTAT &1) != 0) WR_RH_PORTSTAT (RH_PS_PRS ); OK (0);
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PRS);
+ OK (0);
case (RH_PORT_POWER):
WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
- if((RD_RH_PORTSTAT &1) != 0) WR_RH_PORTSTAT (RH_PS_PES ); OK (0);
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PES );
+ OK (0);
}
break;
@@ -1438,11 +1603,13 @@ static int rh_submit_urb (urb_t * urb)
case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
default:
+ dbg ("unsupported root hub command");
status = TD_CC_STALL;
}
- dbg("USB HC roothubstat1: %x", readl ( &(ohci->regs->roothub.portstatus[0]) ));
- dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
+#ifdef DEBUG
+ ohci_dump_roothub (ohci, 0);
+#endif
len = min(len, leni);
if (data != data_buf)
@@ -1473,39 +1640,44 @@ static int rh_unlink_urb (urb_t * urb)
* HC functions
*-------------------------------------------------------------------------*/
-/* reset the HC not the BUS */
+/* reset the HC and BUS */
-static void hc_reset (ohci_t * ohci)
+static int hc_reset (ohci_t * ohci)
{
int timeout = 30;
int smm_timeout = 50; /* 0,5 sec */
- if (readl (&ohci->regs->control) & 0x100) { /* SMM owns the HC */
- writel (0x08, &ohci->regs->cmdstatus); /* request ownership */
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
dbg("USB HC TakeOver from SMM");
- while (readl (&ohci->regs->control) & 0x100) {
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10);
if (--smm_timeout == 0) {
err("USB HC TakeOver failed!");
- break;
+ return -1;
}
}
}
- writel ((1 << 31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
- /* this seems to be needed for the lucent controller on powerbooks.. */
- writel (0, &ohci->regs->control); /* Move USB to reset state */
+
+ /* Reset USB (needed by some controllers) */
+ writel (0, &ohci->regs->control);
- writel (1, &ohci->regs->cmdstatus); /* HC Reset */
- while ((readl (&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+ /* HC Reset requires max 10 ms delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--timeout == 0) {
err("USB HC reset timed out!");
- return;
+ return -1;
}
udelay (1);
}
ohci->disabled = 0;
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -1516,7 +1688,7 @@ static void hc_reset (ohci_t * ohci)
static int hc_start (ohci_t * ohci)
{
- unsigned int mask;
+ __u32 mask;
unsigned int fminterval;
struct usb_device * usb_dev;
struct ohci_device * dev;
@@ -1535,31 +1707,35 @@ static int hc_start (ohci_t * ohci)
writel (fminterval, &ohci->regs->fminterval);
writel (0x628, &ohci->regs->lsthresh);
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ writel (ohci->hc_control, &ohci->regs->control);
+
/* Choose the interrupts we care about now, others later on demand */
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);
writel (mask, &ohci->regs->intrstatus);
-#ifdef OHCI_USE_NPS
- writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
+#ifdef OHCI_USE_NPS
+ writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
&ohci->regs->roothub.a);
- writel (0x10000, &ohci->regs->roothub.status);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+ // POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
-#endif /* OHCI_USE_NPS */
+#endif /* OHCI_USE_NPS */
/* connect the virtual root hub */
-
+ ohci->rh.devnum = 0;
usb_dev = usb_alloc_dev (NULL, ohci->bus);
- if (!usb_dev) return -1;
+ if (!usb_dev)
+ return -ENOMEM;
dev = usb_to_ohci (usb_dev);
ohci->bus->root_hub = usb_dev;
usb_connect (usb_dev);
if (usb_new_device (usb_dev) != 0) {
usb_free_dev (usb_dev);
- return -1;
+ return -ENODEV;
}
return 0;
@@ -1582,11 +1758,12 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
return;
}
- dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
-
+ // 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");
+ // e.g. due to PCI Master/Target Abort
}
if (ints & OHCI_INTR_WDH) {
@@ -1661,8 +1838,9 @@ static void hc_release_ohci (ohci_t * ohci)
dbg("USB HC release ohci");
/* disconnect all devices */
- if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub);
-
+ if (ohci->bus->root_hub)
+ usb_disconnect (&ohci->bus->root_hub);
+
hc_reset (ohci);
writel (OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
@@ -1698,6 +1876,7 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
#endif
printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
(unsigned long) mem_base, bufp);
+ printk(KERN_INFO __FILE__ ": %s\n", dev->name);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
@@ -1707,12 +1886,16 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
- hc_reset (ohci);
+ if (hc_reset (ohci) < 0) {
+ hc_release_ohci (ohci);
+ return -ENODEV;
+ }
+
writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
usb_register_bus (ohci->bus);
- if (request_irq (irq, hc_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+ if (request_irq (irq, hc_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
struct pm_dev *pmdev;
ohci->irq = irq;
@@ -1724,6 +1907,10 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
if (pmdev)
pmdev->data = ohci;
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+
return 0;
}
err("request interrupt %d failed", irq);
@@ -1787,7 +1974,8 @@ static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
case PBOOK_WAKE:
writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
wait_ms (20);
- writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ writel (ohci->hc_control, &ohci->regs->control);
enable_irq (ohci->irq);
break;
}
@@ -1801,22 +1989,24 @@ static struct pmu_sleep_notifier ohci_sleep_notifier = {
#endif /* CONFIG_PMAC_PBOOK */
/*-------------------------------------------------------------------------*/
-
+
static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
{
ohci_t * ohci = (ohci_t*) dev->data;
+ int temp = 0;
+
if (ohci) {
switch (rqst) {
case PM_SUSPEND:
- dbg("USB-Bus suspend: %p", ohci);
- writel (ohci->hc_control = 0xFF, &ohci->regs->control);
- wait_ms (10);
+ dbg("USB-Bus suspend: %p", ohci->regs);
+ if (ohci->bus->root_hub)
+ usb_disconnect (&ohci->bus->root_hub);
+ hc_reset (ohci);
break;
case PM_RESUME:
- dbg("USB-Bus resume: %p", ohci);
- writel (ohci->hc_control = 0x7F, &ohci->regs->control);
- wait_ms (20);
- writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+ dbg("USB-Bus resume: %p", ohci->regs);
+ if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0)
+ err ("can't restart controller, %d", temp);
break;
}
}
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index d1b77c8f5..7a3afe5c4 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -27,7 +27,6 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
-#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
@@ -39,14 +38,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
- * to see if this structure may have changed within the SCSI module.
- * This is by no means foolproof, but it does help us some.
- */
-#define SCSI_HOST_TEMPLATE_SIZE (104)
-
/* direction table -- this indicates the direction of the data
* transfer for each command code -- a 1 indicates input
*/
@@ -76,7 +67,11 @@ 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 */
+
+ /* the device we're working with */
+ struct semaphore dev_semaphore; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */
+
unsigned int flags; /* from filter initially */
/* information about the device -- only good if device is attached */
@@ -113,7 +108,7 @@ struct us_data {
unsigned int irqpipe; /* pipe for release_irq */
/* mutual exclusion structures */
- struct semaphore notify; /* wait for thread to begin */
+ struct semaphore notify; /* thread begin/end */
struct semaphore sleeper; /* to sleep on */
struct semaphore queue_exclusion; /* to protect data structs */
};
@@ -131,7 +126,7 @@ struct us_data {
/* The list of structures and the protective lock for them */
static struct us_data *us_list;
-spinlock_t us_list_spinlock = SPIN_LOCK_UNLOCKED;
+struct semaphore us_list_semaphore;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
static void storage_disconnect(struct usb_device *dev, void *ptr);
@@ -249,43 +244,415 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
{
int i;
unsigned int total = 0;
+ struct scatterlist *sg;
- /* always zero for some commands */
- switch (srb->cmnd[0]) {
- case SEEK_6:
- case SEEK_10:
- case REZERO_UNIT:
- case ALLOW_MEDIUM_REMOVAL:
- case START_STOP:
- case TEST_UNIT_READY:
- return 0;
+ /* Are we going to scatter gather? */
+ if (srb->use_sg) {
+ /* Add up the sizes of all the scatter-gather segments */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ total += sg[i].length;
- /* FIXME: these should be removed and tested */
- case REQUEST_SENSE:
- case INQUIRY:
- case MODE_SENSE:
- return srb->cmnd[4];
+ return total;
+ }
+ else
+ /* Just return the length of the buffer */
+ return srb->request_bufflen;
+}
- /* FIXME: these should be removed and tested */
- case LOG_SENSE:
- case MODE_SENSE_10:
- return (srb->cmnd[7] << 8) + srb->cmnd[8];
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
- default:
- break;
+/* Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and recieve the response.
+ */
+static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int need_auto_sense;
+ int result;
+
+ /* send the command to the transport layer */
+ result = us->transport(srb, us);
+
+ /* Determine if we need to auto-sense
+ *
+ * I normally don't use a flag like this, but it's almost impossible
+ * to understand what's going on here if I don't.
+ */
+ need_auto_sense = 0;
+
+ /*
+ * If we're running the CB transport, which is incapable
+ * of determining status on it's own, we need to auto-sense almost
+ * every time.
+ */
+ if (us->protocol == US_PR_CB) {
+ US_DEBUGP("-- CB transport device requiring auto-sense\n");
+ need_auto_sense = 1;
+
+ /* There are some exceptions to this. Notably, if this is
+ * a UFI device and the command is REQUEST_SENSE or INQUIRY,
+ * then it is impossible to truly determine status.
+ */
+ if (us->subclass == US_SC_UFI &&
+ ((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY)))
+ need_auto_sense = 0;
}
- if (srb->use_sg) {
- struct scatterlist *sg;
+ /*
+ * If we have an error, we're going to do a REQUEST_SENSE
+ * automatically. Note that we differentiate between a command
+ * "failure" and an "error" in the transport mechanism.
+ */
+ if (result == USB_STOR_TRANSPORT_FAILED) {
+ US_DEBUGP("-- transport indicates command failure\n");
+ need_auto_sense = 1;
+ }
+ if (result == USB_STOR_TRANSPORT_ERROR) {
+ /* FIXME: we need to invoke a transport reset here */
+ US_DEBUGP("-- transport indicates transport failure\n");
+ need_auto_sense = 0;
+ srb->result = DID_ERROR << 16;
+ return;
+ }
- sg = (struct scatterlist *) srb->request_buffer;
- for (i = 0; i < srb->use_sg; i++) {
- total += sg[i].length;
+ /*
+ * Also, if we have a short transfer on a command that can't have
+ * a short transfer, we're going to do this.
+ */
+ if ((srb->result == US_BULK_TRANSFER_SHORT) &&
+ !((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY) ||
+ (srb->cmnd[0] == MODE_SENSE) ||
+ (srb->cmnd[0] == LOG_SENSE) ||
+ (srb->cmnd[0] == MODE_SENSE_10))) {
+ US_DEBUGP("-- unexpectedly short transfer\n");
+ need_auto_sense = 1;
+ }
+
+ /* Now, if we need to do the auto-sense, let's do it */
+ if (need_auto_sense) {
+ int temp_result;
+ void* old_request_buffer;
+ int old_sg;
+
+ US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+
+ srb->cmnd[0] = REQUEST_SENSE;
+ srb->cmnd[1] = 0;
+ srb->cmnd[2] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[4] = 18;
+ srb->cmnd[5] = 0;
+
+ /* set the buffer length for transfer */
+ old_request_buffer = srb->request_buffer;
+ old_sg = srb->use_sg;
+ srb->request_bufflen = 18;
+ srb->request_buffer = us->srb->sense_buffer;
+
+ /* FIXME: what if this command fails? */
+ temp_result = us->transport(us->srb, us);
+ US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+ US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+ srb->sense_buffer[2] & 0xf,
+ srb->sense_buffer[12],
+ srb->sense_buffer[13]);
+
+ /* set the result so the higher layers expect this data */
+ srb->result = CHECK_CONDITION;
+
+ /* we're done here */
+ srb->request_buffer = old_request_buffer;
+ srb->use_sg = old_sg;
+ }
+
+ /* Set return code, if necessary */
+ if (need_auto_sense && (srb->sense_buffer[0] == 0x0))
+ srb->result = GOOD;
+ if (!need_auto_sense)
+ srb->result = GOOD;
+}
+
+/*
+ * Control/Bulk/Interrupt transport
+ */
+static int CBI_irq(int state, void *buffer, int len, void *dev_id)
+{
+ struct us_data *us = (struct us_data *)dev_id;
+
+ US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+ US_DEBUGP("-- IRQ data length is %d\n", len);
+ US_DEBUGP("-- IRQ state is %d\n", state);
+
+ /* is the device removed? */
+ if (state != -ENOENT) {
+ /* save the data for interpretation later */
+ us->ip_data = le16_to_cpup((__u16 *)buffer);
+ US_DEBUGP("-- Interrupt Status 0x%x\n", us->ip_data);
+
+ /* was this a wanted interrupt? */
+ if (us->ip_wanted) {
+ us->ip_wanted = 0;
+ up(&(us->ip_waitq));
+ } else
+ US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+ } else
+ US_DEBUGP("-- device has been removed\n");
+
+ /* This return code is truly meaningless -- and I mean truly. It gets
+ * ignored by other layers. It used to indicate if we wanted to get
+ * another interrupt or disable the interrupt callback
+ */
+ return 0;
+}
+
+static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+
+ /* COMMAND STAGE */
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ 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) {
+ /* STALL must be cleared when they are detected */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
}
- return total;
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
}
- else
- return srb->request_bufflen;
+
+ /* Set up for status notification */
+ us->ip_wanted = 1;
+
+ /* DATA STAGE */
+ /* transfer the data payload for this command, if one exists*/
+ if (us_transfer_length(srb)) {
+ us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
+ }
+
+ /* STATUS STAGE */
+
+ /* go to sleep until we get this interrupt */
+ down(&(us->ip_waitq));
+
+ /* 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;
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ 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 on UFI
+ * devices, so we ignore the information for those commands. Note
+ * that this means we could be ignoring a real error on these
+ * commands, but that can't be helped.
+ */
+ if (us->subclass == US_SC_UFI) {
+ if (srb->cmnd[0] == REQUEST_SENSE ||
+ srb->cmnd[0] == INQUIRY)
+ return USB_STOR_TRANSPORT_GOOD;
+ else
+ if (us->ip_data)
+ return USB_STOR_TRANSPORT_FAILED;
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* If not UFI, we interpret the data as a result code
+ * The first byte should always be a 0x0
+ * The second byte & 0x0F should be 0x0 for good, otherwise error
+ */
+ switch ((us->ip_data & 0xFF0F)) {
+ case 0x0000:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x0001:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ US_DEBUGP("CBI_transport() reached end of function\n");
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Control/Bulk transport
+ */
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+
+ /* COMMAND STAGE */
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
+
+ /* check the return code for the command */
+ 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");
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* DATA STAGE */
+ /* transfer the data payload for this command, if one exists*/
+ if (us_transfer_length(srb)) {
+ us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
+ }
+
+
+ /* STATUS STAGE */
+ /* NOTE: CB does not have a status stage. Silly, I know. So
+ * we have to catch this at a higher level.
+ */
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Bulk only transport
+ */
+static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ struct bulk_cb_wrap bcb;
+ struct bulk_cs_wrap bcs;
+ int result;
+ int pipe;
+ int partial;
+
+ /* set up the command wrapper */
+ bcb.Signature = US_BULK_CB_SIGN;
+ bcb.DataTransferLength = us_transfer_length(srb);
+ bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+ bcb.Tag = srb->serial_number;
+ bcb.Lun = srb->cmnd[1] >> 5;
+ bcb.Length = srb->cmd_len;
+
+ /* construct the pipe handle */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ /* copy the command payload */
+ memset(bcb.CDB, 0, sizeof(bcb.CDB));
+ memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+
+ /* send it to out endpoint */
+ US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
+ bcb.Signature, bcb.Tag, bcb.Lun, bcb.DataTransferLength,
+ bcb.Flags, bcb.Length);
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
+ US_BULK_CB_WRAP_LEN, &partial, HZ*5);
+ US_DEBUGP("Bulk command transfer result=%d\n", result);
+
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
+
+ /* if the command transfered well, then we go to the data stage */
+ if (result == 0) {
+ /* send/receive data payload, if there is any */
+ if (bcb.DataTransferLength) {
+ us_transfer(srb, bcb.Flags);
+ US_DEBUGP("Bulk data transfer result 0x%x\n",
+ srb->result);
+ }
+ }
+
+ /* See flow chart on pg 15 of the Bulk Only Transport spec for
+ * an explanation of how this code works.
+ */
+
+ /* construct the pipe handle */
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+
+ /* get CSW for device status */
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+ US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+
+ /* did the attempt to read the CSW fail? */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+
+ /* get the status again */
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+ US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+
+ /* if it fails again, we need a reset and return an error*/
+ if (result == -EPIPE) {
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+
+ /* if we still have a failure at this point, we're in trouble */
+ if (result) {
+ US_DEBUGP("Bulk status result = %d\n", result);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* check bulk status */
+ US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+ bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
+ if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
+ bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+ US_DEBUGP("Bulk logical error\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* based on the status code, we report good or bad */
+ switch (bcs.Status) {
+ case US_BULK_STAT_OK:
+ /* command good -- note that we could be short on data */
+ return USB_STOR_TRANSPORT_GOOD;
+
+ case US_BULK_STAT_FAIL:
+ /* command failed */
+ return USB_STOR_TRANSPORT_FAILED;
+
+ case US_BULK_STAT_PHASE:
+ /* phase error */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* we should never get here, but if we do, we're in trouble */
+ return USB_STOR_TRANSPORT_ERROR;
}
/***********************************************************************
@@ -295,7 +662,6 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
- int result;
/* Fix some commands -- this is a form of mode translation
* ATAPI devices only accept 12 byte long commands
@@ -308,7 +674,7 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmd_len = 12;
/* determine the correct (or minimum) data length for these commands */
- switch (us->srb->cmnd[0]) {
+ switch (srb->cmnd[0]) {
/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
case MODE_SENSE:
@@ -350,60 +716,7 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
} /* end switch on cmnd[0] */
/* send the command to the transport layer */
- result = us->transport(srb, us);
-
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
- */
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
-
- /*
- * If we have an error, we're going to do a
- * REQUEST_SENSE automatically
- */
- if (result != USB_STOR_TRANSPORT_GOOD) {
- int temp_result;
- void* old_request_buffer;
- int old_sg;
-
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
- us->srb->cmnd[0] = REQUEST_SENSE;
- us->srb->cmnd[1] = 0;
- us->srb->cmnd[2] = 0;
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[4] = 18;
- us->srb->cmnd[5] = 0;
-
- /* set the buffer length for transfer */
- old_request_buffer = us->srb->request_buffer;
- old_sg = us->srb->use_sg;
- us->srb->request_bufflen = 18;
- us->srb->request_buffer = us->srb->sense_buffer;
-
- /* FIXME: what if this command fails? */
- temp_result = us->transport(us->srb, us);
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- us->srb->sense_buffer[2] & 0xf,
- us->srb->sense_buffer[12],
- us->srb->sense_buffer[13]);
-
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
- /* we're done here */
- us->srb->request_buffer = old_request_buffer;
- us->srb->use_sg = old_sg;
- return;
- }
+ invoke_transport(srb, us);
/* Fix the MODE_SENSE data if we translated the command
*/
@@ -424,7 +737,7 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
*/
- if (us->srb->cmnd[0] == INQUIRY) {
+ if (srb->cmnd[0] == INQUIRY) {
((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
}
}
@@ -433,7 +746,6 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
- int result;
/* fix some commands -- this is a form of mode translation
* UFI devices only accept 12 byte long commands
@@ -446,11 +758,11 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmd_len = 12;
/* determine the correct (or minimum) data length for these commands */
- switch (us->srb->cmnd[0]) {
+ switch (srb->cmnd[0]) {
/* for INQUIRY, UFI devices only ever return 36 bytes */
case INQUIRY:
- us->srb->cmnd[4] = 36;
+ srb->cmnd[4] = 36;
break;
/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
@@ -482,13 +794,13 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
/* again, for MODE_SENSE_10, we get the minimum (8) */
case MODE_SENSE_10:
- us->srb->cmnd[7] = 0;
- us->srb->cmnd[8] = 8;
+ srb->cmnd[7] = 0;
+ srb->cmnd[8] = 8;
break;
/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
case REQUEST_SENSE:
- us->srb->cmnd[4] = 18;
+ srb->cmnd[4] = 18;
break;
/* change READ_6/WRITE_6 to READ_10/WRITE_10, which
@@ -509,63 +821,10 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmnd[0] = srb->cmnd[0] | 0x20;
break;
} /* end switch on cmnd[0] */
-
- /* send the command to the transport layer */
- result = us->transport(srb, us);
-
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
- */
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
-
- /*
- * If we have an error, we're going to do a
- * REQUEST_SENSE automatically
- */
- if (result != USB_STOR_TRANSPORT_GOOD) {
- int temp_result;
- void* old_request_buffer;
- int old_sg;
-
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
- us->srb->cmnd[0] = REQUEST_SENSE;
- us->srb->cmnd[1] = 0;
- us->srb->cmnd[2] = 0;
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[4] = 18;
- us->srb->cmnd[5] = 0;
-
- /* set the buffer length for transfer */
- old_request_buffer = us->srb->request_buffer;
- old_sg = us->srb->use_sg;
- us->srb->request_bufflen = 18;
- us->srb->request_buffer = us->srb->sense_buffer;
-
- /* FIXME: what if this command fails? */
- temp_result = us->transport(us->srb, us);
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- us->srb->sense_buffer[2] & 0xf,
- us->srb->sense_buffer[12],
- us->srb->sense_buffer[13]);
-
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
- /* we're done here */
- us->srb->request_buffer = old_request_buffer;
- us->srb->use_sg = old_sg;
- return;
- }
-
+ /* send the command to the transport layer */
+ invoke_transport(srb, us);
+
/* Fix the MODE_SENSE data here if we had to translate the command
*/
if (old_cmnd == MODE_SENSE) {
@@ -585,15 +844,13 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
*/
- if (us->srb->cmnd[0] == INQUIRY) {
+ if (srb->cmnd[0] == INQUIRY) {
((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
}
}
static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
{
- unsigned int result = 0;
-
/* This code supports devices which do not support {READ|WRITE}_6
* Apparently, neither Windows or MacOS will use these commands,
* so some devices do not support them
@@ -601,155 +858,76 @@ static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
if (us->flags & US_FL_MODE_XLATE) {
/* translate READ_6 to READ_10 */
- if (us->srb->cmnd[0] == 0x08) {
+ if (srb->cmnd[0] == 0x08) {
/* get the control */
- us->srb->cmnd[9] = us->srb->cmnd[5];
+ srb->cmnd[9] = us->srb->cmnd[5];
/* get the length */
- us->srb->cmnd[8] = us->srb->cmnd[6];
- us->srb->cmnd[7] = 0;
+ srb->cmnd[8] = us->srb->cmnd[6];
+ srb->cmnd[7] = 0;
/* set the reserved area to 0 */
- us->srb->cmnd[6] = 0;
+ srb->cmnd[6] = 0;
/* get LBA */
- us->srb->cmnd[5] = us->srb->cmnd[3];
- us->srb->cmnd[4] = us->srb->cmnd[2];
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[2] = 0;
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
/* LUN and other info in cmnd[1] can stay */
/* fix command code */
- us->srb->cmnd[0] = 0x28;
+ srb->cmnd[0] = 0x28;
US_DEBUGP("Changing READ_6 to READ_10\n");
- US_DEBUG(us_show_command(us->srb));
+ US_DEBUG(us_show_command(srb));
}
/* translate WRITE_6 to WRITE_10 */
- if (us->srb->cmnd[0] == 0x0A) {
+ if (srb->cmnd[0] == 0x0A) {
/* get the control */
- us->srb->cmnd[9] = us->srb->cmnd[5];
+ srb->cmnd[9] = us->srb->cmnd[5];
/* get the length */
- us->srb->cmnd[8] = us->srb->cmnd[4];
- us->srb->cmnd[7] = 0;
+ srb->cmnd[8] = us->srb->cmnd[4];
+ srb->cmnd[7] = 0;
/* set the reserved area to 0 */
- us->srb->cmnd[6] = 0;
+ srb->cmnd[6] = 0;
/* get LBA */
- us->srb->cmnd[5] = us->srb->cmnd[3];
- us->srb->cmnd[4] = us->srb->cmnd[2];
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[2] = 0;
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
/* LUN and other info in cmnd[1] can stay */
/* fix command code */
- us->srb->cmnd[0] = 0x2A;
+ srb->cmnd[0] = 0x2A;
US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
US_DEBUG(us_show_command(us->srb));
}
} /* if (us->flags & US_FL_MODE_XLATE) */
-
- /* send the command to the transport layer */
- result = us->transport(us->srb, us);
-
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
- */
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
- /* if we have an error, we're going to do a REQUEST_SENSE
- * automatically */
- if (result != USB_STOR_TRANSPORT_GOOD) {
- int temp_result;
- int old_sg;
- void* old_request_buffer;
-
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
- /* set up the REQUEST_SENSE command and parameters */
- us->srb->cmnd[0] = REQUEST_SENSE;
- us->srb->cmnd[1] = 0;
- us->srb->cmnd[2] = 0;
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[4] = 18;
- us->srb->cmnd[5] = 0;
-
- /* set the buffer length for transfer */
- old_request_buffer = us->srb->request_buffer;
- old_sg = us->srb->use_sg;
- us->srb->request_bufflen = 18;
- us->srb->request_buffer = us->srb->sense_buffer;
-
- /* FIXME: what if this command fails? */
- temp_result = us->transport(us->srb, us);
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- us->srb->sense_buffer[2] & 0xf,
- us->srb->sense_buffer[12],
- us->srb->sense_buffer[13]);
-
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
- /* we're done here */
- us->srb->use_sg = old_sg;
- us->srb->request_buffer = old_request_buffer;
- return;
- }
+ /* send the command to the transport layer */
+ invoke_transport(srb, us);
/* fix the results of an INQUIRY */
- if (us->srb->cmnd[0] == INQUIRY) {
+ if (srb->cmnd[0] == INQUIRY) {
US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
((unsigned char*)us->srb->request_buffer)[2] |= 2;
}
}
/***********************************************************************
- * Transport routines
+ * Reset routines
***********************************************************************/
-static int CBI_irq(int state, void *buffer, int len, void *dev_id)
-{
- struct us_data *us = (struct us_data *)dev_id;
-
- US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
-
- /* save the data for interpretation later */
- if (state != USB_ST_REMOVED) {
- us->ip_data = le16_to_cpup((__u16 *)buffer);
- US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data);
- }
-
- /* was this a wanted interrupt? */
- if (us->ip_wanted) {
- us->ip_wanted = 0;
- up(&(us->ip_waitq));
- } else {
- US_DEBUGP("ERROR: Unwanted interrupt received!\n");
- }
-
- /* This return code is truly meaningless -- and I mean truly. It gets
- * ignored by other layers. It used to indicate if we wanted to get
- * another interrupt or disable the interrupt callback
- */
- return 0;
-}
-
/* This issues a CB[I] Reset to the device in question
*/
static int CB_reset(struct us_data *us)
@@ -757,7 +935,7 @@ static int CB_reset(struct us_data *us)
unsigned char cmd[12];
int result;
- US_DEBUGP("CB_reset\n");
+ US_DEBUGP("CB_reset() called\n");
memset(cmd, 0xFF, sizeof(cmd));
cmd[0] = SEND_DIAGNOSTIC;
@@ -780,162 +958,6 @@ static int CB_reset(struct us_data *us)
return 0;
}
-/*
- * Control/Bulk/Interrupt transport
- */
-static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- int result;
-
- US_DEBUGP("CBI gets a command:\n");
- US_DEBUG(us_show_command(srb));
-
- /* COMMAND STAGE */
- /* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- 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) {
- /* a stall is a fatal condition from the device */
- if (result == -EPIPE) {
- US_DEBUGP("-- Stall on control pipe. Clearing\n");
- US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
- usb_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0)));
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* FIXME: we need to handle NAKs here */
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* Set up for status notification */
- us->ip_wanted = 1;
-
- /* DATA STAGE */
- /* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb)) {
- us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
- US_DEBUGP("CBI data stage result is 0x%x\n", result);
- }
-
- /* STATUS STAGE */
-
- /* go to sleep until we get this interrupt */
- down(&(us->ip_waitq));
-
- /* 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;
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- 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
- * ignore the information for those commands
- */
- if (us->subclass == US_SC_UFI) {
- if (srb->cmnd[0] == REQUEST_SENSE ||
- srb->cmnd[0] == INQUIRY)
- return USB_STOR_TRANSPORT_GOOD;
- else
- if (us->ip_data)
- return USB_STOR_TRANSPORT_FAILED;
- else
- return USB_STOR_TRANSPORT_GOOD;
- }
-
- /* otherwise, we interpret the data normally */
- switch (us->ip_data) {
- case 0x0001:
- return USB_STOR_TRANSPORT_GOOD;
- case 0x0002:
- return USB_STOR_TRANSPORT_FAILED;
- default:
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- US_DEBUGP("CBI_transport() reached end of function\n");
- return USB_STOR_TRANSPORT_ERROR;
-}
-
-/*
- * Control/Bulk transport
- */
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- int result;
- __u8 status[2];
-
- US_DEBUGP("CBC gets a command:\n");
- US_DEBUG(us_show_command(srb));
-
- /* COMMAND STAGE */
- /* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
-
- /* check the return code for the command */
- 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");
- US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
- usb_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0)));
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* FIXME: we need to handle NAKs here */
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* DATA STAGE */
- /* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb)) {
- us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
- US_DEBUGP("CBC data stage result is 0x%x\n", result);
- }
-
-
- /* STATUS STAGE */
- /* FIXME: this is wrong */
- result = usb_control_msg(us->pusb_dev,
- usb_rcvctrlpipe(us->pusb_dev,0),
- USB_REQ_GET_STATUS, USB_DIR_IN |
- USB_TYPE_STANDARD | USB_RECIP_DEVICE,
- 0, us->ifnum, status, sizeof(status), HZ*5);
-
- if (result < 0) {
- US_DEBUGP("CBC Status stage returns %d\n", result);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- US_DEBUGP("Got CB status 0x%x 0x%x\n", status[0], status[1]);
- if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
- ( (status[0] & ~3) || status[1]))
- return USB_STOR_TRANSPORT_FAILED;
- else
- return USB_STOR_TRANSPORT_GOOD;
-
- US_DEBUGP("CB_transport() reached end of function\n");
- return USB_STOR_TRANSPORT_ERROR;
-}
-
/* FIXME: Does this work? */
static int Bulk_reset(struct us_data *us)
{
@@ -961,135 +983,31 @@ static int Bulk_reset(struct us_data *us)
return result;
}
-/*
- * Bulk only transport
- */
-static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- struct bulk_cb_wrap bcb;
- struct bulk_cs_wrap bcs;
- int result;
- int pipe;
- int partial;
-
- /* set up the command wrapper */
- bcb.Signature = US_BULK_CB_SIGN;
- bcb.DataTransferLength = us_transfer_length(srb);
- bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
- bcb.Tag = srb->serial_number;
- bcb.Lun = 0;
- bcb.Length = srb->cmd_len;
-
- /* construct the pipe handle */
- pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
- /* copy the command payload */
- memset(bcb.CDB, 0, sizeof(bcb.CDB));
- memcpy(bcb.CDB, srb->cmnd, bcb.Length);
-
- /* send it to out endpoint */
- US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n",
- bcb.Signature, bcb.Tag, bcb.DataTransferLength,
- bcb.Flags, bcb.Length);
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
- US_BULK_CB_WRAP_LEN, &partial, HZ*5);
- US_DEBUGP("Bulk command transfer result=%d\n", result);
-
- /* if we stall, we need to clear it before we go on */
- if (result == -EPIPE) {
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
- }
-
- /* if the command transfered well, then we go to the data stage */
- if (result == 0) {
- /* send/receive data payload, if there is any */
- if (bcb.DataTransferLength) {
- us_transfer(srb, bcb.Flags);
- US_DEBUGP("Bulk data transfer result 0x%x\n",
- srb->result);
- }
- }
-
- /* See flow chart on pg 15 of the Bulk Only Transport spec for
- * an explanation of how this code works.
- */
-
- /* construct the pipe handle */
- pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-
- /* get CSW for device status */
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-
- /* did the attempt to read the CSW fail? */
- if (result == -EPIPE) {
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
-
- /* get the status again */
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-
- /* if it fails again, we need a reset and return an error*/
- if (result == -EPIPE) {
- Bulk_reset(us);
- return USB_STOR_TRANSPORT_ERROR;
- }
- }
-
- /* if we still have a failure at this point, we're in trouble */
- if (result) {
- US_DEBUGP("Bulk status result = %d\n", result);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* check bulk status */
- US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
- bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
- if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
- bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
- US_DEBUGP("Bulk logical error\n");
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* based on the status code, we report good or bad */
- switch (bcs.Status) {
- case US_BULK_STAT_OK:
- /* command good -- note that we could be short on data */
- return USB_STOR_TRANSPORT_GOOD;
-
- case US_BULK_STAT_FAIL:
- /* command failed */
- return USB_STOR_TRANSPORT_FAILED;
-
- case US_BULK_STAT_PHASE:
- /* phase error */
- Bulk_reset(us);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* we should never get here, but if we do, we're in trouble */
- return USB_STOR_TRANSPORT_ERROR;
-}
-
/***********************************************************************
* Host functions
***********************************************************************/
-/* detect adapter (always true ) */
+static const char* us_info(struct Scsi_Host *host)
+{
+ return "SCSI emulation for USB Mass Storage devices\n";
+}
+
+/* detect a virtual adapter (always works) */
static int us_detect(struct SHT *sht)
{
- /* FIXME - not nice at all, but how else ? */
- struct us_data *us = (struct us_data *)sht->proc_dir;
- char name[32];
+ struct us_data *us;
+ char local_name[32];
+
+ /* This is not nice at all, but how else are we to get the
+ * data here? */
+ us = (struct us_data *)sht->proc_dir;
- /* set up our name */
- sprintf(name, "usbscsi%d", us->host_number);
- sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
+ /* set up the name of our subdirectory under /proc/scsi/ */
+ sprintf(local_name, "usb-storage-%d", us->host_number);
+ sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
if (!sht->proc_name)
return 0;
- strcpy(sht->proc_name, name);
+ strcpy(sht->proc_name, local_name);
/* we start with no /proc directory entry */
sht->proc_dir = NULL;
@@ -1105,36 +1023,34 @@ static int us_detect(struct SHT *sht)
/* odd... didn't register properly. Abort and free pointers */
kfree(sht->proc_name);
sht->proc_name = NULL;
- sht->name = NULL;
return 0;
}
-/* release - must be here to stop scsi
- * from trying to release IRQ etc.
- * Kill off our data
+/* Release all resources used by the virtual host
+ *
+ * NOTE: There is no contention here, because we're allready deregistered
+ * the driver and we're doing each virtual host in turn, not in parallel
*/
static int us_release(struct Scsi_Host *psh)
{
struct us_data *us = (struct us_data *)psh->hostdata[0];
- 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) {
- 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;
- }
-
- /* lock the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ /* Kill the control threads
+ *
+ * Enqueue the command, wake up the thread, and wait for
+ * notification that it's exited.
+ */
+ US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
+ us->action = US_ACT_EXIT;
+ up(&(us->sleeper));
+ down(&(us->notify));
+
+ /* free the data structure we were using */
+ US_DEBUGP("-- freeing private host data structure\n");
+ kfree(us);
+ (struct us_data*)psh->hostdata[0] = NULL;
/* we always have a successful release */
return 0;
@@ -1171,20 +1087,38 @@ static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
return 0;
}
-/* FIXME: This doesn't actually abort anything */
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command abort
+ *
+ * Note that this is really only meaningful right now for CBI transport
+ * devices which have failed to give us the command completion interrupt
+ */
static int us_abort( Scsi_Cmnd *srb )
{
- return 0;
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+ US_DEBUGP("us_abort() called\n");
+
+ /* if we're stuck waiting for an IRQ, simulate it */
+ if (us->ip_wanted) {
+ US_DEBUGP("-- simulating missing IRQ\n");
+ up(&(us->ip_waitq));
+ return SUCCESS;
+ }
+
+ return FAILED;
}
/* 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];
+ printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
US_DEBUGP("Bus reset requested\n");
- if (us->ip_wanted)
- up(&(us->ip_waitq));
// us->transport_reset(us);
return SUCCESS;
}
@@ -1192,6 +1126,7 @@ static int us_bus_reset( Scsi_Cmnd *srb )
/* FIXME: This doesn't actually reset anything */
static int us_host_reset( Scsi_Cmnd *srb )
{
+ printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
return 0;
}
@@ -1209,14 +1144,13 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
struct us_data *us;
char *pos = buffer;
char *tmp_ptr;
- unsigned long flags;
/* if someone is sending us data, just throw it away */
if (inout)
return length;
/* lock the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
+ down(&us_list_semaphore);
/* find our data from hostno */
us = us_list;
@@ -1228,7 +1162,7 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
/* if we couldn't find it, we return an error */
if (!us) {
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
return -ESRCH;
}
@@ -1274,11 +1208,42 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
break;
}
+ SPRINTF(" Transport: ");
+ switch (us->subclass) {
+ case US_SC_RBC:
+ SPRINTF("Reduced Block Commands\n");
+ break;
+
+ case US_SC_8020:
+ SPRINTF("8020i\n");
+ break;
+
+ case US_SC_QIC:
+ SPRINTF("QIC-157\n");
+ break;
+
+ case US_SC_8070:
+ SPRINTF("8070i\n");
+ break;
+
+ case US_SC_SCSI:
+ SPRINTF("Transparent SCSI\n");
+ break;
+
+ case US_SC_UFI:
+ SPRINTF("Uniform Floppy Interface\n");
+ break;
+
+ default:
+ SPRINTF("Unknown Transport\n");
+ break;
+ }
+
/* show the GUID of the device */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
/* release our lock on the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
/*
* Calculate start of next buffer, and return value.
@@ -1298,36 +1263,30 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
*/
static Scsi_Host_Template my_host_template = {
- NULL, /* next */
- NULL, /* module */
- NULL, /* proc_dir */
- usb_stor_proc_info,
- NULL, /* name - points to unique */
- us_detect,
- us_release,
- NULL, /* info */
- NULL, /* ioctl */
- us_command,
- us_queuecommand,
- NULL, /* eh_strategy */
- us_abort,
- us_bus_reset,
- us_bus_reset,
- us_host_reset,
- NULL, /* abort */
- NULL, /* reset */
- NULL, /* slave_attach */
- NULL, /* bios_param */
- NULL, /* select_queue_depths */
- 1, /* can_queue */
- -1, /* this_id */
- SG_ALL, /* sg_tablesize */
- 1, /* cmd_per_lun */
- 0, /* present */
- FALSE, /* unchecked_isa_dma */
- TRUE, /* use_clustering */
- TRUE, /* use_new_eh_code */
- TRUE /* emulated */
+ name: "usb-storage",
+ proc_info: usb_stor_proc_info,
+ info: us_info,
+
+ detect: us_detect,
+ release: us_release,
+ command: us_command,
+ queuecommand: us_queuecommand,
+
+ eh_abort_handler: us_abort,
+ eh_device_reset_handler:us_bus_reset,
+ eh_bus_reset_handler: us_bus_reset,
+ eh_host_reset_handler: us_host_reset,
+
+ can_queue: 1,
+ this_id: -1,
+
+ sg_tablesize: SG_ALL,
+ cmd_per_lun: 1,
+ present: 0,
+ unchecked_isa_dma: FALSE,
+ use_clustering: TRUE,
+ use_new_eh_code: TRUE,
+ emulated: TRUE,
};
static unsigned char sense_notready[] = {
@@ -1362,10 +1321,11 @@ static int usb_stor_control_thread(void * __us)
*/
daemonize();
- sprintf(current->comm, "usbscsi%d", us->host_number);
+ sprintf(current->comm, "usb-storage-%d", us->host_number);
unlock_kernel();
+ /* signal that we've started the thread */
up(&(us->notify));
for(;;) {
@@ -1382,14 +1342,10 @@ static int usb_stor_control_thread(void * __us)
/* release the queue lock as fast as possible */
up(&(us->queue_exclusion));
- /* FIXME: we need to examine placment of break; and
- * scsi_done() calls */
-
switch (action) {
case US_ACT_COMMAND:
/* bad device */
- /* FIXME: we need to enable and test multiple LUNs */
- if (us->srb->target || us->srb->lun) {
+ if (us->srb->target) {
US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
us->srb->result = DID_BAD_TARGET << 16;
@@ -1399,6 +1355,9 @@ static int usb_stor_control_thread(void * __us)
break;
}
+ /* lock the device pointers */
+ down(&(us->dev_semaphore));
+
/* our device has gone - pretend not ready */
/* FIXME: we also need to handle INQUIRY here,
* probably */
@@ -1414,6 +1373,10 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = (DID_OK << 16) | 2;
}
+ /* unlock the device pointers */
+ up(&(us->dev_semaphore));
+
+ /* indicate that the command is done */
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1434,6 +1397,11 @@ static int usb_stor_control_thread(void * __us)
US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
+
+ /* unlock the device pointers */
+ up(&(us->dev_semaphore));
+
+ /* indicate that the command is done */
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1453,11 +1421,15 @@ static int usb_stor_control_thread(void * __us)
} /* end switch on action */
/* exit if we get a signal to exit */
- if (action == US_ACT_EXIT)
+ if (action == US_ACT_EXIT) {
+ US_DEBUGP("-- US_ACT_EXIT command recieved\n");
break;
+ }
} /* for (;;) */
- printk("usb_stor_control_thread exiting\n");
+ /* notify the exit routine that we're actually exiting now */
+ up(&(us->notify));
+
return 0;
}
@@ -1471,7 +1443,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
struct us_data *ss = NULL;
GUID(guid); /* Global Unique Identifier */
int result;
- unsigned long flags;
/* these are temporary copies -- we test on these, then put them
* in the us-data structure
@@ -1531,9 +1502,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
&ss->irq_handle);
if (result < 0)
return NULL;
-
- /* FIXME: what is this?? */
- down(&(ss->ip_waitq));
}
/*
@@ -1613,7 +1581,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
}
/* lock access to the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
+ down(&us_list_semaphore);
/*
* Now check if we have seen this GUID before
@@ -1655,7 +1623,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
return NULL;
}
memset(ss, 0, sizeof(struct us_data));
@@ -1664,6 +1632,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
init_MUTEX_LOCKED(&(ss->sleeper));
init_MUTEX_LOCKED(&(ss->notify));
init_MUTEX(&(ss->queue_exclusion));
+ init_MUTEX(&(ss->dev_semaphore));
/* copy over the subclass and protocol data */
ss->subclass = subclass;
@@ -1725,7 +1694,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
break;
case US_SC_QIC:
- US_DEBUGPX("QIC157\n");
+ US_DEBUGPX("QIC-157\n");
break;
case US_SC_8070:
@@ -1774,9 +1743,9 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* Grab the next host number */
ss->host_number = my_host_number++;
- /* FIXME: this is bad. We abuse this pointer so we
- * can pass the ss pointer to the host controler thread
- * in us_detect
+ /* We abuse this pointer so we can pass the ss pointer to
+ * the host controler thread in us_detect. But how else are
+ * we to do it?
*/
(struct us_data *)ss->htmplt.proc_dir = ss;
@@ -1795,7 +1764,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
down(&(ss->notify));
/* now register - our detect function will be called */
- ss->htmplt.module = &__this_module;
+ ss->htmplt.module = THIS_MODULE;
scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
/* put us in the list */
@@ -1804,7 +1773,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
}
/* release the data structure lock */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
printk(KERN_DEBUG
"WARNING: USB Mass Storage data integrity not assured\n");
@@ -1829,6 +1798,9 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
return;
}
+ /* lock access to the device data structure */
+ down(&(ss->dev_semaphore));
+
/* release the IRQ, if we have one */
if (ss->irq_handle) {
US_DEBUGP("-- releasing irq handle\n");
@@ -1840,6 +1812,9 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
/* mark the device as gone */
ss->pusb_dev = NULL;
+
+ /* lock access to the device data structure */
+ up(&(ss->dev_semaphore));
}
@@ -1849,18 +1824,10 @@ 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 bad\n");
- printk(KERN_ERR
- "usb-storage: expected %d bytes, got %d bytes\n",
- SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
- return -1 ;
- }
+ /* initialize internal global data elements */
+ us_list = NULL;
+ init_MUTEX(&us_list_semaphore);
+ my_host_number = 0;
/* register the driver, return -1 if error */
if (usb_register(&storage_driver) < 0)
@@ -1873,36 +1840,38 @@ 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;
+ struct us_data *next;
- /*
- * deregister the driver -- this eliminates races with probes and
- * disconnects
+ US_DEBUGP("usb_stor_exit() called\n");
+
+ /* Deregister the driver
+ * This eliminates races with probes and disconnects
*/
+ US_DEBUGP("-- calling usb_deregister()\n");
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));
-
- /* kill the threads */
- /* FIXME: we can do this by sending them a signal to die */
-
- /* free up the data structures */
- /* FIXME: we need to eliminate the host structure also */
- while (ptr) {
- next = ptr->next;
- kfree(ptr);
- ptr = next;
+ down(&us_list_semaphore);
+
+ /* While there are still virtual hosts, unregister them
+ *
+ * Note that the us_release() routine will destroy the local data
+ * structure. So we have to peel these off the top of the list
+ * and keep updating the head pointer as we go.
+ */
+ while (us_list) {
+ /* keep track of where the next one is */
+ next = us_list->next;
+
+ US_DEBUGP("-- calling scsi_unregister_module()\n");
+ scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+
+ /* advance the list pointer */
+ us_list = next;
}
/* unlock the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
}
module_init(usb_stor_init) ;
diff --git a/drivers/usb/usb-storage.h b/drivers/usb/usb-storage.h
index 06e6d958b..6a37924ca 100644
--- a/drivers/usb/usb-storage.h
+++ b/drivers/usb/usb-storage.h
@@ -129,8 +129,8 @@ static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *seri
}
/* Flag definitions */
-#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */
-#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */
+#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */
+#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */
#define US_FL_MODE_XLATE 0x00000004 /* translate _6 to _10 comands for
- Win/MacOS compatibility */
-
+ Win/MacOS compatibility */
+#define US_FL_CBI_AS_CB 0x00000008 /* treat a CBI dev as a CB dev */
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index f77296d7f..b9c09f0d8 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -12,7 +12,7 @@
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: usb-uhci.c,v 1.222 2000/03/13 21:18:02 fliegl Exp $
+ * $Id: usb-uhci.c,v 1.228 2000/04/02 19:55:51 acher Exp $
*/
#include <linux/config.h>
@@ -50,6 +50,8 @@
/* This enables an extra UHCI slab for memory debugging */
#define DEBUG_SLAB
+#define VERSTR "$Revision: 1.228 $ time " __TIME__ " " __DATE__
+
#include <linux/usb.h>
#include "usb-uhci.h"
#include "usb-uhci-debug.h"
@@ -116,6 +118,26 @@ void clean_descs(uhci_t *s, int force)
}
}
/*-------------------------------------------------------------------*/
+_static void uhci_switch_timer_int(uhci_t *s)
+{
+
+ if (!list_empty(&s->urb_unlinked)) {
+ s->td1ms->hw.td.status |= TD_CTRL_IOC;
+ }
+ else {
+ s->td1ms->hw.td.status &= ~TD_CTRL_IOC;
+ }
+
+ if (s->timeout_urbs) {
+ s->td32ms->hw.td.status |= TD_CTRL_IOC;
+ }
+ else {
+ s->td32ms->hw.td.status &= ~TD_CTRL_IOC;
+ }
+
+ wmb();
+}
+/*-------------------------------------------------------------------*/
#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
_static void enable_desc_loop(uhci_t *s, urb_t *urb)
{
@@ -162,6 +184,9 @@ _static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
#endif
((urb_priv_t*)urb->hcpriv)->started=jiffies;
list_add (p, &s->urb_list);
+ if (urb->timeout)
+ s->timeout_urbs++;
+ uhci_switch_timer_int(s);
}
/*-------------------------------------------------------------------*/
_static void queue_urb (uhci_t *s, urb_t *urb)
@@ -185,6 +210,9 @@ _static void dequeue_urb (uhci_t *s, urb_t *urb)
#endif
list_del (&urb->urb_list);
+ if (urb->timeout && s->timeout_urbs)
+ s->timeout_urbs--;
+
}
/*-------------------------------------------------------------------*/
_static int alloc_td (uhci_desc_t ** new, int flags)
@@ -439,6 +467,13 @@ _static void cleanup_skel (uhci_t *s)
clean_descs(s,1);
+
+ if (s->td32ms) {
+
+ unlink_td(s,s->td32ms,1);
+ delete_desc(s->td32ms);
+ }
+
for (n = 0; n < 8; n++) {
td = s->int_chain[n];
clean_td_chain (td);
@@ -531,8 +566,9 @@ _static int init_skel (uhci_t *s)
if (ret)
goto init_skel_cleanup;
- fill_td (td, TD_CTRL_IOC, 0, 0); // generate 1ms interrupt
+ fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
insert_td (s, qh, td, 0);
+ s->td1ms=td;
dbg("allocating qh: bulk_chain");
ret = alloc_qh (&qh);
@@ -597,6 +633,16 @@ _static int init_skel (uhci_t *s)
((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]);
}
+ ret = alloc_td (&td, 0);
+
+ if (ret)
+ goto init_skel_cleanup;
+
+ fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt
+ s->td32ms=td;
+
+ insert_td_horizontal (s, s->int_chain[5], td);
+
mb();
//uhci_show_queue(s->control_chain);
dbg("init_skel exit");
@@ -995,6 +1041,7 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
if (urb->status == -EINPROGRESS) {
// URB probably still in work
dequeue_urb (s, urb);
+ uhci_switch_timer_int(s);
s->unlink_urb_done=1;
spin_unlock_irqrestore (&s->urb_list_lock, flags);
@@ -1125,9 +1172,11 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
if (urb->status == -EINPROGRESS) {
((urb_priv_t*)urb->hcpriv)->started = ~0;
+
dequeue_urb (s, urb);
list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
-
+ uhci_switch_timer_int(s);
+
s->unlink_urb_done = 1;
urb->status = -ECONNABORTED; // mark urb as "waiting to be killed"
@@ -1495,7 +1544,7 @@ _static int uhci_submit_urb (urb_t *urb)
(!(urb->transfer_flags & USB_QUEUE_BULK) || !(bulk_urb->transfer_flags & USB_QUEUE_BULK)))) {
spin_unlock_irqrestore (&s->urb_list_lock, flags);
usb_dec_dev_use (urb->dev);
- err("ENXIO1 %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,bulk_urb);
+ err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,bulk_urb);
return -ENXIO; // urb already queued
}
}
@@ -1599,6 +1648,7 @@ _static void uhci_check_timeouts(uhci_t *s)
#endif
}
+ s->timeout_check=jiffies;
}
/*-------------------------------------------------------------------
@@ -1922,7 +1972,7 @@ _static int rh_submit_urb (urb_t *urb)
OK (len);
case (0x03): /* string descriptors */
len = usb_root_hub_string (wValue & 0xff,
- uhci->io_addr, "UHCI",
+ uhci->io_addr, "UHCI",
data, wLength);
if (len > 0) {
OK (min (leni, len));
@@ -2481,15 +2531,15 @@ restart:
goto restart;
}
}
- if ((s->frame_counter & 63) == 0)
+ if ((jiffies - s->timeout_check) > (HZ/30))
uhci_check_timeouts(s);
clean_descs(s,0);
uhci_cleanup_unlink(s, 0);
-
+ uhci_switch_timer_int(s);
+
spin_unlock (&s->urb_list_lock);
- s->frame_counter++;
outw (status, io_addr + USBSTS);
//dbg("uhci_interrupt: done");
@@ -2630,12 +2680,14 @@ _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_add
spin_lock_init (&s->qh_lock);
spin_lock_init (&s->td_lock);
atomic_set(&s->avoid_bulk, 0);
+ s->timeout_urbs = 0;
s->irq = -1;
s->io_addr = io_addr;
s->io_size = io_size;
s->next = devs; //chain new uhci device into global list
- s->frame_counter = 0;
-
+ s->timeout_check = 0;
+ s->uhci_pci=dev;
+
bus = usb_alloc_bus (&uhci_device_operations);
if (!bus) {
kfree (s);
@@ -2739,6 +2791,7 @@ _static int __init start_uhci (struct pci_dev *dev)
info("Intel USB controller: setting latency timer to %d", UHCI_LATENCY_TIMER);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, UHCI_LATENCY_TIMER);
}
+
return alloc_uhci(dev, dev->irq, io_addr, io_size);
}
return -1;
diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h
index 93173f2c2..3c5717d1e 100644
--- a/drivers/usb/usb-uhci.h
+++ b/drivers/usb/usb-uhci.h
@@ -2,10 +2,9 @@
#define __LINUX_UHCI_H
/*
- $Id: usb-uhci.h,v 1.50 2000/03/13 21:18:04 fliegl Exp $
+ $Id: usb-uhci.h,v 1.54 2000/04/02 19:55:53 acher Exp $
*/
#define MODNAME "usb-uhci"
-#define VERSTR "$Revision: 1.50 $ time " __TIME__ " " __DATE__
#define UHCI_LATENCY_TIMER 0
static __inline__ void uhci_wait_ms(unsigned int ms)
@@ -202,6 +201,8 @@ typedef struct uhci {
uhci_desc_t *control_chain;
uhci_desc_t *bulk_chain;
uhci_desc_t *chain_end;
+ uhci_desc_t *td1ms;
+ uhci_desc_t *td32ms;
struct list_head free_desc;
spinlock_t qh_lock;
spinlock_t td_lock;
@@ -209,7 +210,9 @@ typedef struct uhci {
int loop_usage; // URBs using bandwidth reclamation
struct list_head urb_unlinked; // list of all unlinked urbs
- int frame_counter;
+ long timeout_check;
+ int timeout_urbs;
+ struct pci_dev *uhci_pci;
} uhci_t, *puhci_t;
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 9b2d38b6f..8f962b485 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -24,7 +24,11 @@
#include <linux/bitops.h>
#include <linux/malloc.h>
#include <linux/interrupt.h> /* for in_interrupt() */
-#define DEBUG
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
/*
@@ -1080,7 +1084,7 @@ int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor
int size;
struct usb_descriptor_header *header;
- memcpy(config, buffer, USB_DT_INTERFACE_SIZE);
+ memcpy(config, buffer, USB_DT_CONFIG_SIZE);
le16_to_cpus(&config->wTotalLength);
size = config->wTotalLength;
@@ -1419,32 +1423,28 @@ int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
static void usb_set_maxpacket(struct usb_device *dev)
{
- int i, j, b;
- struct usb_interface *ifp;
+ int i, b;
for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
- ifp = dev->actconfig->interface + i;
-
- for (j = 0; j < ifp->num_altsetting; j++) {
- struct usb_interface_descriptor *as = ifp->altsetting + j;
- struct usb_endpoint_descriptor *ep = as->endpoint;
- int e;
-
- for (e=0; e<as->bNumEndpoints; e++) {
- b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
+ struct usb_interface *ifp = dev->actconfig->interface + i;
+ struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting;
+ struct usb_endpoint_descriptor *ep = as->endpoint;
+ int e;
+
+ for (e=0; e<as->bNumEndpoints; e++) {
+ b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
+ dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+ dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
+ }
+ else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
+ if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+ }
+ else {
+ if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
- }
- else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
- if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
- dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
- }
- else {
- if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
- dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
- }
}
}
}
@@ -1512,6 +1512,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
return ret;
iface->act_altsetting = alternate;
+ dev->toggle[0] = 0; /* 9.1.1.5 says to do this */
+ dev->toggle[1] = 0;
usb_set_maxpacket(dev);
return 0;
}
@@ -1624,7 +1626,7 @@ int usb_get_configuration(struct usb_device *dev)
err("config descriptor too short (expected %i, got %i)",tmp,result);
kfree(bigbuffer);
goto err;
- }
+ }
result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
kfree(bigbuffer);
@@ -1638,8 +1640,8 @@ int usb_get_configuration(struct usb_device *dev)
}
return 0;
- err:
- dev->descriptor.bNumConfigurations=cfgno;
+err:
+ dev->descriptor.bNumConfigurations = cfgno;
return result;
}
@@ -1674,7 +1676,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
dev->have_langid = -1;
dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
/* always use the first langid listed */
- info("USB device number %d default language ID 0x%x",
+ dbg("USB device number %d default language ID 0x%x",
dev->devnum, dev->string_langid);
}
}
@@ -1789,14 +1791,16 @@ int usb_new_device(struct usb_device *dev)
return -1;
}
- info("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
+ dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+#ifdef DEBUG
if (dev->descriptor.iManufacturer)
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
if (dev->descriptor.iProduct)
usb_show_string(dev, "Product", dev->descriptor.iProduct);
if (dev->descriptor.iSerialNumber)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
+#endif
/* now that the basic setup is over, add a /proc/bus/usb entry */
usbdevfs_add_device(dev);
@@ -1874,6 +1878,7 @@ 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_reset_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
EXPORT_SYMBOL(usb_release_bandwidth);
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 2b46f14d9..4c8aa7dd8 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -33,6 +33,9 @@ if [ "$CONFIG_FB" = "y" ]; then
if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
tristate ' Cyber2000 support' CONFIG_FB_CYBER2000
fi
+ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+ bool ' SA-1100 LCD support' CONFIG_FB_SA1100
+ fi
if [ "$CONFIG_APOLLO" = "y" ]; then
define_bool CONFIG_FB_APOLLO y
fi
@@ -193,12 +196,12 @@ if [ "$CONFIG_FB" = "y" ]; then
fi
fi
if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
- "$CONFIG_FB_VIRTUAL" = "y" ]; then
+ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
define_tristate CONFIG_FBCON_CFB2 y
define_tristate CONFIG_FBCON_CFB4 y
else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
- "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
define_tristate CONFIG_FBCON_CFB2 m
define_tristate CONFIG_FBCON_CFB4 m
fi
@@ -217,7 +220,7 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
"$CONFIG_FB_RIVA" = "y" -o \
"$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
- "$CONFIG_FB_3DFX" = "y" ]; then
+ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then
define_tristate CONFIG_FBCON_CFB8 y
else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -232,7 +235,8 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
"$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
"$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
- "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
+ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
+ "$CONFIG_FB_SA1100" = "m" ]; then
define_tristate CONFIG_FBCON_CFB8 m
fi
fi
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 49125330f..2cebdad61 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -46,7 +46,8 @@ obj-$(CONFIG_FONT_6x11) += font_6x11.o
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
+# Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x
+obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o
obj-$(CONFIG_FB_COMPAT_XPMAC) += macmodes.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
@@ -111,6 +112,7 @@ endif
obj-$(CONFIG_FB_SUN3) += sun3fb.o
obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
obj-$(CONFIG_FB_HGA) += hgafb.o
+obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
# Generic Low Level Drivers
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index a0518c009..727815e0c 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -2415,11 +2415,13 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
par->crsr.spot_x = par->crsr.spot_y = 0;
par->crsr.height = par->crsr.width = 0;
+#if 0 /* fbmon not done. uncomment for 2.5.x -brad */
if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal,
&fb_info)) {
DPRINTK("mode doesn't fit for monitor\n");
return -EINVAL;
}
+#endif
return 0;
}
diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c
index 50c1f0bda..496363a6b 100644
--- a/drivers/video/aty128fb.c
+++ b/drivers/video/aty128fb.c
@@ -1210,7 +1210,7 @@ aty128_set_par(struct aty128fb_par *par,
if (par->accel_flags & FB_ACCELF_TEXT)
aty128_init_engine(par, info);
-#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0/*def CONFIG_FB_COMPAT_XPMAC*/
#if 0 /* use this when macmodes gets updated */
if (!console_fb_info || console_fb_info == &info->fb_info) {
disp_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1;
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index b2efe721f..cdacf23a4 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -2539,7 +2539,7 @@ static int atyfb_decode_var(const struct fb_var_screeninfo *var,
else
par->accel_flags = 0;
-#if 0
+#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info))
return -EINVAL;
#endif
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index a63b4fd2c..556411670 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -98,6 +98,8 @@ extern int valkyriefb_setup(char*);
extern int control_init(void);
extern int control_setup(char*);
extern int g364fb_init(void);
+extern void sa1100fb_init(void);
+extern void sa1100fb_setup(char*);
extern int fm2fb_init(void);
extern int fm2fb_setup(char*);
extern int q40fb_init(void);
@@ -216,6 +218,9 @@ static struct {
#ifdef CONFIG_FB_G364
{ "g364", g364fb_init, NULL },
#endif
+#ifdef CONFIG_FB_SA1100
+ { "sa1100", sa1100fb_init, sa1100fb_setup },
+#endif
#ifdef CONFIG_FB_FM2
{ "fm2fb", fm2fb_init, fm2fb_setup },
#endif
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
new file mode 100644
index 000000000..39e518fa5
--- /dev/null
+++ b/drivers/video/sa1100fb.c
@@ -0,0 +1,1147 @@
+/*
+ * linux/drivers/video/sa1100fb.c -- StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ * Copyright (C) 1999 Eric A. Thomas
+ *
+ * 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.
+ *
+ */
+
+
+/*
+ * Code Status:
+ * 4/1/99 - Driver appears to be working for Brutus 320x200x8bpp mode. Other
+ * resolutions are working, but only the 8bpp mode is supported.
+ * Changes need to be made to the palette encode and decode routines
+ * to support 4 and 16 bpp modes.
+ * Driver is not designed to be a module. The FrameBuffer is statically
+ * allocated since dynamic allocation of a 300k buffer cannot be guaranteed.
+ *
+ * 6/17/99 - FrameBuffer memory is now allocated at run-time when the
+ * driver is initialized.
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/proc/pgtable.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+
+/*
+ * Debug macros
+ */
+// #define DEBUG
+#ifdef DEBUG
+# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+# define DPRINTK(fmt, args...)
+#endif
+
+
+/*
+ * The MAX_x defines are used to specify the maximum ranges for
+ * parameters that affect the size of the frame buffer memory
+ * region. Since the frame buffer memory is not dynamically
+ * alocated, the maximum size that will be used is allocated.
+ */
+#if defined (CONFIG_SA1100_PENNY)
+
+#define MAX_BITS_PER_PIXEL 8
+#define MAX_SCREEN_SIZE_H 640
+#define MAX_SCREEN_SIZE_V 480
+
+#elif defined(CONFIG_SA1100_BRUTUS)
+
+#define MAX_BITS_PER_PIXEL 8
+#define MAX_SCREEN_SIZE_H 320
+#define MAX_SCREEN_SIZE_V 240
+
+#elif defined (CONFIG_SA1100_THINCLIENT)
+
+#define MAX_BITS_PER_PIXEL 8
+/*#define MAX_BITS_PER_PIXEL 16*/
+
+#define MAX_SCREEN_SIZE_H 640
+#define MAX_SCREEN_SIZE_V 480
+
+#elif defined(CONFIG_SA1100_TIFON)
+
+#define MAX_BITS_PER_PIXEL 4
+#define MAX_SCREEN_SIZE_H 640
+#define MAX_SCREEN_SIZE_V 200
+
+#define REVERSE_VIDEO_4BIT
+
+#elif defined(CONFIG_SA1100_LART)
+
+#define MAX_BITS_PER_PIXEL 4
+#define MAX_SCREEN_SIZE_H 320
+#define MAX_SCREEN_SIZE_V 240
+
+#endif
+
+/* Default resolutions */
+#if defined(CONFIG_SA1100_PENNY)
+#define DEFAULT_XRES 640
+#define DEFAULT_YRES 480
+#define DEFAULT_BPP 8
+#else
+#define DEFAULT_XRES MAX_SCREEN_SIZE_H
+#define DEFAULT_YRES MAX_SCREEN_SIZE_V
+#define DEFAULT_BPP MAX_BITS_PER_PIXEL
+#endif
+
+/* Memory size macros for determining required FrameBuffer size */
+#define MAX_PALETTE_NUM_ENTRIES 256
+#define ADJUSTED_MAX_BITS_PER_PIXEL (MAX_BITS_PER_PIXEL > 8 ? 16 : MAX_BITS_PER_PIXEL)
+#define MAX_PALETTE_MEM_SIZE (MAX_PALETTE_NUM_ENTRIES * 2)
+#define MAX_PIXEL_MEM_SIZE ((MAX_SCREEN_SIZE_H * MAX_SCREEN_SIZE_V * ADJUSTED_MAX_BITS_PER_PIXEL ) / 8)
+#define MAX_FRAMEBUFFER_MEM_SIZE (MAX_PIXEL_MEM_SIZE + MAX_PALETTE_MEM_SIZE + 32)
+#define ALLOCATED_FB_MEM_SIZE (PAGE_ALIGN (MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2))
+
+#define SA1100_PALETTE_MEM_SIZE(bpp) (((bpp)==8?256:16)*2)
+#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9)
+
+/* Minimum X and Y resolutions */
+#define MIN_XRES 64
+#define MIN_YRES 64
+
+/* Possible controller_state modes */
+#define LCD_MODE_DISABLED 0 // Controller is disabled and Disable Done received
+#define LCD_MODE_DISABLE_BEFORE_ENABLE 1 // Re-enable after Disable Done IRQ is received
+#define LCD_MODE_ENABLED 2 // Controller is enabled
+
+#define SA1100_NAME "SA1100"
+#define NR_MONTYPES 1
+
+static u_char *VideoMemRegion = NULL;
+static u_char *VideoMemRegion_phys = NULL;
+
+/* Local LCD controller parameters */
+/* These can be reduced by making better use of fb_var_screeninfo parameters. */
+/* Several duplicates exist in the two structures. */
+struct sa1100fb_par {
+ u_char *p_screen_base;
+ u_char *v_screen_base;
+ u_short *p_palette_base;
+ u_short *v_palette_base;
+ unsigned long screen_size;
+ unsigned int palette_size;
+ unsigned int xres;
+ unsigned int yres;
+ unsigned int xres_virtual;
+ unsigned int yres_virtual;
+ unsigned int bits_per_pixel;
+ signed int montype;
+ unsigned int currcon;
+ unsigned int visual;
+ unsigned int allow_modeset : 1;
+ unsigned int active_lcd : 1;
+ volatile u_char controller_state;
+};
+
+/* Shadows for LCD controller registers */
+struct sa1100fb_lcd_reg {
+ Address dbar1;
+ Word lccr0;
+ Word lccr1;
+ Word lccr2;
+ Word lccr3;
+};
+
+/* Fake monspecs to fill in fbinfo structure */
+static struct fb_monspecs monspecs __initdata = {
+ 30000, 70000, 50, 65, 0 /* Generic */
+};
+
+static struct display global_disp; /* Initial (default) Display Settings */
+static struct fb_info fb_info;
+static struct sa1100fb_par current_par;
+static struct fb_var_screeninfo __initdata init_var = {};
+static struct sa1100fb_lcd_reg lcd_shadow;
+
+
+static int sa1100fb_open(struct fb_info *info, int user);
+static int sa1100fb_release(struct fb_info *info, int user);
+static int sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);
+static int sa1100fb_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info);
+static int sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+static int sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+static int sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
+static int sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
+static int sa1100fb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+
+static int sa1100fb_switch(int con, struct fb_info *info);
+static void sa1100fb_blank(int blank, struct fb_info *info);
+static int sa1100fb_map_video_memory(void);
+static int sa1100fb_activate_var(struct fb_var_screeninfo *var);
+static void sa1100fb_enable_lcd_controller(void);
+static void sa1100fb_disable_lcd_controller(void);
+
+static struct fb_ops sa1100fb_ops = {
+ sa1100fb_open,
+ sa1100fb_release,
+ sa1100fb_get_fix,
+ sa1100fb_get_var,
+ sa1100fb_set_var,
+ sa1100fb_get_cmap,
+ sa1100fb_set_cmap,
+ sa1100fb_pan_display,
+ sa1100fb_ioctl
+};
+
+
+
+/*
+ * sa1100fb_palette_write:
+ * Write palette data to the LCD frame buffer's palette area
+ */
+static inline void
+sa1100fb_palette_write(u_int regno, u_short pal)
+{
+ current_par.v_palette_base[regno] = (regno ? pal : pal |
+ SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel));
+}
+
+
+static inline u_short
+sa1100fb_palette_encode(u_int regno, u_int red, u_int green, u_int blue, u_int trans)
+{
+ u_short pal;
+
+
+ if(current_par.bits_per_pixel == 4){
+ /*
+ * RGB -> luminance is defined to be
+ * Y = 0.299 * R + 0.587 * G + 0.114 * B
+ */
+ pal = ((19595 * red + 38470 * green + 7471 * blue) >> 28) & 0x00f;
+#ifdef REVERSE_VIDEO_4BIT
+ pal = 15 - pal;
+#endif
+ }
+ else{
+ pal = ((red >> 4) & 0xf00);
+ pal |= ((green >> 8) & 0x0f0);
+ pal |= ((blue >> 12) & 0x00f);
+ }
+
+ return pal;
+}
+
+static inline u_short
+sa1100fb_palette_read(u_int regno)
+{
+ return (current_par.v_palette_base[regno] & 0x0FFF);
+}
+
+
+static void
+sa1100fb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans)
+{
+ u_short pal;
+
+ pal = sa1100fb_palette_read(regno);
+
+ if( current_par.bits_per_pixel == 4){
+#ifdef REVERSE_VIDEO_4BIT
+ pal = 15 - pal;
+#endif
+ pal &= 0x000f;
+ pal |= pal << 4;
+ pal |= pal << 8;
+ *blue = *green = *red = pal;
+ }
+ else{
+ *blue = (pal & 0x000f) << 12;
+ *green = (pal & 0x00f0) << 8;
+ *red = (pal & 0x0f00) << 4;
+ }
+ *trans = 0;
+}
+
+static int
+sa1100fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info)
+{
+ if (regno >= current_par.palette_size)
+ return 1;
+
+ sa1100fb_palette_decode(regno, red, green, blue, trans);
+
+ return 0;
+}
+
+
+static int
+sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info)
+{
+ u_short pal;
+
+ if (regno >= current_par.palette_size)
+ return 1;
+
+ pal = sa1100fb_palette_encode(regno, red, green, blue, trans);
+
+ sa1100fb_palette_write(regno, pal);
+
+ return 0;
+}
+
+static int
+sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err = 0;
+
+ if (con == current_par.currcon)
+ err = fb_get_cmap(cmap, kspc, sa1100fb_getcolreg, info);
+ else if (fb_display[con].cmap.len)
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(current_par.palette_size),
+ cmap, kspc ? 0 : 2);
+ return err;
+}
+
+static int
+sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err = 0;
+
+ if (!fb_display[con].cmap.len)
+ err = fb_alloc_cmap(&fb_display[con].cmap,
+
+ current_par.palette_size, 0);
+ if (!err) {
+ if (con == current_par.currcon)
+ err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg,
+ info);
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ }
+ return err;
+}
+
+static void inline
+sa1100fb_get_par(struct sa1100fb_par *par)
+{
+ *par = current_par;
+}
+
+
+/*
+ * sa1100fb_encode_var():
+ * Modify var structure using values in par
+ */
+static int
+sa1100fb_encode_var(struct fb_var_screeninfo *var,
+ struct sa1100fb_par *par)
+{
+ // Don't know if really want to var on entry.
+ // Look at set_var to see. If so, may need to add extra params to par
+// memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+ var->xres = par->xres;
+ var->yres = par->yres;
+ var->xres_virtual = par->xres_virtual;
+ var->yres_virtual = par->yres_virtual;
+
+ var->bits_per_pixel = par->bits_per_pixel;
+
+ switch(var->bits_per_pixel) {
+ case 2:
+ case 4:
+ case 8:
+ var->red.length = 4;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.length = 0;
+ break;
+ case 12: // This case should differ for Active/Passive mode
+ case 16:
+ var->red.length =
+ var->blue.length =
+ var->green.length = 5;
+ var->transp.length = 0;
+ var->red.offset = 10;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->transp.offset = 0;
+ break;
+ }
+ return 0;
+}
+
+/*
+ * sa1100fb_decode_var():
+ * Get the video params out of 'var'. If a value doesn't fit, round it up,
+ * if it's too big, return -EINVAL.
+ *
+ * Suggestion: Round up in the following order: bits_per_pixel, xres,
+ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ * bitfields, horizontal timing, vertical timing.
+ */
+static int
+sa1100fb_decode_var(struct fb_var_screeninfo *var,
+ struct sa1100fb_par *par)
+{
+ u_long palette_mem_phys;
+ u_long palette_mem_size;
+
+ *par = current_par;
+
+ if ((par->xres = var->xres) < MIN_XRES)
+ par->xres = MIN_XRES;
+ if ((par->yres = var->yres) < MIN_YRES)
+ par->yres = MIN_YRES;
+ if (par->xres > MAX_SCREEN_SIZE_H)
+ par->xres = MAX_SCREEN_SIZE_H;
+ if (par->yres > MAX_SCREEN_SIZE_V)
+ par->yres = MAX_SCREEN_SIZE_V;
+ par->xres_virtual =
+ var->xres_virtual < par->xres ? par->xres : var->xres_virtual;
+ par->yres_virtual =
+ var->yres_virtual < par->yres ? par->yres : var->yres_virtual;
+ par->bits_per_pixel = var->bits_per_pixel;
+
+ switch (par->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ par->visual = FB_VISUAL_PSEUDOCOLOR;
+ par->palette_size = 16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ par->visual = FB_VISUAL_PSEUDOCOLOR;
+ par->palette_size = 256;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16: /* RGB 555 */
+ par->visual = FB_VISUAL_TRUECOLOR;
+ par->palette_size = -1;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ palette_mem_size = SA1100_PALETTE_MEM_SIZE(par->bits_per_pixel);
+ palette_mem_phys = (u_long)VideoMemRegion_phys + PAGE_SIZE -
+ palette_mem_size;
+ par->p_palette_base = (u_short *)palette_mem_phys;
+ par->v_palette_base = (u_short *)((u_long)VideoMemRegion + PAGE_SIZE - palette_mem_size);
+ par->p_screen_base = (u_char *)((u_long)VideoMemRegion_phys + PAGE_SIZE);
+ par->v_screen_base = (u_char *)((u_long)VideoMemRegion + PAGE_SIZE);
+
+ DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base);
+ DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base);
+ DPRINTK("p_screen_base = 0x%08lx\n",(u_long)par->p_screen_base);
+ DPRINTK("v_screen_base = 0x%08lx\n",(u_long)par->v_screen_base);
+ DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion);
+ DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys);
+ return 0;
+}
+
+static int
+sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+ struct sa1100fb_par par;
+
+ if (con == -1) {
+ sa1100fb_get_par(&par);
+ sa1100fb_encode_var(var, &par);
+ } else
+ *var = fb_display[con].var;
+
+ return 0;
+}
+
+/*
+ * sa1100fb_set_var():
+ * Set the user defined part of the display for the specified console
+ */
+static int
+sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+ struct display *display;
+ int err, chgvar = 0;
+ struct sa1100fb_par par;
+
+ if (con >= 0)
+ display = &fb_display[con]; /* Display settings for console */
+ else
+ display = &global_disp; /* Default display settings */
+
+
+ DPRINTK("xres = %d, yres = %d\n",var->xres, var->yres);
+ // Decode var contents into a par structure, adjusting any
+ // out of range values.
+ if ((err = sa1100fb_decode_var(var, &par)))
+ return err;
+ // Store adjusted par values into var structure
+ sa1100fb_encode_var(var, &par);
+
+ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+ return 0;
+ else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) &&
+ ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN))
+ return -EINVAL;
+
+ if (con >= 0) {
+ if ((display->var.xres != var->xres) ||
+ (display->var.yres != var->yres) ||
+ (display->var.xres_virtual != var->xres_virtual) ||
+ (display->var.yres_virtual != var->yres_virtual) ||
+ (display->var.sync != var->sync) ||
+ (display->var.bits_per_pixel != var->bits_per_pixel) ||
+ (memcmp(&display->var.red, &var->red, sizeof(var->red))) ||
+ (memcmp(&display->var.green, &var->green, sizeof(var->green))) ||
+ (memcmp(&display->var.blue, &var->blue, sizeof(var->blue))))
+ chgvar = 1;
+ }
+
+ display->var = *var;
+ display->screen_base = par.v_screen_base;
+ display->visual = par.visual;
+ display->type = FB_TYPE_PACKED_PIXELS;
+ display->type_aux = 0;
+ display->ypanstep = 0;
+ display->ywrapstep = 0;
+ display->line_length =
+ display->next_line = (var->xres * var->bits_per_pixel) / 8;
+
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+
+ switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ display->dispsw = &fbcon_cfb4;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ display->dispsw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+ default:
+ display->dispsw = &fbcon_dummy;
+ break;
+ }
+
+ // If the console has changed and the console has defined
+ // a changevar function, call that function.
+ if (chgvar && info && info->changevar)
+ info->changevar(con);
+
+ // If the current console is selected, update the palette
+ if (con == current_par.currcon)
+ {
+ struct fb_cmap *cmap;
+
+ current_par = par;
+ if (display->cmap.len)
+ cmap = &display->cmap;
+ else
+ cmap = fb_default_cmap(current_par.palette_size);
+
+ fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info);
+
+ sa1100fb_activate_var(var);
+ }
+ return 0;
+}
+
+static int
+sa1100fb_updatevar(int con, struct fb_info *info)
+{
+ DPRINTK("entered\n");
+ return 0;
+}
+
+static int
+sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+ struct display *display;
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, SA1100_NAME);
+
+ if (con >= 0)
+ {
+ DPRINTK("Using console specific display for con=%d\n",con);
+ display = &fb_display[con]; /* Display settings for console */
+ }
+ else
+ display = &global_disp; /* Default display settings */
+
+ fix->smem_start = current_par.p_screen_base;
+ fix->smem_len = current_par.screen_size;
+ fix->type = display->type;
+ fix->type_aux = display->type_aux;
+ fix->xpanstep = 0;
+ fix->ypanstep = display->ypanstep;
+ fix->ywrapstep = display->ywrapstep;
+ fix->visual = display->visual;
+ fix->line_length = display->line_length;
+ fix->accel = FB_ACCEL_NONE;
+
+ return 0;
+}
+
+
+static void
+__init sa1100fb_init_fbinfo(void)
+{
+ strcpy(fb_info.modename, SA1100_NAME);
+ strcpy(fb_info.fontname, "Acorn8x8");
+
+ fb_info.node = -1;
+ fb_info.flags = FBINFO_FLAG_DEFAULT;
+ fb_info.fbops = &sa1100fb_ops;
+ fb_info.monspecs = monspecs;
+ fb_info.disp = &global_disp;
+ fb_info.changevar = NULL;
+ fb_info.switch_con = sa1100fb_switch;
+ fb_info.updatevar = sa1100fb_updatevar;
+ fb_info.blank = sa1100fb_blank;
+
+ /*
+ * setup initial parameters
+ */
+ memset(&init_var, 0, sizeof(init_var));
+
+ init_var.xres = DEFAULT_XRES;
+ init_var.yres = DEFAULT_YRES;
+ init_var.xres_virtual = init_var.xres;
+ init_var.yres_virtual = init_var.yres;
+ init_var.xoffset = 0;
+ init_var.yoffset = 0;
+ init_var.bits_per_pixel = DEFAULT_BPP;
+
+ init_var.transp.length = 0;
+ init_var.nonstd = 0;
+ init_var.activate = FB_ACTIVATE_NOW;
+ init_var.height = -1;
+ init_var.width = -1;
+ init_var.vmode = FB_VMODE_NONINTERLACED;
+
+#if defined(CONFIG_SA1100_PENNY)
+ init_var.red.length = 4;
+ init_var.green = init_var.red;
+ init_var.blue = init_var.red;
+ init_var.sync = 0;
+#elif defined(CONFIG_SA1100_BRUTUS)
+ init_var.red.length = 4;
+ init_var.green = init_var.red;
+ init_var.blue = init_var.red;
+ init_var.sync = 0;
+#elif defined(CONFIG_SA1100_THINCLIENT)
+ init_var.red.length = 4;
+ init_var.green = init_var.red;
+ init_var.blue = init_var.red;
+ init_var.sync = 0;
+#elif defined(CONFIG_SA1100_TIFON)
+ init_var.red.length = 4;
+ init_var.green = init_var.red;
+ init_var.blue = init_var.red;
+ init_var.grayscale = 1;
+ init_var.pixclock = 150000;
+ init_var.left_margin = 20;
+ init_var.right_margin = 255;
+ init_var.upper_margin = 20;
+ init_var.lower_margin = 0;
+ init_var.hsync_len = 2;
+ init_var.vsync_len = 1;
+ init_var.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
+ init_var.vmode = 0;
+#elif defined(CONFIG_SA1100_LART)
+ init_var.red.length = 4;
+ init_var.green = init_var.red;
+ init_var.blue = init_var.red;
+ init_var.grayscale = 1;
+ init_var.pixclock = 150000;
+ init_var.sync = 0;
+#endif
+
+ current_par.montype = -1;
+ current_par.currcon = -1;
+ current_par.allow_modeset = 1;
+ current_par.controller_state = LCD_MODE_DISABLED;
+}
+
+
+
+/*
+ * sa1100fb_map_video_memory():
+ * Allocates the DRAM memory for the frame buffer. This buffer is
+ * remapped into a non-cached, non-buffered, memory region to
+ * allow palette and pixel writes to occur without flushing the
+ * cache. Once this area is remapped, all virtual memory
+ * access to the video memory should occur at the new region.
+ */
+static int
+__init sa1100fb_map_video_memory(void)
+{
+ u_int required_pages;
+ u_int extra_pages;
+ u_int order;
+ u_int i;
+ char *allocated_region;
+
+ if (VideoMemRegion != NULL)
+ return -EINVAL;
+
+ /* Find order required to allocate enough memory for framebuffer */
+ required_pages = ALLOCATED_FB_MEM_SIZE >> PAGE_SHIFT;
+ for (order = 0 ; required_pages >> order ; order++) {;}
+ extra_pages = (1 << order) - required_pages;
+
+ if ((allocated_region =
+ (char *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)) == NULL)
+ return -ENOMEM;
+
+ VideoMemRegion = (u_char *)allocated_region + (extra_pages << PAGE_SHIFT);
+ VideoMemRegion_phys = (u_char *)__virt_to_phys((u_long)VideoMemRegion);
+
+ /* Free all pages that we don't need but were given to us because */
+ /* __get_free_pages() works on powers of 2. */
+ for (;extra_pages;extra_pages--)
+ free_page((u_int)allocated_region + ((extra_pages-1) << PAGE_SHIFT));
+
+ /* Set reserved flag for fb memory to allow it to be remapped into */
+ /* user space by the common fbmem driver using remap_page_range(). */
+ for(i = MAP_NR(VideoMemRegion);
+ i < MAP_NR(VideoMemRegion + ALLOCATED_FB_MEM_SIZE); i++)
+ set_bit(PG_reserved, &mem_map[i].flags);
+
+ /* Remap the fb memory to a non-buffered, non-cached region */
+ VideoMemRegion = (u_char *)__ioremap((u_long)VideoMemRegion_phys,
+ ALLOCATED_FB_MEM_SIZE,
+ L_PTE_PRESENT |
+ L_PTE_YOUNG |
+ L_PTE_DIRTY |
+ L_PTE_WRITE);
+ return (VideoMemRegion == NULL ? -EINVAL : 0);
+}
+
+static const int frequency[16] = {
+ 59000000,
+ 73700000,
+ 88500000,
+ 103200000,
+ 118000000,
+ 132700000,
+ 147500000,
+ 162200000,
+ 176900000,
+ 191700000,
+ 206400000,
+ 230000000,
+ 245000000,
+ 260000000,
+ 275000000,
+ 290000000
+};
+
+
+static int get_pcd(unsigned int pixclock)
+{
+ unsigned int pcd;
+ pcd = frequency[PPCR &0xf] / 1000;
+ pcd *= pixclock/1000;
+ return pcd / 10000000 * 12;
+ /* the last multiplication by 1.2 is to handle */
+ /* sync problems */
+}
+
+/*
+ * sa1100fb_activate_var():
+ * Configures LCD Controller based on entries in var parameter. Settings are
+ * only written to the controller if changes were made.
+ */
+static int
+sa1100fb_activate_var(struct fb_var_screeninfo *var)
+{
+ u_long flags;
+ int pcd = get_pcd(var->pixclock);
+
+ if (current_par.p_palette_base == NULL)
+ return -EINVAL;
+
+ /* Disable interrupts and save status */
+ save_flags_cli(flags); // disable the interrupts and save flags
+
+ /* Reset the LCD Controller's DMA address if it has changed */
+ lcd_shadow.dbar1 = (Address)current_par.p_palette_base;
+
+#if defined(CONFIG_SA1100_PENNY)
+ DPRINTK("Configuring SA1100 LCD\n");
+
+ DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres);
+
+ lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ lcd_shadow.lccr1 = LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth (65) +
+ LCCR1_EndLnDel (43) + LCCR1_BegLnDel(43) ;
+ lcd_shadow.lccr2 = LCCR2_DisHght (var->yres) + LCCR2_VrtSnchWdth (35) +
+ LCCR2_EndFrmDel (0) + LCCR2_BegFrmDel (0) ;
+ lcd_shadow.lccr3 = LCCR3_PixClkDiv(16) +
+ LCCR3_ACBsDiv (2) + LCCR3_ACBsCntOff +
+ ((var->sync & FB_SYNC_HOR_HIGH_ACT) ?LCCR3_HorSnchH:LCCR3_HorSnchL) +
+ ((var->sync & FB_SYNC_VERT_HIGH_ACT)?LCCR3_VrtSnchH:LCCR3_VrtSnchL);
+
+#elif defined(CONFIG_SA1100_BRUTUS)
+ DPRINTK("Configuring BRUTUS LCD\n");
+ lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ lcd_shadow.lccr1 = LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) +
+ LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+ lcd_shadow.lccr2 = LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+ lcd_shadow.lccr3 = LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + LCCR3_HorSnchH +
+ LCCR3_ACBsCntOff + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
+#elif defined(CONFIG_SA1100_THINCLIENT)
+ DPRINTK("Configuring ThinClient LCD\n");
+ DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres);
+
+ lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+ LCCR0_Act;
+ lcd_shadow.lccr1 = LCCR1_DisWdth(var->xres) +LCCR1_HorSnchWdth(10)+
+ LCCR1_EndLnDel (81) + LCCR1_BegLnDel(81) ;
+ lcd_shadow.lccr2 = LCCR2_DisHght (var->yres) +LCCR2_VrtSnchWdth(9) +
+ LCCR2_EndFrmDel (20) + LCCR2_BegFrmDel (20) ;
+ lcd_shadow.lccr3 = LCCR3_PixClkDiv(6) +
+ LCCR3_ACBsDiv (2) + LCCR3_ACBsCntOff +
+ LCCR3_HorSnchL + LCCR3_VrtSnchL;
+
+#elif defined(CONFIG_SA1100_TIFON)
+ DPRINTK("Configuring TIFON LCD\n");
+
+ lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
+ LCCR0_BigEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_8PixMono + LCCR0_DMADel(0);
+ lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
+ LCCR1_HorSnchWdth( var->hsync_len) +
+ LCCR1_BegLnDel( var->left_margin) +
+ LCCR1_EndLnDel( var->right_margin);
+ lcd_shadow.lccr2 = LCCR2_DisHght( var->yres ) +
+ LCCR2_VrtSnchWdth( var->vsync_len )+
+ LCCR2_BegFrmDel( var->upper_margin ) +
+ LCCR2_EndFrmDel( var->lower_margin );
+ lcd_shadow.lccr3 = LCCR3_PixClkDiv( pcd ) +
+ LCCR3_ACBsDiv( 512 ) +
+ LCCR3_ACBsCnt(0) +
+ LCCR3_HorSnchH + LCCR3_VrtSnchH;
+ /*
+ ((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ?
+ LCCR3_HorSnchH : LCCR3_HorSnchL) +
+ ((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ?
+ LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+ */
+#elif defined(CONFIG_SA1100_LART)
+ DPRINTK("Configuring LART LCD\n");
+
+ lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
+ LCCR1_HorSnchWdth( 2 ) +
+ LCCR1_BegLnDel( 4 ) +
+ LCCR1_EndLnDel( 2 );
+ lcd_shadow.lccr2 = LCCR2_DisHght( var->yres ) +
+ LCCR2_VrtSnchWdth( 1 )+
+ LCCR2_BegFrmDel( 0 ) +
+ LCCR2_EndFrmDel( 0 );
+ lcd_shadow.lccr3 = LCCR3_PixClkDiv( 34 ) +
+ LCCR3_ACBsDiv( 512 ) +
+ LCCR3_ACBsCntOff +
+ LCCR3_HorSnchH +
+ LCCR3_VrtSnchH;
+#endif
+
+ /* Restore status of interrupts */
+ restore_flags(flags);
+
+
+ if (( LCCR0 != lcd_shadow.lccr0 ) ||
+ ( LCCR1 != lcd_shadow.lccr1 ) ||
+ ( LCCR2 != lcd_shadow.lccr2 ) ||
+ ( LCCR3 != lcd_shadow.lccr3 ) ||
+ ( DBAR1 != lcd_shadow.dbar1 ))
+ {
+ sa1100fb_enable_lcd_controller();
+ }
+
+ return 0;
+}
+
+
+/*
+ * sa1100fb_inter_handler():
+ * Interrupt handler for LCD controller. Processes disable done interrupt (LDD)
+ * to reenable controller if controller was disabled to change register values.
+ */
+static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (LCSR & LCSR_LDD) {
+ /* Disable Done Flag is set */
+ LCCR0 |= LCCR0_LDM; /* Mask LCD Disable Done Interrupt */
+ current_par.controller_state = LCD_MODE_DISABLED;
+ if (current_par.controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) {
+ sa1100fb_enable_lcd_controller();
+ }
+ }
+ LCSR = 0; /* Clear LCD Status Register */
+}
+
+
+/*
+ * sa1100fb_disable_lcd_controller():
+ * Disables LCD controller by and enables LDD interrupt. The controller_state
+ * is not changed until the LDD interrupt is received to indicate the current
+ * frame has completed. Platform specific hardware disabling is also included.
+ */
+static void sa1100fb_disable_lcd_controller(void)
+{
+ DPRINTK("sa1100fb: Disabling LCD controller\n");
+
+ /* Exit if already LCD disabled, or LDD IRQ unmasked */
+ if ((current_par.controller_state == LCD_MODE_DISABLED) ||
+ (!(LCCR0 & LCCR0_LDM))) {
+ DPRINTK("sa1100fb: LCD already disabled\n");
+ return;
+ }
+
+#if defined(CONFIG_SA1100_PENNY)
+ FpgaLcdCS1 = 0x000; /* LCD Backlight to 0% */
+ FpgaPortI &= ~LCD_ON; /* Turn off LCD Backlight */
+#elif defined(CONFIG_SA1100_TIFON)
+ GPCR = GPIO_GPIO(24); /* turn off display */
+#endif
+
+ LCSR = 0; /* Clear LCD Status Register */
+ LCCR0 &= ~(LCCR0_LDM); /* Enable LCD Disable Done Interrupt */
+ enable_irq(IRQ_LCD); /* Enable LCD IRQ */
+ LCCR0 &= ~(LCCR0_LEN); /* Disable LCD Controller */
+
+}
+
+/*
+ * sa1100fb_enable_lcd_controller():
+ * Enables LCD controller. If the controller is already enabled, it is first disabled.
+ * This forces all changes to the LCD controller registers to be done when the
+ * controller is disabled. Platform specific hardware enabling is also included.
+ */
+static void sa1100fb_enable_lcd_controller(void)
+{
+ u_long flags;
+
+ save_flags_cli(flags);
+
+ /* Disable controller before changing parameters */
+ if (current_par.controller_state == LCD_MODE_ENABLED) {
+ current_par.controller_state = LCD_MODE_DISABLE_BEFORE_ENABLE;
+ sa1100fb_disable_lcd_controller();
+ } else {
+ DPRINTK("sa1100fb: Enabling LCD controller\n");
+
+ /* Make sure the mode bits are present in the first palette entry */
+ current_par.v_palette_base[0] &= 0x0FFF;
+ current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);
+
+ /* disable the interrupts and save flags */
+ save_flags_cli(flags);
+
+ DBAR1 = lcd_shadow.dbar1;
+ LCCR3 = lcd_shadow.lccr3;
+ LCCR2 = lcd_shadow.lccr2;
+ LCCR1 = lcd_shadow.lccr1;
+ LCCR0 = lcd_shadow.lccr0;
+
+#if defined(CONFIG_SA1100_PENNY)
+ FpgaLcdCS1 = 0x0FF; /* LCD Backlight to 100% */
+ FpgaPortI |= LCD_ON; /* Turn on LCD Backlight */
+#elif defined(CONFIG_SA1100_TIFON)
+ GPCR = GPIO_GPIO(24); /* cycle on/off-switch */
+ udelay(150);
+ GPSR = GPIO_GPIO(24); /* turn on display */
+ udelay(150);
+ GPSR = GPIO_GPIO(24); /* turn on display */
+#endif
+ current_par.controller_state = LCD_MODE_ENABLED;
+
+ /* Restore status of interrupts */
+ }
+ restore_flags(flags);
+}
+
+
+
+static int
+sa1100fb_open(struct fb_info *info, int user)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+sa1100fb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+static int
+sa1100fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ DPRINTK("entered\n");
+ return -EINVAL;
+}
+
+
+/*
+ * sa1100fb_blank():
+ * Blank the display by setting all palette values to zero. Note, the
+ * 12 and 16 bpp modes don't really use the palette, so this will not
+ * blank the display in all modes.
+ */
+static void
+sa1100fb_blank(int blank, struct fb_info *info)
+{
+ int i;
+
+ if (blank) {
+ for (i = 0; i < current_par.palette_size; i++)
+ sa1100fb_palette_write(i, sa1100fb_palette_encode(i, 0, 0, 0, 0));
+ sa1100fb_disable_lcd_controller();
+ }
+ else {
+ sa1100fb_set_cmap(&fb_display[current_par.currcon].cmap, 1,
+ current_par.currcon, info);
+ sa1100fb_enable_lcd_controller();
+ }
+}
+
+
+/*
+ * sa1100fb_switch():
+ * Change to the specified console. Palette and video mode
+ * are changed to the console's stored parameters.
+ */
+static int
+sa1100fb_switch(int con, struct fb_info *info)
+{
+ struct fb_cmap *cmap;
+
+ if (current_par.currcon >= 0) {
+ // Get the colormap for the selected console
+ cmap = &fb_display[current_par.currcon].cmap;
+
+ if (cmap->len)
+ fb_get_cmap(cmap, 1, sa1100fb_getcolreg, info);
+ }
+
+ current_par.currcon = con;
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+ sa1100fb_set_var(&fb_display[con].var, con, info);
+ return 0;
+}
+
+
+void __init sa1100fb_init(void)
+{
+ current_par.p_palette_base = NULL;
+ current_par.v_palette_base = NULL;
+ current_par.p_screen_base = NULL;
+ current_par.v_screen_base = NULL;
+ current_par.palette_size = MAX_PALETTE_NUM_ENTRIES;
+ current_par.screen_size = MAX_PIXEL_MEM_SIZE;
+
+#if defined(CONFIG_SA1100_PENNY)
+ GPDR |= GPIO_GPDR_GFX; /* GPIO Data Direction register for LCD data bits 8-11 */
+ GAFR |= GPIO_GAFR_GFX; /* GPIO Alternate Function register for LCD data bits 8-11 */
+#elif defined(CONFIG_SA1100_TIFON)
+
+ GPDR = GPDR | GPIO_GPIO(24); /* set GPIO24 to output */
+#endif
+
+ /* Initialize video memory */
+ if (sa1100fb_map_video_memory())
+ return;
+
+ sa1100fb_init_fbinfo();
+ if (current_par.montype < 0 || current_par.montype > NR_MONTYPES)
+ current_par.montype = 1;
+
+ /* Request the interrupt in the init routine only because */
+ /* this driver will not be used as a module. */
+ if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL)!= 0) {
+ DPRINTK("sa1100fb: failed in request_irq\n");
+ }
+ DPRINTK("sa1100fb: request_irq succeeded\n");
+ disable_irq(IRQ_LCD);
+
+ if (sa1100fb_set_var(&init_var, -1, &fb_info))
+ current_par.allow_modeset = 0;
+ sa1100fb_decode_var(&init_var, &current_par);
+
+ register_framebuffer(&fb_info);
+
+ /* This driver cannot be unloaded */
+ MOD_INC_USE_COUNT;
+}
+
+void __init sa1100fb_setup(char *options)
+{
+ if (!options || !*options)
+ return;
+
+ return;
+}
+
+
+
+static int
+sa1100fb_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info)
+{
+ return -ENOIOCTLCMD;
+}
+
+
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index c44401939..fcb6443ed 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -362,7 +362,7 @@ static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
var->yres_virtual != var->yres ||
var->nonstd || (1000000000/var->pixclock) > TGA_PLL_MAX_FREQ ||
(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED
-#if 0
+#if 0 /* fbmon not done. uncomment for 2.5.x -brad */
|| !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info))
#else
)
diff --git a/fs/Config.in b/fs/Config.in
index e9eb8099c..53029b7d3 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -10,9 +10,7 @@ tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS
dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_ADFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW
-fi
+dep_mbool ' ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
tristate 'Amiga FFS file system support' CONFIG_AFFS_FS
@@ -28,21 +26,15 @@ dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
tristate 'Compressed ROM file system support' CONFIG_CRAMFS
+tristate 'Simple RAM-based file system support' CONFIG_RAMFS
tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
-if [ "$CONFIG_ISO9660_FS" != "n" ]; then
- bool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET
-else
- # needed by nls/Config.in
- define_bool CONFIG_JOLIET n
-fi
+dep_mbool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS
tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'NTFS file system support (read only)' CONFIG_NTFS_FS
-if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW
-fi
+dep_mbool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL
tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS
@@ -58,44 +50,33 @@ dep_bool ' Debug devfs' CONFIG_DEVFS_DEBUG $CONFIG_DEVFS_FS
dep_bool '/dev/pts file system for Unix98 PTYs' CONFIG_DEVPTS_FS $CONFIG_UNIX98_PTYS
dep_tristate 'QNX4 file system support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_QNX4FS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW
-fi
+dep_mbool ' QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW $CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL
tristate 'ROM file system support' CONFIG_ROMFS_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
tristate 'System V and Coherent file system support (read only)' CONFIG_SYSV_FS
-if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE
-fi
+dep_mbool ' SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL
tristate 'UDF file system support (read only)' CONFIG_UDF_FS
-if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW
-fi
+dep_mbool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW $CONFIG_UDF_FS $CONFIG_EXPERIMENTAL
tristate 'UFS file system support (read only)' CONFIG_UFS_FS
-if [ "$CONFIG_UFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE
-fi
+dep_mbool ' UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL
if [ "$CONFIG_NET" = "y" ]; then
-mainmenu_option next_comment
-comment 'Network File Systems'
-
-if [ "$CONFIG_INET" = "y" ]; then
- tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS
+ mainmenu_option next_comment
+ comment 'Network File Systems'
- tristate 'NFS file system support' CONFIG_NFS_FS
+ dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET
+ dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
+ dep_mbool ' Provide NFSv3 client support (EXPERIMENTAL)' CONFIG_NFS_V3 $CONFIG_NFS_FS
dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
- tristate 'NFS server support' CONFIG_NFSD
- if [ "$CONFIG_NFSD" != "n" ]; then
- bool ' Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
- fi
+ dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
+ dep_mbool ' Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD
if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
define_tristate CONFIG_SUNRPC y
@@ -109,19 +90,24 @@ if [ "$CONFIG_INET" = "y" ]; then
define_tristate CONFIG_LOCKD n
fi
fi
- if [ "$CONFIG_NFSD_V3" = "y" ]; then
+ if [ "$CONFIG_NFSD_V3" = "y" -o "$CONFIG_NFS_V3" = "y" ]; then
define_bool CONFIG_LOCKD_V4 y
fi
- tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS
-fi
-if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
- tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
- if [ "$CONFIG_NCP_FS" != "n" ]; then
+
+ dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
+
+ if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
+ tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
source fs/ncpfs/Config.in
+ else
+ # for fs/nls/Config.in
+ define_bool CONFIG_NCPFS_NLS n
fi
-fi
+ endmenu
-endmenu
+else
+ # for fs/nls/Config.in
+ define_bool CONFIG_NCPFS_NLS n
fi
mainmenu_option next_comment
diff --git a/fs/Makefile b/fs/Makefile
index 74fc394ed..9219a138f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -19,7 +19,7 @@ MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
nfsd nls devpts devfs adfs partitions qnx4 udf bfs cramfs \
- openpromfs autofs4
+ openpromfs autofs4 ramfs
SUB_DIRS := partitions
@@ -45,6 +45,14 @@ else
endif
endif
+ifeq ($(CONFIG_RAMFS),y)
+SUB_DIRS += ramfs
+else
+ ifeq ($(CONFIG_RAMFS),m)
+ MOD_SUB_DIRS += ramfs
+ endif
+endif
+
ifeq ($(CONFIG_CODA_FS),y)
SUB_DIRS += coda
else
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index c9226513e..a5fcc1a54 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -30,7 +30,7 @@ static int
adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct inode *inode = filp->f_dentry->d_inode;
- struct super_block *sb = filp->f_dentry->d_sb;
+ struct super_block *sb = inode->i_sb;
struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
struct object_info obj;
struct adfs_dir dir;
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index d861dc59d..b5626e5bb 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -78,8 +78,7 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
/* Make sure entry is mounted and unused; note that dentry will
point to the mounted-on-top root. */
- if ( !S_ISDIR(dentry->d_inode->i_mode)
- || dentry->d_mounts == dentry ) {
+ if (!S_ISDIR(dentry->d_inode->i_mode)||!d_mountpoint(dentry)) {
DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
continue;
}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 1540ceda8..06e2e86ea 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -63,7 +63,7 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
/* fall through */
default:
while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
- if ( !ent->dentry || ent->dentry->d_mounts != ent->dentry ) {
+ if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
return 0;
filp->f_pos = nr;
@@ -117,7 +117,7 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
/* If this is a directory that isn't a mount point, bitch at the
daemon and fix it in user space */
- if ( S_ISDIR(dentry->d_inode->i_mode) && dentry->d_mounts == dentry ) {
+ if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
return !autofs_wait(sbi, &dentry->d_name);
}
@@ -157,7 +157,7 @@ static int autofs_revalidate(struct dentry * dentry, int flags)
return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
/* Check for a non-mountpoint directory */
- if ( S_ISDIR(dentry->d_inode->i_mode) && dentry->d_mounts == dentry ) {
+ if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
if (autofs_oz_mode(sbi))
return 1;
else
diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
index 129d5917f..3b90a077e 100644
--- a/fs/autofs/symlink.c
+++ b/fs/autofs/symlink.c
@@ -18,10 +18,10 @@ static int autofs_readlink(struct dentry *dentry, char *buffer, int buflen)
return vfs_readlink(dentry, buffer, buflen, s);
}
-static struct dentry *autofs_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+static int autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
- return vfs_follow_link(dentry, base, flags, s);
+ return vfs_follow_link(nd, s);
}
struct inode_operations autofs_symlink_inode_operations = {
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 2318b9aec..dd3695648 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -47,8 +47,7 @@ static int is_tree_busy(struct dentry *root)
}
/* Mountpoints don't count */
- if (root->d_mounts != root ||
- root->d_covers != root) {
+ if (d_mountpoint(root)) {
DPRINTK(("is_tree_busy: mountpoint\n"));
count--;
}
@@ -77,8 +76,7 @@ resume:
count += (dentry->d_count - 1);
/* Mountpoints don't count */
- if (dentry->d_mounts != dentry ||
- dentry->d_covers != dentry) {
+ if (d_mountpoint(dentry)) {
DPRINTK(("is_tree_busy: mountpoint\n"));
adj++;
}
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 8ff33b344..41dc98984 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -181,7 +181,7 @@ static int try_to_fill_dentry(struct dentry *dentry,
/* If this is an unused directory that isn't a mount point,
bitch at the daemon and fix it in user space */
if (S_ISDIR(dentry->d_inode->i_mode) &&
- dentry->d_mounts == dentry &&
+ !d_mountpoint(dentry) &&
list_empty(&dentry->d_subdirs)) {
DPRINTK(("try_to_fill_entry: mounting existing dir\n"));
return autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT) == 0;
@@ -226,7 +226,7 @@ static int autofs4_root_revalidate(struct dentry * dentry, int flags)
/* Check for a non-mountpoint directory with no contents */
if (S_ISDIR(dentry->d_inode->i_mode) &&
- dentry->d_mounts == dentry &&
+ !d_mountpoint(dentry) &&
list_empty(&dentry->d_subdirs)) {
DPRINTK(("autofs_root_revalidate: dentry=%p %.*s, emptydir\n",
dentry, dentry->d_name.len, dentry->d_name.name));
diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
index b86b400cf..0bcb312e0 100644
--- a/fs/autofs4/symlink.c
+++ b/fs/autofs4/symlink.c
@@ -19,13 +19,11 @@ static int autofs4_readlink(struct dentry *dentry, char *buffer, int buflen)
return vfs_readlink(dentry, buffer, buflen, ino->u.symlink);
}
-static struct dentry * autofs4_follow_link(struct dentry *dentry,
- struct dentry *base,
- unsigned int flags)
+static int autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct autofs_info *ino = autofs4_dentry_ino(dentry);
- return vfs_follow_link(dentry, base, flags, ino->u.symlink);
+ return vfs_follow_link(nd, ino->u.symlink);
}
struct inode_operations autofs4_symlink_inode_operations = {
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index adb26f415..1744c5eef 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -15,10 +15,11 @@
* so that a bad root inode can at least be unmounted. To do this
* we must dput() the base and return the dentry with a dget().
*/
-static struct dentry * bad_follow_link(struct dentry *dent, struct dentry *base, unsigned int follow)
+static int bad_follow_link(struct dentry *dent, struct nameidata *nd)
{
- dput(base);
- return dget(dent);
+ dput(nd->dentry);
+ nd->dentry = dget(dent);
+ return 0;
}
static int return_EIO(void)
@@ -64,7 +65,7 @@ struct inode_operations bad_inode_ops =
};
-/*
+/*
* When a filesystem is unable to read an inode due to an I/O error in
* its read_inode() function, it can call make_bad_inode() to return a
* set of stubs which will return EIO errors as required.
@@ -72,6 +73,16 @@ struct inode_operations bad_inode_ops =
* We only need to do limited initialisation: all other fields are
* preinitialised to zero automatically.
*/
+
+/**
+ * make_bad_inode - mark an inode bad due to an I/O error
+ * @inode: Inode to mark bad
+ *
+ * When an inode cannot be read due to a media or remote network
+ * failure this function makes the inode 'bad' and causes I/O operations
+ * on it to fail from this point on
+ */
+
void make_bad_inode(struct inode * inode)
{
inode->i_mode = S_IFREG;
@@ -85,6 +96,14 @@ void make_bad_inode(struct inode * inode)
* &bad_inode_ops to cover the case of invalidated inodes as well as
* those created by make_bad_inode() above.
*/
+
+/**
+ * is_bad_inode - is an inode errored
+ * @inode: inode to test
+ *
+ * Returns true if the inode in question has been marked as bad
+ */
+
int is_bad_inode(struct inode * inode)
{
return (inode->i_op == &bad_inode_ops);
diff --git a/fs/dcache.c b/fs/dcache.c
index d4aef49e7..24e2f2568 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -30,11 +30,6 @@
/* 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[];
-#define nr_inodes (inodes_stat[0])
-
kmem_cache_t *dentry_cache;
/*
@@ -87,8 +82,8 @@ static inline void dentry_iput(struct dentry * dentry)
}
}
-/*
- * dput()
+/*
+ * dput
*
* This is complicated by the fact that we do not want to put
* dentries that are no longer on any hash chain on the unused
@@ -103,6 +98,17 @@ static inline void dentry_iput(struct dentry * dentry)
* on the compiler to always get this right (gcc generally doesn't).
* Real recursion would eat up our stack space.
*/
+
+/*
+ * dput - release a dentry
+ * @dentry: dentry to release
+ *
+ * Release a dentry. This will drop the usage count and if appropriate
+ * call the dentry unlink method as well as removing it from the queues and
+ * releasing its resources. If the parent dentries were scheduled for release
+ * they too may now get deleted.
+ */
+
void dput(struct dentry *dentry)
{
int count;
@@ -166,11 +172,16 @@ out:
BUG();
}
-/*
+/**
+ * d_invalidate - invalidate a dentry
+ * @dentry: dentry to invalidate
+ *
* Try to invalidate the dentry if it turns out to be
* possible. If there are other dentries that can be
- * reached through this one we can't delete it.
+ * reached through this one we can't delete it and we
+ * return -EBUSY. On success we return 0.
*/
+
int d_invalidate(struct dentry * dentry)
{
check_lock();
@@ -225,12 +236,19 @@ static inline void prune_one_dentry(struct dentry * dentry)
dput(parent);
}
-/*
+/**
+ * prune_dcache - shrink the dcache
+ * @count: number of entries to try and free
+ *
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
* something (at which point we need to unuse
* all dentries).
+ *
+ * This function may fail to free any resources if
+ * all the dentries are in use.
*/
+
void prune_dcache(int count)
{
check_lock();
@@ -264,6 +282,16 @@ void prune_dcache(int count)
* each dput(), but since the target dentries are all at
* the end, it's really just a single traversal.
*/
+
+/**
+ * shrink_dcache_sb - shrink dcache for a superblock
+ * @sb: superblock
+ *
+ * Shrink the dcache for the specified super block. This
+ * is used to free the dcache before unmounting a file
+ * system
+ */
+
void shrink_dcache_sb(struct super_block * sb)
{
struct list_head *tmp, *next;
@@ -307,11 +335,17 @@ repeat:
}
}
-/*
+/**
+ * is_root_busy - check if a root dentry could be freed
+ * @root: Dentry to work down from
+ *
* Check whether a root dentry would be in use if all of its
* child dentries were freed. This allows a non-destructive
* test for unmounting a device.
+ *
+ * Return non zero if the root is still busy.
*/
+
int is_root_busy(struct dentry *root)
{
struct dentry *this_parent = root;
@@ -353,12 +387,21 @@ resume:
* We descend to the next level whenever the d_subdirs
* list is non-empty and continue searching.
*/
+
+/**
+ * have_submounts - check for mounts over a dentry
+ * @parent: dentry to check.
+ *
+ * Return true if the parent or its subdirectories contain
+ * a mount point
+ */
+
int have_submounts(struct dentry *parent)
{
struct dentry *this_parent = parent;
struct list_head *next;
- if (parent->d_mounts != parent)
+ if (d_mountpoint(parent))
return 1;
repeat:
next = this_parent->d_subdirs.next;
@@ -368,7 +411,7 @@ resume:
struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
/* Have we found a mount point ? */
- if (dentry->d_mounts != dentry)
+ if (d_mountpoint(dentry))
return 1;
if (!list_empty(&dentry->d_subdirs)) {
this_parent = dentry;
@@ -440,9 +483,13 @@ this_parent->d_parent->d_name.name, this_parent->d_name.name, found);
return found;
}
-/*
+/**
+ * shrink_dcache_parent - prune dcache
+ * @parent: parent of entries to prune
+ *
* Prune the dcache to remove unused children of the parent dentry.
*/
+
void shrink_dcache_parent(struct dentry * parent)
{
int found;
@@ -482,6 +529,16 @@ int shrink_dcache_memory(int priority, unsigned int gfp_mask, zone_t * zone)
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
+/**
+ * d_alloc - allocate a dcache entry
+ * @parent: parent of entry to allocate
+ * @name: qstr of the name
+ *
+ * Allocates a dentry. It returns NULL if there is insufficient memory
+ * available. On a success the dentry is returned. The name passed in is
+ * copied and the copy passed in may be reused after this call.
+ */
+
struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
{
char * str;
@@ -530,7 +587,11 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
return dentry;
}
-/*
+/**
+ * d_instantiate - fill in inode information for a dentry
+ * @entry: dentry to complete
+ * @inode: inode to attacheto this dentry
+ *
* Fill in inode information in the entry.
*
* This turns negative dentries into productive full members
@@ -540,6 +601,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
* (or otherwise set) by the caller to indicate that it is now
* in use by the dcache..
*/
+
void d_instantiate(struct dentry *entry, struct inode * inode)
{
if (inode)
@@ -547,6 +609,15 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
entry->d_inode = inode;
}
+/**
+ * d_alloc_root - allocate root dentry
+ * @root_inode: inode to allocate the root for
+ *
+ * Allocate a root ('/') dentry for the inode given. The inode is
+ * instantiated and returned. NULL is returned if there is insufficient
+ * memory or the inode passed is NULL.
+ */
+
struct dentry * d_alloc_root(struct inode * root_inode)
{
struct dentry *res = NULL;
@@ -569,6 +640,17 @@ static inline struct list_head * d_hash(struct dentry * parent, unsigned long ha
return dentry_hashtable + (hash & D_HASHMASK);
}
+/**
+ * d_lookup - search for a dentry
+ * @parent: parent dentry
+ * @name: qstr of name we wish to find
+ *
+ * Searches the children of the parent dentry for the name in question. If
+ * the dentry is found its reference count is incremented and the dentry
+ * is returned. The caller must use d_put to free the entry when it has
+ * finished using it. NULL is returned on failure.
+ */
+
struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
{
unsigned int len = name->len;
@@ -602,16 +684,23 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
return NULL;
}
-/*
- * An insecure source has sent us a dentry, here we verify it.
+/**
+ * d_validate - verify dentry provided from insecure source
+ * @dentry: The dentry alleged to be valid
+ * @dparent: The parent dentry
+ * @hash: Hash of the dentry
+ * @len: Length of the name
*
+ * An insecure source has sent us a dentry, here we verify it.
* This is used by ncpfs in its readdir implementation.
+ * Zero is returned in the dentry is invalid.
*
- * NOTE! Do _not_ dereference the pointers before we have
+ * NOTE: This function does _not_ dereference the pointers before we have
* validated them. We can test the pointer values, but we
* must not actually use them until we have found a valid
* copy of the pointer in kernel space..
*/
+
int d_validate(struct dentry *dentry, struct dentry *dparent,
unsigned int hash, unsigned int len)
{
@@ -659,12 +748,19 @@ out:
* it from the hash queues and waiting for
* it to be deleted later when it has no users
*/
+
+/**
+ * d_delete - delete a dentry
+ * @dentry: The dentry to delete
+ *
+ * Turn the dentry into a negative dentry if possible, otherwise
+ * remove it from the hash queues so it can be deleted later
+ */
+
void d_delete(struct dentry * dentry)
{
check_lock();
- check_lock();
-
/*
* Are we the only user?
*/
@@ -680,6 +776,13 @@ void d_delete(struct dentry * dentry)
d_drop(dentry);
}
+/**
+ * d_rehash - add an entry back to the hash
+ * @entry: dentry to add to the hash
+ *
+ * Adds a dentry to the hash according to its name
+ */
+
void d_rehash(struct dentry * entry)
{
struct dentry * parent = entry->d_parent;
@@ -733,6 +836,16 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target)
* the fact that any list-entry can be a head of the list.
* Think about it.
*/
+
+/**
+ * d_move - move a dentry
+ * @dentry: entry to move
+ * @target: new dentry
+ *
+ * Update the dcache to reflect the move of a file name. Negative
+ * dcache entries should not be moved in this way.
+ */
+
void d_move(struct dentry * dentry, struct dentry * target)
{
check_lock();
@@ -762,14 +875,24 @@ void d_move(struct dentry * dentry, struct dentry * target)
list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
}
-/*
+/**
+ * d_path - return the path of a dentry
+ * @dentry: dentry to report
+ * @buffer: buffer to return value in
+ * @buflen: buffer length
+ *
+ * Convert a dentry into an ascii path name. If the entry has been deleted
+ * the string ' (deleted)' is appended. Note that this is ambiguous. Returns
+ * the buffer.
+ *
* "buflen" should be PAGE_SIZE or more.
*/
-char * d_path(struct dentry *dentry, char *buffer, int buflen)
+char * __d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+ struct dentry *root, struct vfsmount *rootmnt,
+ char *buffer, int buflen)
{
char * end = buffer+buflen;
char * retval;
- struct dentry * root = current->fs->root;
*--end = '\0';
buflen--;
@@ -839,7 +962,7 @@ asmlinkage long sys_getcwd(char *buf, unsigned long size)
char * cwd;
lock_kernel();
- cwd = d_path(pwd, page, PAGE_SIZE);
+ cwd = d_path(pwd, current->fs->pwdmnt, page, PAGE_SIZE);
unlock_kernel();
error = -ERANGE;
@@ -860,6 +983,16 @@ asmlinkage long sys_getcwd(char *buf, unsigned long size)
*
* Trivially implemented using the dcache structure
*/
+
+/**
+ * is_subdir - is new dentry a subdirectory of old_dentry
+ * @new_dentry: new dentry
+ * @old_dentry: old dentry
+ *
+ * Returns 1 if new_dentry is a subdirectory of the parent (at any depth).
+ * Returns 0 otherwise.
+ */
+
int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry)
{
int result;
@@ -879,14 +1012,20 @@ int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry)
return result;
}
-/*
+/**
+ * find_inode_number - check for dentry with name
+ * @dir: directory to check
+ * @name: Name to find.
+ *
* Check whether a dentry already exists for the given name,
- * and return the inode number if it has an inode.
+ * and return the inode number if it has an inode. Otherwise
+ * 0 is returned.
*
* This routine is used to post-process directory listings for
* filesystems using synthetic inode numbers, and is necessary
* to keep getcwd() working.
*/
+
ino_t find_inode_number(struct dentry *dir, struct qstr *name)
{
struct dentry * dentry;
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index ab1e9ee83..eb38eff34 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -3091,16 +3091,14 @@ static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen)
return vfs_readlink(dentry, buffer, buflen, name);
} /* End Function devfs_readlink */
-static struct dentry *devfs_follow_link (struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
+static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd)
{
struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode);
char *name = ERR_PTR(-ENOENT);
if (di && di->de->registered)
name = di->de->u.symlink.linkname;
- return vfs_follow_link(dentry, base, follow, name);
+ return vfs_follow_link(nd, name);
} /* End Function devfs_follow_link */
static struct inode_operations devfs_iops =
@@ -3393,12 +3391,11 @@ int __init init_devfs_fs (void)
void __init mount_devfs_fs (void)
{
int err;
- extern int do_mount (struct block_device *bdev, const char *dev_name,
- const char *dir_name, const char * type, int flags,
- void * data);
+ extern long do_sys_mount (char *dev_name, char *dir_name,
+ char * type, int flags, void * data);
if ( (boot_options & OPTION_NOMOUNT) ) return;
- err = do_mount (NULL, "none", "/dev", "devfs", 0, "");
+ err = do_sys_mount ("none", "/dev", "devfs", 0, "");
if (err == 0) printk ("Mounted devfs on /dev\n");
else printk ("Warning: unable to mount devfs, err: %d\n", err);
} /* End Function mount_devfs_fs */
diff --git a/fs/dquot.c b/fs/dquot.c
index c602697f5..64416f9ee 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -716,15 +716,16 @@ int remove_inode_dquot_ref(struct inode *inode, short type, struct list_head *to
}
inode->i_flags &= ~S_QUOTA;
put_it:
- if (dquot != NODQUOT)
+ if (dquot != NODQUOT) {
if (dqput_blocks(dquot)) {
if (dquot->dq_count != 1)
printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", dquot->dq_count);
list_add(&dquot->dq_free, tofree_head); /* As dquot must have currently users it can't be on the free list... */
return 1;
- }
- else
+ } else {
dqput(dquot); /* We have guaranteed we won't block */
+ }
+ }
return 0;
}
@@ -793,20 +794,12 @@ static inline int need_print_warning(struct dquot *dquot, int flag)
static void print_warning(struct dquot *dquot, int flag, const char *fmtstr)
{
- struct dentry *root;
- char *path, *buffer;
-
if (!need_print_warning(dquot, flag))
return;
- root = dquot->dq_sb->s_root;
- dget(root);
- buffer = (char *) __get_free_page(GFP_KERNEL);
- path = buffer ? d_path(root, buffer, PAGE_SIZE) : "?";
- sprintf(quotamessage, fmtstr, path, quotatypes[dquot->dq_type]);
- free_page((unsigned long) buffer);
+ sprintf(quotamessage, fmtstr,
+ bdevname(dquot->dq_sb->s_dev), quotatypes[dquot->dq_type]);
tty_write_message(current->tty, quotamessage);
dquot->dq_flags |= flag;
- dput(root);
}
static inline char ignore_hardlimit(struct dquot *dquot)
@@ -1469,7 +1462,7 @@ static int quota_on(struct super_block *sb, short type, char *path)
if (IS_ERR(tmp))
goto out_lock;
- f = filp_open(tmp, O_RDWR, 0600, NULL);
+ f = filp_open(tmp, O_RDWR, 0600);
putname(tmp);
error = PTR_ERR(f);
diff --git a/fs/exec.c b/fs/exec.c
index 8a8a10631..22e151141 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -112,7 +112,7 @@ asmlinkage long sys_uselib(const char * library)
goto out;
file = fget(fd);
retval = -ENOEXEC;
- if (file && file->f_dentry && file->f_op && file->f_op->read) {
+ if (file && file->f_op && file->f_op->read) {
spin_lock(&binfmt_lock);
for (fmt = formats ; fmt ; fmt = fmt->next) {
if (!fmt->load_shlib)
@@ -315,27 +315,30 @@ int setup_arg_pages(struct linux_binprm *bprm)
return 0;
}
+/* MOUNT_REWRITE: &mnt should be passed to lookup_dentry */
struct file *open_exec(const char *name)
{
struct dentry *dentry;
+ struct vfsmount *mnt = NULL;
struct file *file;
lock_kernel();
- dentry = lookup_dentry(name, NULL, LOOKUP_FOLLOW);
+ dentry = lookup_dentry(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
file = (struct file*) dentry;
if (!IS_ERR(dentry)) {
file = ERR_PTR(-EACCES);
- if (dentry->d_inode && S_ISREG(dentry->d_inode->i_mode)) {
+ if (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);
+ file = dentry_open(dentry, mnt, O_RDONLY);
out:
unlock_kernel();
return file;
}
}
dput(dentry);
+ mntput(mnt);
}
goto out;
}
@@ -860,7 +863,6 @@ int do_coredump(long signr, struct pt_regs * regs)
struct linux_binfmt * binfmt;
char corename[6+sizeof(current->comm)];
struct file * file;
- struct dentry * dentry;
struct inode * inode;
lock_kernel();
@@ -879,17 +881,16 @@ int do_coredump(long signr, struct pt_regs * regs)
#else
corename[4] = '\0';
#endif
- file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600, NULL);
+ file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
if (IS_ERR(file))
goto fail;
- dentry = file->f_dentry;
- inode = dentry->d_inode;
+ inode = file->f_dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
if (!S_ISREG(inode->i_mode))
goto close_fail;
- if (!inode->i_fop)
+ if (!file->f_op)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 79caca33b..c5bc9471d 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -182,61 +182,71 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
return NULL;
}
+static inline void ext2_set_de_type(struct super_block *sb,
+ struct ext2_dir_entry_2 *de,
+ umode_t mode) {
+ if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
+ return;
+ if (S_ISREG(mode))
+ de->file_type = EXT2_FT_REG_FILE;
+ else if (S_ISDIR(mode))
+ de->file_type = EXT2_FT_DIR;
+ else if (S_ISLNK(mode))
+ de->file_type = EXT2_FT_SYMLINK;
+ else if (S_ISSOCK(mode))
+ de->file_type = EXT2_FT_SOCK;
+ else if (S_ISFIFO(mode))
+ de->file_type = EXT2_FT_FIFO;
+ else if (S_ISCHR(mode))
+ de->file_type = EXT2_FT_CHRDEV;
+ else if (S_ISBLK(mode))
+ de->file_type = EXT2_FT_BLKDEV;
+}
+
/*
* ext2_add_entry()
*
- * adds a file entry to the specified directory, using the same
- * semantics as ext2_find_entry(). It returns NULL if it failed.
- *
- * NOTE!! The inode part of 'de' is left at 0 - which means you
- * may not sleep between calling this and putting something into
- * the entry, as someone else might have used it while you slept.
+ * adds a file entry to the specified directory.
*/
-static struct buffer_head * ext2_add_entry (struct inode * dir,
- const char * name, int namelen,
- struct ext2_dir_entry_2 ** res_dir,
- int *err)
+int ext2_add_entry (struct inode * dir, const char * name, int namelen,
+ struct inode *inode)
{
unsigned long offset;
unsigned short rec_len;
struct buffer_head * bh;
struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
+ int retval;
- *err = -EINVAL;
- *res_dir = NULL;
if (!dir || !dir->i_nlink)
- return NULL;
+ return -EINVAL;
sb = dir->i_sb;
if (!namelen)
- return NULL;
+ return -EINVAL;
/*
* Is this a busy deleted directory? Can't create new files if so
*/
if (dir->i_size == 0)
{
- *err = -ENOENT;
- return NULL;
+ return -ENOENT;
}
- bh = ext2_bread (dir, 0, 0, err);
+ bh = ext2_bread (dir, 0, 0, &retval);
if (!bh)
- return NULL;
+ return retval;
rec_len = EXT2_DIR_REC_LEN(namelen);
offset = 0;
de = (struct ext2_dir_entry_2 *) bh->b_data;
- *err = -ENOSPC;
while (1) {
if ((char *)de >= sb->s_blocksize + bh->b_data) {
brelse (bh);
bh = NULL;
- bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err);
+ bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &retval);
if (!bh)
- return NULL;
+ return retval;
if (dir->i_size <= offset) {
if (dir->i_size == 0) {
- *err = -ENOENT;
- return NULL;
+ return -ENOENT;
}
ext2_debug ("creating next block\n");
@@ -256,14 +266,12 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
}
if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
offset)) {
- *err = -ENOENT;
brelse (bh);
- return NULL;
+ return -ENOENT;
}
if (ext2_match (namelen, name, de)) {
- *err = -EEXIST;
brelse (bh);
- return NULL;
+ return -EEXIST;
}
if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
(le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
@@ -276,7 +284,11 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
de = de1;
}
- de->inode = 0;
+ if (inode) {
+ de->inode = cpu_to_le32(inode->i_ino);
+ ext2_set_de_type(dir->i_sb, de, inode->i_mode);
+ } else
+ de->inode = 0;
de->name_len = namelen;
de->file_type = 0;
memcpy (de->name, name, namelen);
@@ -296,22 +308,26 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
mark_inode_dirty(dir);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
- *res_dir = de;
- *err = 0;
- return bh;
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ brelse(bh);
+ return 0;
}
offset += le16_to_cpu(de->rec_len);
de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
brelse (bh);
- return NULL;
+ return -ENOSPC;
}
/*
* ext2_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
-static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
+static int ext2_delete_entry (struct inode * dir,
+ struct ext2_dir_entry_2 * de_del,
struct buffer_head * bh)
{
struct ext2_dir_entry_2 * de, * pde;
@@ -324,13 +340,19 @@ static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
if (!ext2_check_dir_entry ("ext2_delete_entry", NULL,
de, bh, i))
return -EIO;
- if (de == dir) {
+ if (de == de_del) {
if (pde)
pde->rec_len =
cpu_to_le16(le16_to_cpu(pde->rec_len) +
- le16_to_cpu(dir->rec_len));
+ le16_to_cpu(de->rec_len));
else
- dir->inode = 0;
+ de->inode = 0;
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ if (IS_SYNC(dir)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
return 0;
}
i += le16_to_cpu(de->rec_len);
@@ -340,27 +362,6 @@ static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
return -ENOENT;
}
-static inline void ext2_set_de_type(struct super_block *sb,
- struct ext2_dir_entry_2 *de,
- umode_t mode) {
- if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
- return;
- if (S_ISREG(mode))
- de->file_type = EXT2_FT_REG_FILE;
- else if (S_ISDIR(mode))
- de->file_type = EXT2_FT_DIR;
- else if (S_ISLNK(mode))
- de->file_type = EXT2_FT_SYMLINK;
- else if (S_ISSOCK(mode))
- de->file_type = EXT2_FT_SOCK;
- else if (S_ISFIFO(mode))
- de->file_type = EXT2_FT_FIFO;
- else if (S_ISCHR(mode))
- de->file_type = EXT2_FT_CHRDEV;
- else if (S_ISBLK(mode))
- de->file_type = EXT2_FT_BLKDEV;
-}
-
/*
* By the time this is called, we already have created
* the directory cache entry for the new file, but it
@@ -372,38 +373,28 @@ static inline void ext2_set_de_type(struct super_block *sb,
static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
- struct buffer_head * bh;
- struct ext2_dir_entry_2 * de;
- int err = -EIO;
+ int err;
/*
* N.B. Several error exits in ext2_new_inode don't set err.
*/
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
- return err;
+ return -EIO;
inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations;
inode->i_mapping->a_ops = &ext2_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh) {
+ err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len,
+ inode);
+ if (err) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput (inode);
return err;
}
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, S_IFREG);
- dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
- brelse (bh);
d_instantiate(dentry, inode);
return 0;
}
@@ -411,56 +402,42 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct inode * inode;
- struct buffer_head * bh;
- struct ext2_dir_entry_2 * de;
- int err = -EIO;
+ int err;
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
- goto out;
+ return -EIO;
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len,
+ inode);
+ if (err)
goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
- dir->i_version = ++event;
- ext2_set_de_type(dir->i_sb, de, inode->i_mode);
mark_inode_dirty(inode);
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
d_instantiate(dentry, inode);
- brelse(bh);
- err = 0;
-out:
- return err;
+ return 0;
out_no_entry:
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
- goto out;
+ return err;
}
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
- struct buffer_head * bh, * dir_block;
+ struct buffer_head * dir_block;
struct ext2_dir_entry_2 * de;
int err;
- err = -EMLINK;
if (dir->i_nlink >= EXT2_LINK_MAX)
- goto out;
+ return -EMLINK;
- err = -EIO;
inode = ext2_new_inode (dir, S_IFDIR, &err);
if (!inode)
- goto out;
+ return -EIO;
inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations;
@@ -471,7 +448,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_nlink--; /* is this nlink == 0? */
mark_inode_dirty(inode);
iput (inode);
- return err;
+ return -EIO;
}
de = (struct ext2_dir_entry_2 *) dir_block->b_data;
de->inode = cpu_to_le32(inode->i_ino);
@@ -492,31 +469,21 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len,
+ inode);
+ if (err)
goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, S_IFDIR);
- dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
dir->i_nlink++;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
d_instantiate(dentry, inode);
- brelse (bh);
- err = 0;
-out:
- return err;
+ return 0;
out_no_entry:
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput (inode);
- goto out;
+ return err;
}
/*
@@ -604,15 +571,9 @@ static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
if (!empty_dir (inode))
goto end_rmdir;
- retval = ext2_delete_entry (de, bh);
- dir->i_version = ++event;
+ retval = ext2_delete_entry(dir, de, bh);
if (retval)
goto end_rmdir;
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
if (inode->i_nlink != 2)
ext2_warning (inode->i_sb, "ext2_rmdir",
"empty directory has nlink!=2 (%d)",
@@ -657,15 +618,9 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry)
inode->i_ino, inode->i_nlink);
inode->i_nlink = 1;
}
- retval = ext2_delete_entry (de, bh);
+ retval = ext2_delete_entry(dir, de, bh);
if (retval)
goto end_unlink;
- dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
@@ -683,18 +638,14 @@ end_unlink:
static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
struct inode * inode;
- struct ext2_dir_entry_2 * de;
- struct buffer_head * bh = NULL;
int l, err;
- err = -ENAMETOOLONG;
l = strlen(symname)+1;
if (l > dir->i_sb->s_blocksize)
- goto out;
+ return -ENAMETOOLONG;
- err = -EIO;
if (!(inode = ext2_new_inode (dir, S_IFLNK, &err)))
- goto out;
+ return -EIO;
inode->i_mode = S_IFLNK | S_IRWXUGO;
@@ -711,36 +662,24 @@ static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char *
}
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+ err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len,
+ inode);
+ if (err)
goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, S_IFLNK);
- dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
- brelse (bh);
d_instantiate(dentry, inode);
- err = 0;
-out:
- return err;
+ return 0;
out_no_entry:
inode->i_nlink--;
mark_inode_dirty(inode);
iput (inode);
- goto out;
+ return err;
}
static int ext2_link (struct dentry * old_dentry,
struct inode * dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
- struct ext2_dir_entry_2 * de;
- struct buffer_head * bh;
int err;
if (S_ISDIR(inode->i_mode))
@@ -748,20 +687,12 @@ static int ext2_link (struct dentry * old_dentry,
if (inode->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
-
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
+
+ err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len,
+ inode);
+ if (err)
return err;
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, inode->i_mode);
- dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
- if (IS_SYNC(dir)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
- brelse (bh);
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
@@ -829,14 +760,26 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
goto end_rename;
}
if (!new_bh) {
- new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name,
- new_dentry->d_name.len, &new_de,
- &retval);
- if (!new_bh)
+ retval = ext2_add_entry (new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len,
+ old_inode);
+ if (retval)
goto end_rename;
+ } else {
+ new_de->inode = le32_to_cpu(old_inode->i_ino);
+ if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ new_de->file_type = old_de->file_type;
+ new_dir->i_version = ++event;
+ mark_buffer_dirty(new_bh, 1);
+ if (IS_SYNC(new_dir)) {
+ ll_rw_block (WRITE, 1, &new_bh);
+ wait_on_buffer (new_bh);
+ }
+ brelse(new_bh);
+ new_bh = NULL;
}
- new_dir->i_version = ++event;
-
+
/*
* Like most other Unix systems, set the ctime for inodes on a
* rename.
@@ -847,14 +790,8 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
/*
* ok, that's it
*/
- new_de->inode = le32_to_cpu(old_inode->i_ino);
- if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
- EXT2_FEATURE_INCOMPAT_FILETYPE))
- new_de->file_type = old_de->file_type;
-
- ext2_delete_entry (old_de, old_bh);
+ ext2_delete_entry(old_dir, old_de, old_bh);
- old_dir->i_version = ++event;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
@@ -877,16 +814,6 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
mark_inode_dirty(new_dir);
}
}
- mark_buffer_dirty(old_bh, 1);
- if (IS_SYNC(old_dir)) {
- ll_rw_block (WRITE, 1, &old_bh);
- wait_on_buffer (old_bh);
- }
- mark_buffer_dirty(new_bh, 1);
- if (IS_SYNC(new_dir)) {
- ll_rw_block (WRITE, 1, &new_bh);
- wait_on_buffer (new_bh);
- }
retval = 0;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index a68289d71..aa6a599fc 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -197,6 +197,8 @@ 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);
else if (!strcmp (this_char, "nogrpid") ||
!strcmp (this_char, "sysvgroups"))
clear_opt (*mount_options, GRPID);
@@ -300,13 +302,6 @@ static void ext2_setup_super (struct super_block * sb,
}
#endif
}
-#if 0 /* ibasket's still have unresolved bugs... -DaveM */
-
- /* [T. Schoebel-Theuer] This limit should be maintained on disk.
- * This is just provisionary.
- */
- sb->s_ibasket_max = 100;
-#endif
}
static int ext2_check_descriptors (struct super_block * sb)
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index d56ef4c62..d992efbe7 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -25,10 +25,10 @@ static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
return vfs_readlink(dentry, buffer, buflen, s);
}
-static struct dentry *ext2_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
{
char *s = (char *)dentry->d_inode->u.ext2_i.i_data;
- return vfs_follow_link(dentry, base, flags, s);
+ return vfs_follow_link(nd, s);
}
struct inode_operations ext2_fast_symlink_inode_operations = {
diff --git a/fs/file_table.c b/fs/file_table.c
index 3f795576e..ee7be9890 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -122,13 +122,17 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
static void __fput(struct file *filp)
{
struct dentry * dentry = filp->f_dentry;
+ struct vfsmount * mnt = filp->f_vfsmnt;
struct inode * inode = dentry->d_inode;
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode, filp);
filp->f_dentry = NULL;
+ filp->f_vfsmnt = NULL;
if (filp->f_mode & FMODE_WRITE)
put_write_access(inode);
+ if (mnt)
+ mntput(mnt);
dput(dentry);
}
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index debe0a967..07f4ab93d 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -314,14 +314,10 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry)
if (!d_unhashed(dentry))
goto hfs_rmdir_put;
- if (/* we only have to worry about 2 and 3 for mount points */
- (victim->sys_entry[2] &&
- (victim->sys_entry[2]->d_mounts !=
- victim->sys_entry[2]->d_covers)) ||
- (victim->sys_entry[3] &&
- (victim->sys_entry[3]->d_mounts !=
- victim->sys_entry[3]->d_covers))
- )
+ /* we only have to worry about 2 and 3 for mount points */
+ if (victim->sys_entry[2] && d_mountpoint(victim->sys_entry[2]))
+ goto hfs_rmdir_put;
+ if (victim->sys_entry[3] && d_mountpoint(victim->sys_entry[3]))
goto hfs_rmdir_put;
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index a2f33d56d..51d519d7f 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -23,7 +23,7 @@ loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
loff_t pos;
struct quad_buffer_head qbh;
struct inode *i = filp->f_dentry->d_inode;
- struct super_block *s = filp->f_dentry->d_sb;
+ struct super_block *s = i->i_sb;
/*printk("dir lseek\n");*/
if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
hpfs_lock_inode(i);
diff --git a/fs/inode.c b/fs/inode.c
index c4915bba1..de7267c84 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -111,6 +111,14 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
* In short, make sure you hash any inodes _before_
* you start marking them dirty..
*/
+
+/**
+ * __mark_inode_dirty - internal function
+ * @inode: inode to mark
+ *
+ * Mark an inode as dirty. Callers should use mark_inode_dirty
+ */
+
void __mark_inode_dirty(struct inode *inode)
{
struct super_block * sb = inode->i_sb;
@@ -202,10 +210,14 @@ static inline void sync_list(struct list_head *head)
sync_one(list_entry(tmp, struct inode, i_list));
}
-/*
- * "sync_inodes()" goes through the super block's dirty list,
- * writes them out, and puts them back on the normal list.
+/**
+ * sync_inodes
+ * @dev: device to sync the inodes from.
+ *
+ * sync_inodes goes through the super block's dirty list,
+ * writes them out, and puts them back on the normal list.
*/
+
void sync_inodes(kdev_t dev)
{
struct super_block * sb = sb_entry(super_blocks.next);
@@ -241,9 +253,14 @@ static void sync_all_inodes(void)
}
}
-/*
- * Needed by knfsd
+/**
+ * write_inode_now - write an inode to disk
+ * @inode: inode to write to disk
+ *
+ * This function commits an inode to disk immediately if it is
+ * dirty. This is primarily needed by knfsd.
*/
+
void write_inode_now(struct inode *inode)
{
struct super_block * sb = inode->i_sb;
@@ -258,11 +275,15 @@ void write_inode_now(struct inode *inode)
printk("write_inode_now: no super block\n");
}
-/*
+/**
+ * clear_inode - clear an inode
+ * @inode: inode to clear
+ *
* This is called by the filesystem to tell us
* that the inode is no longer useful. We just
* terminate it with extreme prejudice.
*/
+
void clear_inode(struct inode *inode)
{
if (inode->i_data.nrpages)
@@ -346,6 +367,16 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru
* is because we don't want to sleep while messing
* with the global lists..
*/
+
+/**
+ * invalidate_inodes - discard the inodes on a device
+ * @sb: superblock
+ *
+ * Discard all of the inodes for a given superblock. If the discard
+ * fails because there are busy inodes then a non zero value is returned.
+ * If the discard is successful all the inodes are dicarded.
+ */
+
int invalidate_inodes(struct super_block * sb)
{
int busy;
@@ -490,12 +521,19 @@ static void clean_inode(struct inode *inode)
inode->i_mapping = &inode->i_data;
}
-/*
+/**
+ * get_empty_inode - obtain an inode
+ *
* This is called by things like the networking layer
* etc that want to get an inode without any inode
* number, or filesystems that allocate new inodes with
* no pre-existing information.
+ *
+ * On a successful return the inode pointer is returned. On a failure
+ * a NULL pointer is returned. The returned inode is not on any superblock
+ * lists.
*/
+
struct inode * get_empty_inode(void)
{
static unsigned long last_ino = 0;
@@ -585,6 +623,22 @@ static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
}
/* Yeah, I know about quadratic hash. Maybe, later. */
+
+/**
+ * iunique - get a unique inode number
+ * @sb: superblock
+ * @max_reserved: highest reserved inode number
+ *
+ * Obtain an inode number that is unique on the system for a given
+ * superblock. This is used by file systems that have no natural
+ * permanent inode numbering system. An inode number is returned that
+ * is higher than the reserved limit but unique.
+ *
+ * BUGS:
+ * With a large number of inodes live on the file system this function
+ * currently becomes quite slow.
+ */
+
ino_t iunique(struct super_block *sb, ino_t max_reserved)
{
static ino_t counter = 0;
@@ -625,6 +679,7 @@ struct inode *igrab(struct inode *inode)
return inode;
}
+
struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
{
struct list_head * head = inode_hashtable + hash(sb,ino);
@@ -647,6 +702,14 @@ struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find
return get_new_inode(sb, ino, head, find_actor, opaque);
}
+/**
+ * insert_inode_hash - hash an inode
+ * @inode: unhashed inode
+ *
+ * Add an inode to the inode hash for this superblock. If the inode
+ * has no superblock it is added to a seperate anonymous chain
+ */
+
void insert_inode_hash(struct inode *inode)
{
struct list_head *head = &anon_hash_chain;
@@ -657,6 +720,13 @@ void insert_inode_hash(struct inode *inode)
spin_unlock(&inode_lock);
}
+/**
+ * remove_inode_hash - remove an inode from the hash
+ * @inode: inode to unhash
+ *
+ * Remove an inode from the superblock or anonymous hash
+ */
+
void remove_inode_hash(struct inode *inode)
{
spin_lock(&inode_lock);
@@ -665,6 +735,14 @@ void remove_inode_hash(struct inode *inode)
spin_unlock(&inode_lock);
}
+/**
+ * iput - put an inode
+ * @inode: inode to put
+ *
+ * Puts an inode, dropping its usage count. If the inode use count hits
+ * zero the inode is also then freed and may be destroyed.
+ */
+
void iput(struct inode *inode)
{
if (inode) {
@@ -686,11 +764,12 @@ void iput(struct inode *inode)
inode->i_state|=I_FREEING;
spin_unlock(&inode_lock);
+ if (inode->i_data.nrpages)
+ truncate_inode_pages(&inode->i_data, 0);
+
destroy = 1;
if (op && op->delete_inode) {
void (*delete)(struct inode *) = op->delete_inode;
- if (inode->i_data.nrpages)
- truncate_inode_pages(&inode->i_data, 0);
/* s_op->delete_inode internally recalls clear_inode() */
delete(inode);
} else
@@ -743,6 +822,18 @@ kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count));
}
}
+/**
+ * bmap - find a block number in a file
+ * @inode: inode of file
+ * @block: block to find
+ *
+ * Returns the block number on the device holding the inode that
+ * is the disk block number for the block of the file requested.
+ * That is asked for block 4 of inode 1 the function will return the
+ * disk block relative to the disk start that holds that block of the
+ * file
+ */
+
int bmap(struct inode * inode, int block)
{
int res = 0;
@@ -774,13 +865,22 @@ void __init inode_init(void)
panic("cannot create inode slab cache");
}
+/**
+ * update_atime - update the access time
+ * @inode: inode accessed
+ *
+ * Update the accessed time on an inode and mark it for writeback.
+ * This function automatically handles read only file systems and media,
+ * as well as the noatime flag and inode specific noatime markers
+ */
+
void update_atime (struct inode *inode)
{
- if ( IS_NOATIME (inode) ) return;
- if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
- if ( IS_RDONLY (inode) ) return;
- inode->i_atime = CURRENT_TIME;
- mark_inode_dirty (inode);
+ if ( IS_NOATIME (inode) ) return;
+ if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
+ if ( IS_RDONLY (inode) ) return;
+ inode->i_atime = CURRENT_TIME;
+ mark_inode_dirty (inode);
} /* End Function update_atime */
diff --git a/fs/ioctl.c b/fs/ioctl.c
index a02bbec67..614cdaf67 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -98,9 +98,7 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
default:
error = -ENOTTY;
- if (!filp->f_dentry || !filp->f_dentry->d_inode)
- error = -ENOENT;
- else if (S_ISREG(filp->f_dentry->d_inode->i_mode))
+ if (S_ISREG(filp->f_dentry->d_inode->i_mode))
error = file_ioctl(filp, cmd, arg);
else if (filp->f_op && filp->f_op->ioctl)
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 7a4674d85..f89188d12 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -152,7 +152,7 @@ nlmclnt_recovery(struct nlm_host *host, u32 newstate)
host->h_monitored = 0;
host->h_nsmstate = newstate;
host->h_state++;
- host->h_count++;
+ nlm_get_host(host);
kernel_thread(reclaimer, host, 0);
}
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 20b9bb490..376eed9cc 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -106,10 +106,18 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
struct nlm_rqst reqst, *call = &reqst;
sigset_t oldset;
unsigned long flags;
- int status;
+ int status, proto, vers;
- /* Always use NLM version 1 over UDP for now... */
- if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), IPPROTO_UDP, 1)))
+ vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
+ if (NFS_PROTO(inode)->version > 3) {
+ printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
+ return -ENOLCK;
+ }
+
+ /* Retrieve transport protocol from NFS client */
+ proto = NFS_CLIENT(inode)->cl_xprt->prot;
+
+ if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
return -ENOLCK;
/* Create RPC client handle if not there, and copy soft
@@ -142,6 +150,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
spin_unlock_irqrestore(&current->sigmask_lock, flags);
call = nlmclnt_alloc_call();
+ if (!call) {
+ status = -ENOMEM;
+ goto out_restore;
+ }
call->a_flags = RPC_TASK_ASYNC;
} else {
spin_unlock_irqrestore(&current->sigmask_lock, flags);
@@ -165,8 +177,9 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
}
if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
- rpc_free(call);
+ kfree(call);
+ out_restore:
spin_lock_irqsave(&current->sigmask_lock, flags);
current->blocked = oldset;
recalc_sigpending(current);
@@ -200,8 +213,7 @@ nlmclnt_alloc_call(void)
struct nlm_rqst *call;
while (!signalled()) {
- call = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
- sizeof(struct nlm_rqst));
+ call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
if (call)
return call;
printk("nlmclnt_alloc_call: failed, waiting for memory\n");
@@ -246,6 +258,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
case -ECONNREFUSED:
case -ETIMEDOUT:
case -ENOTCONN:
+ nlm_rebind_host(host);
status = -EAGAIN;
break;
case -ERESTARTSYS:
@@ -253,10 +266,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
default:
break;
}
- if (req->a_args.block)
- nlm_rebind_host(host);
- else
- break;
+ break;
} else
if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
dprintk("lockd: server in grace period\n");
@@ -290,7 +300,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
* Generic NLM call, async version.
*/
int
-nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
{
struct nlm_host *host = req->a_host;
struct rpc_clnt *clnt;
@@ -313,9 +323,20 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
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))
- host->h_count++;
+ return status;
+}
+
+int
+nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+{
+ struct nlm_host *host = req->a_host;
+ int status;
+
+ /* Increment host refcount */
+ nlm_get_host(host);
+ status = nlmsvc_async_call(req, proc, callback);
+ if (status < 0)
+ nlm_release_host(host);
return status;
}
@@ -347,6 +368,20 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
return 0;
}
+static
+void nlmclnt_insert_lock_callback(struct file_lock *fl)
+{
+ nlm_get_host(fl->fl_u.nfs_fl.host);
+}
+static
+void nlmclnt_remove_lock_callback(struct file_lock *fl)
+{
+ if (fl->fl_u.nfs_fl.host) {
+ nlm_release_host(fl->fl_u.nfs_fl.host);
+ fl->fl_u.nfs_fl.host = NULL;
+ }
+}
+
/*
* LOCK: Try to create a lock
*
@@ -380,7 +415,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
return -ENOLCK;
}
- while (1) {
+ do {
if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) {
if (resp->status != NLM_LCK_BLOCKED)
break;
@@ -388,11 +423,14 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
}
if (status < 0)
return status;
- }
+ } while (resp->status == NLM_LCK_BLOCKED);
if (resp->status == NLM_LCK_GRANTED) {
fl->fl_u.nfs_fl.state = host->h_state;
fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
+ fl->fl_u.nfs_fl.host = host;
+ fl->fl_insert = nlmclnt_insert_lock_callback;
+ fl->fl_remove = nlmclnt_remove_lock_callback;
}
return nlm_stat_to_errno(resp->status);
@@ -444,15 +482,9 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
static int
nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
{
- struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
int status;
- /* No monitor, no lock: see nlmclnt_lock().
- * Since this is an UNLOCK, don't try to setup monitoring here. */
- if (!host->h_monitored)
- return -ENOLCK;
-
/* Clean the GRANTED flag now so the lock doesn't get
* reclaimed while we're stuck in the unlock call. */
fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
@@ -487,9 +519,7 @@ nlmclnt_unlock_callback(struct rpc_task *task)
if (task->tk_status < 0) {
dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status);
- nlm_rebind_host(req->a_host);
- rpc_restart_call(task);
- return;
+ goto retry_unlock;
}
if (status != NLM_LCK_GRANTED
&& status != NLM_LCK_DENIED_GRACE_PERIOD) {
@@ -497,7 +527,12 @@ nlmclnt_unlock_callback(struct rpc_task *task)
}
die:
- rpc_release_task(task);
+ nlm_release_host(req->a_host);
+ kfree(req);
+ return;
+ retry_unlock:
+ nlm_rebind_host(req->a_host);
+ rpc_restart_call(task);
}
/*
@@ -520,10 +555,9 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, flags);
- do {
- req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
- sizeof(*req));
- } while (req == NULL);
+ req = nlmclnt_alloc_call();
+ if (!req)
+ return -ENOMEM;
req->a_host = host;
req->a_flags = RPC_TASK_ASYNC;
@@ -532,7 +566,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
status = nlmclnt_async_call(req, NLMPROC_CANCEL,
nlmclnt_cancel_callback);
if (status < 0)
- rpc_free(req);
+ kfree(req);
spin_lock_irqsave(&current->sigmask_lock, flags);
current->blocked = oldset;
@@ -573,7 +607,6 @@ nlmclnt_cancel_callback(struct rpc_task *task)
}
die:
- rpc_release_task(task);
nlm_release_host(req->a_host);
kfree(req);
return;
@@ -582,7 +615,6 @@ retry_cancel:
nlm_rebind_host(req->a_host);
rpc_restart_call(task);
rpc_delay(task, 30 * HZ);
- return;
}
/*
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 02cfb07f4..dcd33c19b 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -15,6 +15,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
@@ -105,8 +106,7 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
host->h_next = nlm_hosts[hash];
nlm_hosts[hash] = host;
}
- host->h_expires = jiffies + NLM_HOST_EXPIRE;
- host->h_count++;
+ nlm_get_host(host);
up(&nlm_host_sema);
return host;
}
@@ -172,9 +172,12 @@ nlm_bind_host(struct nlm_host *host)
down(&host->h_sema);
/* If we've already created an RPC client, check whether
- * RPC rebind is required */
+ * RPC rebind is required
+ * Note: why keep rebinding if we're on a tcp connection?
+ */
if ((clnt = host->h_rpcclnt) != NULL) {
- if (time_after_eq(jiffies, host->h_nextrebind)) {
+ xprt = clnt->cl_xprt;
+ if (!xprt->stream && time_after_eq(jiffies, host->h_nextrebind)) {
clnt->cl_port = 0;
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
dprintk("lockd: next rebind in %ld jiffies\n",
@@ -230,13 +233,27 @@ nlm_rebind_host(struct nlm_host *host)
}
/*
+ * Increment NLM host count
+ */
+struct nlm_host * nlm_get_host(struct nlm_host *host)
+{
+ if (host) {
+ dprintk("lockd: get host %s\n", host->h_name);
+ host->h_count ++;
+ host->h_expires = jiffies + NLM_HOST_EXPIRE;
+ }
+ return host;
+}
+
+/*
* Release NLM host after use
*/
-void
-nlm_release_host(struct nlm_host *host)
+void nlm_release_host(struct nlm_host *host)
{
- dprintk("lockd: release host %s\n", host->h_name);
- host->h_count -= 1;
+ if (host && host->h_count) {
+ dprintk("lockd: release host %s\n", host->h_name);
+ host->h_count --;
+ }
}
/*
@@ -308,6 +325,8 @@ nlm_gc_hosts(void)
}
dprintk("lockd: delete host %s\n", host->h_name);
*q = host->h_next;
+ if (host->h_monitored)
+ nsm_unmonitor(host);
if ((clnt = host->h_rpcclnt) != NULL) {
if (clnt->cl_users) {
printk(KERN_WARNING
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 55dee3886..283d66e97 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -30,14 +30,12 @@ u32 nsm_local_state = 0;
* Common procedure for SM_MON/SM_UNMON calls
*/
static int
-nsm_mon_unmon(struct nlm_host *host, char *what, u32 proc)
+nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
{
struct rpc_clnt *clnt;
int status;
struct nsm_args args;
- struct nsm_res res;
- dprintk("lockd: nsm_%s(%s)\n", what, host->h_name);
status = -EACCES;
clnt = nsm_create();
if (!clnt)
@@ -47,23 +45,15 @@ nsm_mon_unmon(struct nlm_host *host, char *what, u32 proc)
args.prog = NLM_PROGRAM;
args.vers = 1;
args.proc = NLMPROC_NSM_NOTIFY;
+ memset(res, 0, sizeof(*res));
- status = rpc_call(clnt, proc, &args, &res, 0);
- if (status < 0) {
+ status = rpc_call(clnt, proc, &args, res, 0);
+ if (status < 0)
printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
status);
- goto out;
- }
-
- status = -EACCES;
- if (res.status != 0) {
- printk(KERN_NOTICE "lockd: cannot %s %s\n", what, host->h_name);
- goto out;
- }
-
- nsm_local_state = res.state;
- status = 0;
-out:
+ else
+ status = 0;
+ out:
return status;
}
@@ -73,10 +63,16 @@ out:
int
nsm_monitor(struct nlm_host *host)
{
+ struct nsm_res res;
int status;
- status = nsm_mon_unmon(host, "monitor", SM_MON);
- if (status >= 0)
+ dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
+
+ status = nsm_mon_unmon(host, SM_MON, &res);
+
+ if (status < 0 || res.status != 0)
+ printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
+ else
host->h_monitored = 1;
return status;
}
@@ -87,9 +83,15 @@ nsm_monitor(struct nlm_host *host)
int
nsm_unmonitor(struct nlm_host *host)
{
+ struct nsm_res res;
int status;
- if ((status = nsm_mon_unmon(host, "unmonitor", SM_UNMON)) >= 0)
+ dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+
+ status = nsm_mon_unmon(host, SM_UNMON, &res);
+ if (status < 0)
+ printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
+ else
host->h_monitored = 0;
return status;
}
@@ -187,7 +189,7 @@ xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
static int
xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
{
- resp->status = ntohl(*p++);
+ resp->state = ntohl(*p++);
return 0;
}
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index b690eb97e..a1e30454e 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -470,7 +470,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
host = nlmclnt_lookup_host(&rqstp->rq_addr,
rqstp->rq_prot, rqstp->rq_vers);
if (!host) {
- rpc_free(call);
+ kfree(call);
return rpc_system_err;
}
@@ -478,12 +478,14 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
call->a_host = host;
memcpy(&call->a_args, resp, sizeof(*resp));
-/* FIXME this should become nlmSVC_async_call when that code gets
- merged in XXX */
- if (nlmclnt_async_call(call, proc, nlm4svc_callback_exit) < 0)
- return rpc_system_err;
+ if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
+ goto error;
return rpc_success;
+ error:
+ kfree(call);
+ nlm_release_host(host);
+ return rpc_system_err;
}
static void
@@ -496,7 +498,7 @@ nlm4svc_callback_exit(struct rpc_task *task)
task->tk_pid, -task->tk_status);
}
nlm_release_host(call->a_host);
- rpc_free(call);
+ kfree(call);
}
/*
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 1bed616cb..97a9d27ef 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -94,14 +94,16 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
struct nlm_block **head, *block;
struct file_lock *fl;
- dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %ld-%ld ty=%d\n",
- file, lock->fl.fl_pid, lock->fl.fl_start,
- lock->fl.fl_end, lock->fl.fl_type);
+ dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
+ file, lock->fl.fl_pid,
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end, lock->fl.fl_type);
for (head = &nlm_blocked; (block = *head); head = &block->b_next) {
fl = &block->b_call.a_args.lock.fl;
- dprintk("lockd: check f=%p pd=%d %ld-%ld ty=%d cookie=%x\n",
- block->b_file, fl->fl_pid, fl->fl_start,
- fl->fl_end, fl->fl_type,
+ dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%x\n",
+ block->b_file, fl->fl_pid,
+ (long long)fl->fl_start,
+ (long long)fl->fl_end, fl->fl_type,
*(unsigned int*)(block->b_call.a_args.cookie.data));
if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
if (remove)
@@ -286,12 +288,12 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_block *block;
int error;
- dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
+ dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_type, lock->fl.fl_pid,
- lock->fl.fl_start,
- lock->fl.fl_end,
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end,
wait);
/* Lock file against concurrent access */
@@ -365,16 +367,17 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
{
struct file_lock *fl;
- dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %ld-%ld)\n",
+ dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_type,
- lock->fl.fl_start,
- lock->fl.fl_end);
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
- dprintk("lockd: conflicting lock(ty=%d, %ld-%ld)\n",
- fl->fl_type, fl->fl_start, fl->fl_end);
+ dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
+ fl->fl_type, (long long)fl->fl_start,
+ (long long)fl->fl_end);
conflock->caller = "somehost"; /* FIXME */
conflock->oh.len = 0; /* don't return OH info */
conflock->fl = *fl;
@@ -396,12 +399,12 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
{
int error;
- dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %ld-%ld)\n",
+ dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_pid,
- lock->fl.fl_start,
- lock->fl.fl_end);
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
/* First, cancel any lock that might be there */
nlmsvc_cancel_blocked(file, lock);
@@ -424,12 +427,12 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
{
struct nlm_block *block;
- dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n",
+ dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_pid,
- lock->fl.fl_start,
- lock->fl.fl_end);
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
down(&file->f_sema);
if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
@@ -576,7 +579,6 @@ nlmsvc_grant_callback(struct rpc_task *task)
block->b_incall = 0;
nlm_release_host(call->a_host);
- rpc_release_task(task);
}
/*
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index c92358dec..b0cbd4a50 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -503,10 +503,14 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
call->a_host = host;
memcpy(&call->a_args, resp, sizeof(*resp));
- if (nlmclnt_async_call(call, proc, nlmsvc_callback_exit) < 0)
- return rpc_system_err;
+ if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0)
+ goto error;
return rpc_success;
+ error:
+ nlm_release_host(host);
+ kfree(call);
+ return rpc_system_err;
}
static void
@@ -519,7 +523,6 @@ nlmsvc_callback_exit(struct rpc_task *task)
task->tk_pid, -task->tk_status);
}
nlm_release_host(call->a_host);
- rpc_release_task(task);
kfree(call);
}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c6395a54f..1d5b5382c 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -34,7 +34,7 @@ static inline unsigned int file_hash(struct nfs_fh *f)
{
unsigned int tmp=0;
int i;
- for (i=0; i<NFS_FHSIZE;i++)
+ for (i=0; i<NFS2_FHSIZE;i++)
tmp += f->data[i];
return tmp & (FILE_NRHASH - 1);
}
@@ -175,7 +175,7 @@ again:
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
- lock.fl_end = NLM_OFFSET_MAX;
+ lock.fl_end = OFFSET_MAX;
if (posix_lock_file(&file->f_file, &lock, 0) < 0) {
printk("lockd: unlock failure in %s:%d\n",
__FILE__, __LINE__);
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index eba3aaef6..9a179d530 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -22,6 +22,25 @@
#define NLMDBG_FACILITY NLMDBG_XDR
+static inline loff_t
+s32_to_loff_t(__s32 offset)
+{
+ return (loff_t)offset;
+}
+
+static inline __s32
+loff_t_to_s32(loff_t offset)
+{
+ __s32 res;
+ if (offset >= NLM_OFFSET_MAX)
+ res = NLM_OFFSET_MAX;
+ else if (offset <= -NLM_OFFSET_MAX)
+ res = -NLM_OFFSET_MAX;
+ else
+ res = offset;
+ return res;
+}
+
/*
* XDR functions for basic NLM types
*/
@@ -65,22 +84,23 @@ nlm_decode_fh(u32 *p, struct nfs_fh *f)
{
unsigned int len;
- if ((len = ntohl(*p++)) != sizeof(*f)) {
+ if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
printk(KERN_NOTICE
"lockd: bad fhandle size %x (should be %Zu)\n",
- len, sizeof(*f));
+ len, NFS2_FHSIZE);
return NULL;
}
- memcpy(f, p, sizeof(*f));
- return p + XDR_QUADLEN(sizeof(*f));
+ f->size = NFS2_FHSIZE;
+ memcpy(f->data, p, NFS2_FHSIZE);
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
}
static inline u32 *
nlm_encode_fh(u32 *p, struct nfs_fh *f)
{
- *p++ = htonl(sizeof(*f));
- memcpy(p, f, sizeof(*f));
- return p + XDR_QUADLEN(sizeof(*f));
+ *p++ = htonl(NFS2_FHSIZE);
+ memcpy(p, f->data, NFS2_FHSIZE);
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
}
/*
@@ -102,7 +122,7 @@ static inline u32 *
nlm_decode_lock(u32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
- int len;
+ s32 start, len, end;
if (!(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN))
|| !(p = nlm_decode_fh(p, &lock->fh))
@@ -114,10 +134,16 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock)
fl->fl_pid = ntohl(*p++);
fl->fl_flags = FL_POSIX;
fl->fl_type = F_RDLCK; /* as good as anything else */
- fl->fl_start = ntohl(*p++);
+ start = ntohl(*p++);
len = ntohl(*p++);
- if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
- fl->fl_end = NLM_OFFSET_MAX;
+ end = start + len - 1;
+
+ fl->fl_start = s32_to_loff_t(start);
+
+ if (len == 0 || end < 0)
+ fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s32_to_loff_t(end);
return p;
}
@@ -128,18 +154,26 @@ static u32 *
nlm_encode_lock(u32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
+ __s32 start, len;
if (!(p = xdr_encode_string(p, lock->caller))
|| !(p = nlm_encode_fh(p, &lock->fh))
|| !(p = nlm_encode_oh(p, &lock->oh)))
return NULL;
- *p++ = htonl(fl->fl_pid);
- *p++ = htonl(lock->fl.fl_start);
- if (lock->fl.fl_end == NLM_OFFSET_MAX)
- *p++ = xdr_zero;
+ if (fl->fl_start > NLM_OFFSET_MAX
+ || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
+ return NULL;
+
+ start = loff_t_to_s32(fl->fl_start);
+ if (fl->fl_end == OFFSET_MAX)
+ len = 0;
else
- *p++ = htonl(lock->fl.fl_end - lock->fl.fl_start + 1);
+ len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
+
+ *p++ = htonl(fl->fl_pid);
+ *p++ = htonl(start);
+ *p++ = htonl(len);
return p;
}
@@ -150,6 +184,8 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock)
static u32 *
nlm_encode_testres(u32 *p, struct nlm_res *resp)
{
+ s32 start, len;
+
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return 0;
*p++ = resp->status;
@@ -164,11 +200,14 @@ nlm_encode_testres(u32 *p, struct nlm_res *resp)
if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
return 0;
- *p++ = htonl(fl->fl_start);
- if (fl->fl_end == NLM_OFFSET_MAX)
- *p++ = xdr_zero;
+ start = loff_t_to_s32(fl->fl_start);
+ if (fl->fl_end == OFFSET_MAX)
+ len = 0;
else
- *p++ = htonl(fl->fl_end - fl->fl_start + 1);
+ len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
+
+ *p++ = htonl(start);
+ *p++ = htonl(len);
}
return p;
@@ -387,7 +426,8 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
resp->status = ntohl(*p++);
if (resp->status == NLM_LCK_DENIED) {
struct file_lock *fl = &resp->lock.fl;
- u32 excl, len;
+ u32 excl;
+ s32 start, len, end;
memset(&resp->lock, 0, sizeof(resp->lock));
excl = ntohl(*p++);
@@ -397,10 +437,15 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
fl->fl_flags = FL_POSIX;
fl->fl_type = excl? F_WRLCK : F_RDLCK;
- fl->fl_start = ntohl(*p++);
+ start = ntohl(*p++);
len = ntohl(*p++);
- if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
- fl->fl_end = NLM_OFFSET_MAX;
+ end = start + len - 1;
+
+ fl->fl_start = s32_to_loff_t(start);
+ if (len == 0 || end < 0)
+ fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s32_to_loff_t(end);
}
return 0;
}
@@ -487,7 +532,7 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
#define NLM_caller_sz 1+QUADLEN(sizeof(system_utsname.nodename))
#define NLM_netobj_sz 1+QUADLEN(XDR_MAX_NETOBJ)
/* #define NLM_owner_sz 1+QUADLEN(NLM_MAXOWNER) */
-#define NLM_fhandle_sz 1+QUADLEN(NFS_FHSIZE)
+#define NLM_fhandle_sz 1+QUADLEN(NFS2_FHSIZE)
#define NLM_lock_sz 3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
#define NLM_holder_sz 4+NLM_netobj_sz
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 025e3c5b0..7ffa0a433 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -20,14 +20,25 @@
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_XDR
-#define OFFSET_MAX ((off_t)LONG_MAX)
+static inline loff_t
+s64_to_loff_t(__s64 offset)
+{
+ return (loff_t)offset;
+}
-static inline off_t
-size_to_off_t(__s64 size)
+
+static inline s64
+loff_t_to_s64(loff_t offset)
{
- size = (size > (__s64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size;
- return (size < (__s64)-LONG_MAX) ? (off_t)-LONG_MAX : (off_t) size;
+ s64 res;
+ if (offset > NLM4_OFFSET_MAX)
+ res = NLM4_OFFSET_MAX;
+ else if (offset < -NLM4_OFFSET_MAX)
+ res = -NLM4_OFFSET_MAX;
+ else
+ res = offset;
+ return res;
}
/*
@@ -73,36 +84,24 @@ static u32 *
nlm4_decode_fh(u32 *p, struct nfs_fh *f)
{
memset(f->data, 0, sizeof(f->data));
-#ifdef NFS_MAXFHSIZE
f->size = ntohl(*p++);
if (f->size > NFS_MAXFHSIZE) {
printk(KERN_NOTICE
- "lockd: bad fhandle size %x (should be %d)\n",
+ "lockd: bad fhandle size %d (should be <=%d)\n",
f->size, NFS_MAXFHSIZE);
return NULL;
}
memcpy(f->data, p, f->size);
return p + XDR_QUADLEN(f->size);
-#else
- if (ntohl(*p++) != NFS_FHSIZE)
- return NULL; /* for now, all filehandles are 32 bytes */
- memcpy(f->data, p, NFS_FHSIZE);
- return p + XDR_QUADLEN(NFS_FHSIZE);
-#endif
}
static u32 *
nlm4_encode_fh(u32 *p, struct nfs_fh *f)
{
-#ifdef NFS_MAXFHSIZE
*p++ = htonl(f->size);
+ if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
memcpy(p, f->data, f->size);
return p + XDR_QUADLEN(f->size);
-#else
- *p++ = htonl(NFS_FHSIZE);
- memcpy(p, f->data, NFS_FHSIZE);
- return p + XDR_QUADLEN(NFS_FHSIZE);
-#endif
}
/*
@@ -141,11 +140,12 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
p = xdr_decode_hyper(p, &len);
end = start + len - 1;
- fl->fl_start = size_to_off_t(start);
- fl->fl_end = size_to_off_t(end);
+ fl->fl_start = s64_to_loff_t(start);
- if (len == 0 || fl->fl_end < 0)
+ if (len == 0 || end < 0)
fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s64_to_loff_t(end);
return p;
}
@@ -156,18 +156,26 @@ static u32 *
nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
+ __s64 start, len;
if (!(p = xdr_encode_string(p, lock->caller))
|| !(p = nlm4_encode_fh(p, &lock->fh))
|| !(p = nlm4_encode_oh(p, &lock->oh)))
return NULL;
- *p++ = htonl(fl->fl_pid);
- p = xdr_encode_hyper(p, fl->fl_start);
+ if (fl->fl_start > NLM4_OFFSET_MAX
+ || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
+ return NULL;
+
+ start = loff_t_to_s64(fl->fl_start);
if (fl->fl_end == OFFSET_MAX)
- p = xdr_encode_hyper(p, 0);
+ len = 0;
else
- p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+ len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
+
+ *p++ = htonl(fl->fl_pid);
+ p = xdr_encode_hyper(p, start);
+ p = xdr_encode_hyper(p, len);
return p;
}
@@ -178,6 +186,8 @@ nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
static u32 *
nlm4_encode_testres(u32 *p, struct nlm_res *resp)
{
+ s64 start, len;
+
dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
return 0;
@@ -193,12 +203,17 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp)
if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
return 0;
- p = xdr_encode_hyper(p, fl->fl_start);
+ start = loff_t_to_s64(fl->fl_start);
if (fl->fl_end == OFFSET_MAX)
- p = xdr_encode_hyper(p, 0);
+ len = 0;
else
- p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
- dprintk("xdr: encode_testres (status %d pid %d type %d start %ld end %ld)\n", resp->status, fl->fl_pid, fl->fl_type, fl->fl_start, fl->fl_end);
+ len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
+
+ p = xdr_encode_hyper(p, start);
+ p = xdr_encode_hyper(p, len);
+ dprintk("xdr: encode_testres (status %d pid %d type %d start %Ld end %Ld)\n",
+ resp->status, fl->fl_pid, fl->fl_type,
+ (long long)fl->fl_start, (long long)fl->fl_end);
}
dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
@@ -434,10 +449,11 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
p = xdr_decode_hyper(p, &len);
end = start + len - 1;
- fl->fl_start = size_to_off_t(start);
- fl->fl_end = size_to_off_t(end);
- if (len == 0 || fl->fl_end < 0)
+ fl->fl_start = s64_to_loff_t(start);
+ if (len == 0 || end < 0)
fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s64_to_loff_t(end);
}
return 0;
}
diff --git a/fs/locks.c b/fs/locks.c
index 1661a4a5c..18ee63e92 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -111,8 +111,6 @@
#include <asm/uaccess.h>
-#define OFFSET_MAX ((off_t)LONG_MAX) /* FIXME: move elsewhere? */
-
static int flock_make_lock(struct file *filp, struct file_lock *fl,
unsigned int cmd);
static int posix_make_lock(struct file *filp, struct file_lock *fl,
@@ -195,9 +193,9 @@ static void locks_insert_block(struct file_lock *blocker,
if (waiter->fl_prevblock) {
printk(KERN_ERR "locks_insert_block: remove duplicated lock "
- "(pid=%d %ld-%ld type=%d)\n",
- waiter->fl_pid, waiter->fl_start,
- waiter->fl_end, waiter->fl_type);
+ "(pid=%d %Ld-%Ld type=%d)\n",
+ waiter->fl_pid, (long long)waiter->fl_start,
+ (long long)waiter->fl_end, waiter->fl_type);
locks_delete_block(waiter->fl_prevblock, waiter);
}
@@ -338,10 +336,6 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
if (!filp)
goto out;
- error = -EINVAL;
- if (!filp->f_dentry || !filp->f_dentry->d_inode)
- goto out_putf;
-
if (!posix_make_lock(filp, &file_lock, &flock))
goto out_putf;
@@ -385,7 +379,6 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
struct file *filp;
struct file_lock file_lock;
struct flock flock;
- struct dentry * dentry;
struct inode *inode;
int error;
@@ -405,10 +398,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
goto out;
error = -EINVAL;
- if (!(dentry = filp->f_dentry))
- goto out_putf;
- if (!(inode = dentry->d_inode))
- goto out_putf;
+ inode = filp->f_dentry->d_inode;
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
@@ -616,7 +606,7 @@ repeat:
/* Block for writes against a "read" lock,
* and both reads and writes against a "write" lock.
*/
- if (posix_locks_conflict(fl, &tfl)) {
+ if (posix_locks_conflict(&tfl, fl)) {
error = -EAGAIN;
if (filp && (filp->f_flags & O_NONBLOCK))
break;
@@ -650,7 +640,7 @@ repeat:
static int posix_make_lock(struct file *filp, struct file_lock *fl,
struct flock *l)
{
- off_t start;
+ loff_t start;
memset(fl, 0, sizeof(*fl));
@@ -683,8 +673,11 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
if (((start += l->l_start) < 0) || (l->l_len < 0))
return (0);
+ fl->fl_end = start + l->l_len - 1;
+ if (l->l_len > 0 && fl->fl_end < 0)
+ return (0);
fl->fl_start = start; /* we record the absolute position */
- if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0))
+ if (l->l_len == 0)
fl->fl_end = OFFSET_MAX;
fl->fl_file = filp;
@@ -703,8 +696,6 @@ static int flock_make_lock(struct file *filp, struct file_lock *fl,
memset(fl, 0, sizeof(*fl));
init_waitqueue_head(&fl->fl_wait);
- if (!filp->f_dentry) /* just in case */
- return (0);
switch (cmd & ~LOCK_NB) {
case LOCK_SH:
@@ -1128,6 +1119,8 @@ static struct file_lock *locks_init_lock(struct file_lock *new,
new->fl_start = fl->fl_start;
new->fl_end = fl->fl_end;
new->fl_notify = fl->fl_notify;
+ new->fl_insert = fl->fl_insert;
+ new->fl_remove = fl->fl_remove;
new->fl_u = fl->fl_u;
}
return new;
@@ -1146,6 +1139,9 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
fl->fl_next = *pos; /* insert into file's list */
*pos = fl;
+ if (fl->fl_insert)
+ fl->fl_insert(fl);
+
return;
}
@@ -1173,6 +1169,9 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
prevfl->fl_nextlink = nextfl;
else
file_lock_table = nextfl;
+
+ if (thisfl->fl_remove)
+ thisfl->fl_remove(thisfl);
locks_wake_up_blocks(thisfl, wait);
locks_free_lock(thisfl);
@@ -1201,10 +1200,10 @@ static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
p += sprintf(p, "FLOCK ADVISORY ");
}
p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
- p += sprintf(p, "%d %s:%ld %ld %ld ",
+ p += sprintf(p, "%d %s:%ld %Ld %Ld ",
fl->fl_pid,
- kdevname(inode->i_dev), inode->i_ino, fl->fl_start,
- fl->fl_end);
+ kdevname(inode->i_dev), inode->i_ino,
+ (long long)fl->fl_start, (long long)fl->fl_end);
sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
(long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
(long)fl->fl_next, (long)fl->fl_nextblock);
@@ -1212,7 +1211,7 @@ static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
}
static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
- off_t offset, off_t length)
+ off_t offset, int length)
{
off_t i;
@@ -1236,7 +1235,7 @@ static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
return (1);
}
-int get_locks_status(char *buffer, char **start, off_t offset, off_t length)
+int get_locks_status(char *buffer, char **start, off_t offset, int length)
{
struct file_lock *fl;
struct file_lock *bfl;
diff --git a/fs/namei.c b/fs/namei.c
index 8675e28c5..58f7a590a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -192,31 +192,6 @@ void put_write_access(struct inode * inode)
}
/*
- * "." and ".." are special - ".." especially so because it has to be able
- * to know about the current root directory and parent relationships
- */
-static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name)
-{
- struct dentry *result = NULL;
- if (name->name[0] == '.') {
- switch (name->len) {
- default:
- break;
- case 2:
- if (name->name[1] != '.')
- break;
-
- if (parent != current->fs->root)
- parent = parent->d_covers->d_parent;
- /* fallthrough */
- case 1:
- result = parent;
- }
- }
- return dget(result);
-}
-
-/*
* Internal lookup() using the new generic dcache.
*/
static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
@@ -279,39 +254,28 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i
return result;
}
-static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow)
+static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- struct inode * inode = dentry->d_inode;
-
- if ((follow & LOOKUP_FOLLOW)
- && inode && inode->i_op && inode->i_op->follow_link) {
- if (current->link_count < 32) {
- struct dentry * result;
-
- current->link_count++;
- /* This eats the base */
- result = inode->i_op->follow_link(dentry, base, follow);
- current->link_count--;
- dput(dentry);
- return result;
- }
- dput(dentry);
- dentry = ERR_PTR(-ELOOP);
- }
- dput(base);
- return dentry;
+ int err;
+ if (current->link_count >= 32)
+ goto loop;
+ current->link_count++;
+ UPDATE_ATIME(dentry->d_inode);
+ err = dentry->d_inode->i_op->follow_link(dentry, nd);
+ current->link_count--;
+ return err;
+loop:
+ dput(nd->dentry);
+ mntput(nd->mnt);
+ return -ELOOP;
}
-static inline struct dentry * follow_mount(struct dentry * dentry)
+static inline int follow_down(struct dentry ** dentry, struct vfsmount **mnt)
{
- struct dentry * mnt = dentry->d_mounts;
-
- if (mnt != dentry) {
- dget(mnt);
- dput(dentry);
- dentry = mnt;
- }
- return dentry;
+ struct dentry * parent = dget((*dentry)->d_mounts);
+ dput(*dentry);
+ *dentry = parent;
+ return 1;
}
/*
@@ -319,36 +283,31 @@ static inline struct dentry * follow_mount(struct dentry * dentry)
*
* This is the basic name resolution function, turning a pathname
* into the final dentry.
+ *
+ * We expect 'base' to be positive and a directory.
*/
-struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned int lookup_flags)
+int walk_name(const char * name, unsigned lookup_flags, struct nameidata *nd)
{
- struct dentry * dentry;
+ struct dentry *dentry;
struct inode *inode;
+ int err;
- if (*name == '/') {
- if (base)
- dput(base);
- do {
- name++;
- } while (*name == '/');
- __prefix_lookup_dentry(name, lookup_flags);
- base = dget(current->fs->root);
- } else if (!base) {
- base = dget(current->fs->pwd);
- }
-
+ while (*name=='/')
+ name++;
if (!*name)
goto return_base;
- inode = base->d_inode;
- lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK;
+ inode = nd->dentry->d_inode;
+ if (current->link_count)
+ lookup_flags = LOOKUP_FOLLOW;
+
+ lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY |
+ LOOKUP_SLASHOK | LOOKUP_POSITIVE | LOOKUP_PARENT;
/* At this point we know we have a real path component. */
for(;;) {
- int err;
unsigned long hash;
struct qstr this;
- unsigned int flags;
unsigned int c;
err = permission(inode, MAY_EXEC);
@@ -369,99 +328,240 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
this.hash = end_name_hash(hash);
/* remove trailing slashes? */
- flags = lookup_flags;
- if (c) {
- char tmp;
-
- flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
- do {
- tmp = *++name;
- } while (tmp == '/');
- if (tmp)
- flags |= LOOKUP_CONTINUE;
- }
+ if (!c)
+ goto last_component;
+ while (*++name == '/');
+ if (!*name)
+ goto last_with_slashes;
/*
+ * "." and ".." are special - ".." especially so because it has
+ * to be able to know about the current root directory and
+ * parent relationships.
+ */
+ if (this.name[0] == '.') switch (this.len) {
+ default:
+ break;
+ case 2:
+ if (this.name[1] != '.')
+ break;
+ if (nd->dentry != current->fs->root) {
+ dentry = dget(nd->dentry->d_covers->d_parent);
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ inode = dentry->d_inode;
+ }
+ /* fallthrough */
+ case 1:
+ continue;
+ }
+ /*
* See if the low-level filesystem might want
* to use its own hash..
*/
- if (base->d_op && base->d_op->d_hash) {
- int error;
- error = base->d_op->d_hash(base, &this);
- if (error < 0) {
- dentry = ERR_PTR(error);
+ if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
+ err = nd->dentry->d_op->d_hash(nd->dentry, &this);
+ if (err < 0)
break;
- }
}
-
/* This does the actual lookups.. */
- dentry = reserved_lookup(base, &this);
+ dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
if (!dentry) {
- dentry = cached_lookup(base, &this, flags);
- if (!dentry) {
- dentry = real_lookup(base, &this, flags);
- if (IS_ERR(dentry))
- break;
- }
-
- /* Check mountpoints.. */
- dentry = follow_mount(dentry);
+ dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ break;
}
+ /* Check mountpoints.. */
+ while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+ ;
- base = do_follow_link(base, dentry, flags);
- if (IS_ERR(base))
- goto return_base;
+ err = -ENOENT;
+ inode = dentry->d_inode;
+ if (!inode)
+ break;
+ err = -ENOTDIR;
+ if (!inode->i_op)
+ break;
- inode = base->d_inode;
- if (flags & LOOKUP_DIRECTORY) {
+ if (inode->i_op->follow_link) {
+ err = do_follow_link(dentry, nd);
+ dput(dentry);
+ if (err)
+ goto return_err;
+ err = -ENOENT;
+ inode = nd->dentry->d_inode;
if (!inode)
- goto no_inode;
- dentry = ERR_PTR(-ENOTDIR);
+ break;
+ err = -ENOTDIR;
+ if (!inode->i_op)
+ break;
+ } else {
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ }
+ err = -ENOTDIR;
+ if (!inode->i_op->lookup)
+ break;
+ continue;
+ /* here ends the main loop */
+
+last_with_slashes:
+ lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+last_component:
+ if (lookup_flags & LOOKUP_PARENT)
+ goto lookup_parent;
+ if (this.name[0] == '.') switch (this.len) {
+ default:
+ break;
+ case 2:
+ if (this.name[1] != '.')
+ break;
+ if (nd->dentry != current->fs->root) {
+ dentry = dget(nd->dentry->d_covers->d_parent);
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ inode = dentry->d_inode;
+ }
+ /* fallthrough */
+ case 1:
+ goto return_base;
+ }
+ if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
+ err = nd->dentry->d_op->d_hash(nd->dentry, &this);
+ if (err < 0)
+ break;
+ }
+ dentry = cached_lookup(nd->dentry, &this, 0);
+ if (!dentry) {
+ dentry = real_lookup(nd->dentry, &this, 0);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ break;
+ }
+ while (d_mountpoint(dentry) && follow_down(&dentry, &nd->mnt))
+ ;
+ inode = dentry->d_inode;
+ if ((lookup_flags & LOOKUP_FOLLOW)
+ && inode && inode->i_op && inode->i_op->follow_link) {
+ err = do_follow_link(dentry, nd);
+ dput(dentry);
+ if (err)
+ goto return_err;
+ inode = nd->dentry->d_inode;
+ } else {
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ }
+ err = -ENOENT;
+ if (!inode)
+ goto no_inode;
+ if (lookup_flags & LOOKUP_DIRECTORY) {
+ err = -ENOTDIR;
if (!inode->i_op || !inode->i_op->lookup)
break;
- if (flags & LOOKUP_CONTINUE)
- continue;
}
-return_base:
- return base;
-/*
- * The case of a nonexisting file is special.
- *
- * In the middle of a pathname lookup (ie when
- * LOOKUP_CONTINUE is set), it's an obvious
- * error and returns ENOENT.
- *
- * At the end of a pathname lookup it's legal,
- * and we return a negative dentry. However, we
- * get here only if there were trailing slashes,
- * which is legal only if we know it's supposed
- * to be a directory (ie "mkdir"). Thus the
- * LOOKUP_SLASHOK flag.
- */
+ goto return_base;
no_inode:
- dentry = ERR_PTR(-ENOENT);
- if (flags & LOOKUP_CONTINUE)
+ err = -ENOENT;
+ if (lookup_flags & LOOKUP_POSITIVE)
break;
- if (flags & LOOKUP_SLASHOK)
- goto return_base;
- break;
+ if (lookup_flags & LOOKUP_DIRECTORY)
+ if (!(lookup_flags & LOOKUP_SLASHOK))
+ break;
+ goto return_base;
+lookup_parent:
+ nd->last = this;
+return_base:
+ return 0;
}
- dput(base);
- return dentry;
+ dput(nd->dentry);
+ mntput(nd->mnt);
+return_err:
+ return err;
+}
+
+/* returns 1 if everything is done */
+static int __emul_lookup_dentry(const char *name, int lookup_flags,
+ struct nameidata *nd)
+{
+ char *emul = __emul_prefix();
+
+ if (!emul)
+ return 0;
+
+ nd->mnt = mntget(current->fs->rootmnt);
+ nd->dentry = dget(current->fs->root);
+ if (walk_name(emul,LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE,nd))
+ return 0;
+ if (walk_name(name, lookup_flags, nd))
+ return 0;
+
+ if (!nd->dentry->d_inode) {
+ struct nameidata nd_root;
+ nd_root.last.len = 0;
+ nd_root.mnt = mntget(current->fs->rootmnt);
+ nd_root.dentry = dget(current->fs->root);
+ if (walk_name(name, lookup_flags, &nd_root))
+ return 1;
+ if (nd_root.dentry->d_inode) {
+ dput(nd->dentry);
+ mntput(nd->mnt);
+ nd->dentry = nd_root.dentry;
+ nd->mnt = nd_root.mnt;
+ nd->last = nd_root.last;
+ return 1;
+ }
+ dput(nd_root.dentry);
+ mntput(nd_root.mnt);
+ }
+ return 1;
+}
+
+static inline int
+walk_init_root(const char *name, unsigned flags, struct nameidata *nd)
+{
+ if (current->personality != PER_LINUX)
+ if (__emul_lookup_dentry(name,flags,nd));
+ return 0;
+ nd->mnt = mntget(current->fs->rootmnt);
+ nd->dentry = dget(current->fs->root);
+ return 1;
+}
+
+int walk_init(const char *name,unsigned int flags,struct nameidata *nd)
+{
+ nd->last.len = 0;
+ if (*name=='/')
+ return walk_init_root(name,flags,nd);
+ nd->mnt = mntget(current->fs->pwdmnt);
+ nd->dentry = dget(current->fs->pwd);
+ return 1;
+}
+
+struct dentry * lookup_dentry(const char * name, unsigned int lookup_flags)
+{
+ struct nameidata nd;
+ int err = 0;
+
+ if (walk_init(name, lookup_flags, &nd))
+ err = walk_name(name, lookup_flags, &nd);
+ if (!err) {
+ mntput(nd.mnt);
+ return nd.dentry;
+ }
+ return ERR_PTR(err);
}
/*
* Restricted form of lookup. Doesn't follow links, single-component only,
* needs parent already locked. Doesn't follow mounts.
*/
-struct dentry * lookup_one(const char * name, struct dentry * base)
+static inline struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
{
struct dentry * dentry;
struct inode *inode;
int err;
- unsigned long hash;
- struct qstr this;
- unsigned int c;
inode = base->d_inode;
err = permission(inode, MAY_EXEC);
@@ -469,36 +569,20 @@ struct dentry * lookup_one(const char * name, struct dentry * base)
if (err)
goto out;
- this.name = name;
- c = *(const unsigned char *)name;
- if (!c)
- goto access;
-
- hash = init_name_hash();
- do {
- name++;
- if (c == '/')
- goto access;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *)name;
- } while (c);
- this.len = name - (const char *) this.name;
- this.hash = end_name_hash(hash);
-
/*
* See if the low-level filesystem might want
* to use its own hash..
*/
if (base->d_op && base->d_op->d_hash) {
- err = base->d_op->d_hash(base, &this);
+ err = base->d_op->d_hash(base, name);
dentry = ERR_PTR(err);
if (err < 0)
goto out;
}
- dentry = cached_lookup(base, &this, 0);
+ dentry = cached_lookup(base, name, 0);
if (!dentry) {
- struct dentry *new = d_alloc(base, &this);
+ struct dentry *new = d_alloc(base, name);
dentry = ERR_PTR(-ENOMEM);
if (!new)
goto out;
@@ -515,9 +599,33 @@ struct dentry * lookup_one(const char * name, struct dentry * base)
out:
dput(base);
return dentry;
+}
+
+struct dentry * lookup_one(const char * name, struct dentry * base)
+{
+ unsigned long hash;
+ struct qstr this;
+ unsigned int c;
+
+ this.name = name;
+ c = *(const unsigned char *)name;
+ if (!c)
+ goto access;
+
+ hash = init_name_hash();
+ do {
+ name++;
+ if (c == '/')
+ goto access;
+ hash = partial_name_hash(c, hash);
+ c = *(const unsigned char *)name;
+ } while (c);
+ this.len = name - (const char *) this.name;
+ this.hash = end_name_hash(hash);
+
+ return lookup_hash(&this, base);
access:
- dentry = ERR_PTR(-EACCES);
- goto out;
+ return ERR_PTR(-EACCES);
}
/*
@@ -538,14 +646,8 @@ struct dentry * __namei(const char *pathname, unsigned int lookup_flags)
name = getname(pathname);
dentry = (struct dentry *) name;
if (!IS_ERR(name)) {
- dentry = lookup_dentry(name, NULL, lookup_flags);
+ dentry = lookup_dentry(name,lookup_flags|LOOKUP_POSITIVE);
putname(name);
- if (!IS_ERR(dentry)) {
- if (!dentry->d_inode) {
- dput(dentry);
- dentry = ERR_PTR(-ENOENT);
- }
- }
}
return dentry;
}
@@ -600,7 +702,7 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir)
return -ENOTDIR;
if (IS_ROOT(victim))
return -EBUSY;
- if (victim->d_mounts != victim->d_covers)
+ if (d_mountpoint(victim))
return -EBUSY;
} else if (S_ISDIR(victim->d_inode->i_mode))
return -EISDIR;
@@ -639,7 +741,7 @@ static inline int lookup_flags(unsigned int f)
if (f & O_DIRECTORY)
retval |= LOOKUP_DIRECTORY;
-
+
return retval;
}
@@ -679,64 +781,92 @@ exit_lock:
* which is a lot more logical, and also allows the "no perm" needed
* for symlinks (where the permissions are checked later).
*/
-struct dentry * __open_namei(const char * pathname, int flag, int mode, struct dentry * dir)
+int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
{
- int acc_mode, error;
+ int acc_mode, error = 0;
struct inode *inode;
struct dentry *dentry;
- dentry = lookup_dentry(pathname, dir, lookup_flags(flag));
- if (IS_ERR(dentry))
- return dentry;
-
acc_mode = ACC_MODE(flag);
- if (flag & O_CREAT) {
+ if (!(flag & O_CREAT)) {
+ if (walk_init(pathname, lookup_flags(flag), nd))
+ error = walk_name(pathname, lookup_flags(flag), nd);
+ if (error)
+ return error;
+
+ dentry = nd->dentry;
+ } else {
struct dentry *dir;
- if (dentry->d_inode) {
- if (!(flag & O_EXCL))
- goto nocreate;
- error = -EEXIST;
+ if (walk_init(pathname, LOOKUP_PARENT, nd))
+ error = walk_name(pathname, LOOKUP_PARENT, nd);
+ if (error)
+ return error;
+ /*
+ * It's not obvious that open(".", O_CREAT, foo) should
+ * fail, but it's even less obvious that it should succeed.
+ * Since O_CREAT means an intention to create the thing and
+ * open(2) had never created directories, count it as caller's
+ * luserdom and let him sod off - -EISDIR it is.
+ */
+ error = -EISDIR;
+ if (!nd->last.len || (nd->last.name[0] == '.' &&
+ (nd->last.len == 1 ||
+ (nd->last.name[1] == '.' && nd->last.len == 2))))
+ goto exit;
+ /* same for foo/ */
+ if (nd->last.name[nd->last.len])
goto exit;
- }
- dir = lock_parent(dentry);
- if (!check_parent(dir, dentry)) {
- /*
- * Really nasty race happened. What's the
- * right error code? We had a dentry, but
- * before we could use it it was removed
- * by somebody else. We could just re-try
- * everything, I guess.
- *
- * ENOENT is definitely wrong.
- */
- error = -ENOENT;
- unlock_dir(dir);
+ dir = dget(nd->dentry);
+ down(&dir->d_inode->i_sem);
+
+ dentry = lookup_hash(&nd->last, dget(nd->dentry));
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry)) {
+ up(&dir->d_inode->i_sem);
+ dput(dir);
goto exit;
}
- /*
- * Somebody might have created the file while we
- * waited for the directory lock.. So we have to
- * re-do the existence test.
- */
if (dentry->d_inode) {
- error = 0;
+ up(&dir->d_inode->i_sem);
+ dput(dir);
+ error = -EEXIST;
if (flag & O_EXCL)
- error = -EEXIST;
+ goto exit;
+ if (dentry->d_inode->i_op &&
+ dentry->d_inode->i_op->follow_link) {
+ /*
+ * With O_EXCL it would be -EEXIST.
+ * If symlink is a dangling one it's -ENOENT.
+ * Otherwise we open the object it points to.
+ */
+ error = do_follow_link(dentry, nd);
+ dput(dentry);
+ if (error)
+ return error;
+ dentry = nd->dentry;
+ } else {
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ }
+ error = -EISDIR;
+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
+ goto exit;
} else {
- error = vfs_create(dir->d_inode, dentry,mode);
+ error = vfs_create(dir->d_inode, dentry, mode);
/* Don't check for write permission, don't truncate */
acc_mode = 0;
flag &= ~O_TRUNC;
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ unlock_dir(dir);
+ if (error)
+ goto exit;
}
- unlock_dir(dir);
- if (error)
- goto exit;
}
-nocreate:
error = -ENOENT;
inode = dentry->d_inode;
if (!inode)
@@ -804,11 +934,45 @@ nocreate:
if (flag & FMODE_WRITE)
DQUOT_INIT(inode);
- return dentry;
+ return 0;
exit:
+ dput(nd->dentry);
+ mntput(nd->mnt);
+ return error;
+}
+
+static struct dentry *lookup_create(const char *name, int is_dir)
+{
+ struct nameidata nd;
+ struct dentry *dentry;
+ int err = 0;
+ if (walk_init(name, LOOKUP_PARENT, &nd))
+ err = walk_name(name, LOOKUP_PARENT, &nd);
+ dentry = ERR_PTR(err);
+ if (err)
+ goto out;
+ down(&nd.dentry->d_inode->i_sem);
+ dentry = ERR_PTR(-EEXIST);
+ if (!nd.last.len || (nd.last.name[0] == '.' &&
+ (nd.last.len == 1 || (nd.last.name[1] == '.' && nd.last.len == 2))))
+ goto fail;
+ dentry = lookup_hash(&nd.last, dget(nd.dentry));
+ if (IS_ERR(dentry))
+ goto fail;
+ if (!is_dir && nd.last.name[nd.last.len] && !dentry->d_inode)
+ goto enoent;
+out_dput:
+ dput(nd.dentry);
+ mntput(nd.mnt);
+out:
+ return dentry;
+enoent:
dput(dentry);
- return ERR_PTR(error);
+ dentry = ERR_PTR(-ENOENT);
+fail:
+ up(&nd.dentry->d_inode->i_sem);
+ goto out_dput;
}
int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
@@ -842,18 +1006,14 @@ struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
struct dentry *dir;
struct dentry *dentry, *retval;
- dentry = lookup_dentry(filename, NULL, 0);
+ dentry = lookup_create(filename, 0);
if (IS_ERR(dentry))
return dentry;
- dir = lock_parent(dentry);
- error = -ENOENT;
- if (!check_parent(dir, dentry))
- goto exit_lock;
+ dir = dget(dentry->d_parent);
error = vfs_mknod(dir->d_inode, dentry, mode, dev);
-exit_lock:
retval = ERR_PTR(error);
if (!error)
retval = dget(dentry);
@@ -875,14 +1035,11 @@ asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
return PTR_ERR(tmp);
lock_kernel();
- dentry = lookup_dentry(tmp, NULL, 0);
+ dentry = lookup_create(tmp, 0);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out;
- dir = lock_parent(dentry);
- error = -ENOENT;
- if (!check_parent(dir, dentry))
- goto out_unlock;
+ dir = dget(dentry->d_parent);
switch (mode & S_IFMT) {
case 0: case S_IFREG:
error = vfs_create(dir->d_inode, dentry, mode);
@@ -896,7 +1053,6 @@ asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
default:
error = -EINVAL;
}
-out_unlock:
unlock_dir(dir);
dput(dentry);
out:
@@ -928,50 +1084,28 @@ exit_lock:
return error;
}
-static inline int do_mkdir(const char * pathname, int mode)
-{
- int error;
- struct dentry *dir;
- struct dentry *dentry;
-
- dentry = lookup_dentry(pathname, NULL, LOOKUP_SLASHOK);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto exit;
-
- /*
- * EEXIST is kind of a strange error code to
- * return, but basically if the dentry was moved
- * or unlinked while we locked the parent, we
- * do know that it _did_ exist before, and as
- * such it makes perfect sense.. In contrast,
- * ENOENT doesn't make sense for mkdir.
- */
- dir = lock_parent(dentry);
- error = -EEXIST;
- if (!check_parent(dir, dentry))
- goto exit_lock;
-
- error = vfs_mkdir(dir->d_inode, dentry, mode);
-
-exit_lock:
- unlock_dir(dir);
- dput(dentry);
-exit:
- return error;
-}
-
asmlinkage long sys_mkdir(const char * pathname, int mode)
{
int error;
char * tmp;
tmp = getname(pathname);
- if(IS_ERR(tmp))
- return PTR_ERR(tmp);
- lock_kernel();
- error = do_mkdir(tmp,mode);
- unlock_kernel();
+ error = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
+ struct dentry *dir;
+ struct dentry *dentry;
+
+ lock_kernel();
+ dentry = lookup_create(tmp, 1);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ dir = dget(dentry->d_parent);
+ error = vfs_mkdir(dir->d_inode, dentry, mode);
+ unlock_dir(dir);
+ dput(dentry);
+ }
+ unlock_kernel();
+ }
putname(tmp);
return error;
@@ -1033,7 +1167,7 @@ static inline int do_rmdir(const char * name)
struct dentry *dir;
struct dentry *dentry;
- dentry = lookup_dentry(name, NULL, 0);
+ dentry = lookup_dentry(name, LOOKUP_POSITIVE);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto exit;
@@ -1082,13 +1216,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
return error;
}
-int do_unlink(const char * name, struct dentry * base)
+static int do_unlink(const char * name)
{
int error;
struct dentry *dir;
struct dentry *dentry;
- dentry = lookup_dentry(name, base, 0);
+ dentry = lookup_dentry(name, LOOKUP_POSITIVE);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto exit;
@@ -1113,7 +1247,7 @@ asmlinkage long sys_unlink(const char * pathname)
if(IS_ERR(tmp))
return PTR_ERR(tmp);
lock_kernel();
- error = do_unlink(tmp, NULL);
+ error = do_unlink(tmp);
unlock_kernel();
putname(tmp);
@@ -1141,32 +1275,6 @@ exit_lock:
return error;
}
-static inline int do_symlink(const char * oldname, const char * newname)
-{
- int error;
- struct dentry *dir;
- struct dentry *dentry;
-
- dentry = lookup_dentry(newname, NULL, 0);
-
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto exit;
-
- dir = lock_parent(dentry);
- error = -ENOENT;
- if (!check_parent(dir, dentry))
- goto exit_lock;
-
- error = vfs_symlink(dir->d_inode, dentry, oldname);
-
-exit_lock:
- unlock_dir(dir);
- dput(dentry);
-exit:
- return error;
-}
-
asmlinkage long sys_symlink(const char * oldname, const char * newname)
{
int error;
@@ -1179,8 +1287,18 @@ asmlinkage long sys_symlink(const char * oldname, const char * newname)
to = getname(newname);
error = PTR_ERR(to);
if (!IS_ERR(to)) {
+ struct dentry *dir;
+ struct dentry *dentry;
+
lock_kernel();
- error = do_symlink(from,to);
+ dentry = lookup_create(to, 0);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ dir = dget(dentry->d_parent);
+ error = vfs_symlink(dir->d_inode, dentry, from);
+ unlock_dir(dir);
+ dput(dentry);
+ }
unlock_kernel();
putname(to);
}
@@ -1224,51 +1342,20 @@ exit_lock:
return error;
}
-static inline int do_link(const char * oldname, const char * newname)
-{
- struct dentry *old_dentry, *new_dentry, *dir;
- int error;
-
- /*
- * Hardlinks are often used in delicate situations. We avoid
- * security-related surprises by not following symlinks on the
- * newname. --KAB
- *
- * We don't follow them on the oldname either to be compatible
- * with linux 2.0, and to avoid hard-linking to directories
- * and other special files. --ADM
- */
- old_dentry = lookup_dentry(oldname, NULL, 0);
- error = PTR_ERR(old_dentry);
- if (IS_ERR(old_dentry))
- goto exit;
-
- new_dentry = lookup_dentry(newname, NULL, 0);
- error = PTR_ERR(new_dentry);
- if (IS_ERR(new_dentry))
- goto exit_old;
-
- dir = lock_parent(new_dentry);
- error = -ENOENT;
- if (!check_parent(dir, new_dentry))
- goto exit_lock;
-
- error = vfs_link(old_dentry, dir->d_inode, new_dentry);
-
-exit_lock:
- unlock_dir(dir);
- dput(new_dentry);
-exit_old:
- dput(old_dentry);
-exit:
- return error;
-}
-
+/*
+ * Hardlinks are often used in delicate situations. We avoid
+ * security-related surprises by not following symlinks on the
+ * newname. --KAB
+ *
+ * We don't follow them on the oldname either to be compatible
+ * with linux 2.0, and to avoid hard-linking to directories
+ * and other special files. --ADM
+ */
asmlinkage long sys_link(const char * oldname, const char * newname)
{
int error;
char * from;
- char * to;
+ char * to;
from = getname(oldname);
if(IS_ERR(from))
@@ -1276,8 +1363,24 @@ asmlinkage long sys_link(const char * oldname, const char * newname)
to = getname(newname);
error = PTR_ERR(to);
if (!IS_ERR(to)) {
+ struct dentry *old_dentry, *new_dentry, *dir;
+
lock_kernel();
- error = do_link(from,to);
+ old_dentry = lookup_dentry(from, LOOKUP_POSITIVE);
+ error = PTR_ERR(old_dentry);
+ if (IS_ERR(old_dentry))
+ goto exit;
+
+ new_dentry = lookup_create(to, 0);
+ error = PTR_ERR(new_dentry);
+ if (!IS_ERR(new_dentry)) {
+ dir = dget(new_dentry->d_parent);
+ error = vfs_link(old_dentry, dir->d_inode, new_dentry);
+ unlock_dir(dir);
+ dput(new_dentry);
+ }
+ dput(old_dentry);
+exit:
unlock_kernel();
putname(to);
}
@@ -1435,21 +1538,17 @@ static inline int do_rename(const char * oldname, const char * newname)
struct dentry * old_dir, * new_dir;
struct dentry * old_dentry, *new_dentry;
- old_dentry = lookup_dentry(oldname, NULL, 0);
+ old_dentry = lookup_dentry(oldname, LOOKUP_POSITIVE);
error = PTR_ERR(old_dentry);
if (IS_ERR(old_dentry))
goto exit;
- error = -ENOENT;
- if (!old_dentry->d_inode)
- goto exit_old;
-
{
unsigned int flags = 0;
if (S_ISDIR(old_dentry->d_inode->i_mode))
flags = LOOKUP_SLASHOK;
- new_dentry = lookup_dentry(newname, NULL, flags);
+ new_dentry = lookup_dentry(newname, flags);
}
error = PTR_ERR(new_dentry);
@@ -1512,29 +1611,30 @@ out:
return len;
}
-static inline struct dentry *
-__vfs_follow_link(struct dentry *dentry, struct dentry *base,
- unsigned follow, const char *link)
+static inline int
+__vfs_follow_link(struct nameidata *nd, const char *link)
{
- struct dentry *result;
- UPDATE_ATIME(dentry->d_inode);
-
if (IS_ERR(link))
goto fail;
- result = lookup_dentry(link, base, follow);
- return result;
+ if (*link == '/') {
+ dput(nd->dentry);
+ mntput(nd->mnt);
+ if (!walk_init_root(link, LOOKUP_FOLLOW, nd))
+ /* weird __emul_prefix() stuff did it */
+ return 0;
+ }
+ return walk_name(link, LOOKUP_FOLLOW, nd);
fail:
- dput(base);
- return (struct dentry *)link;
+ dput(nd->dentry);
+ mntput(nd->mnt);
+ return PTR_ERR(link);
}
-struct dentry *
-vfs_follow_link(struct dentry *dentry, struct dentry *base,
-unsigned int follow, const char *link)
+int vfs_follow_link(struct nameidata *nd, const char *link)
{
- return __vfs_follow_link(dentry,base,follow,link);
+ return __vfs_follow_link(nd, link);
}
/* get the link contents into pagecache */
@@ -1572,12 +1672,11 @@ int page_readlink(struct dentry *dentry, char *buffer, int buflen)
return res;
}
-struct dentry *
-page_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
+int page_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct page *page = NULL;
char *s = page_getlink(dentry, &page);
- struct dentry *res = __vfs_follow_link(dentry,base,follow,s);
+ int res = __vfs_follow_link(nd, s);
if (page) {
kunmap(page);
page_cache_release(page);
diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in
index a9909cb49..104f5a3c7 100644
--- a/fs/ncpfs/Config.in
+++ b/fs/ncpfs/Config.in
@@ -1,13 +1,13 @@
#
# NCP Filesystem configuration
#
-bool ' Packet signatures' CONFIG_NCPFS_PACKET_SIGNING
-bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
-bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
-bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
-bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
-bool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
-bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
-bool ' NDS authentication support' CONFIG_NCPFS_NDS_DOMAINS
-bool ' Use Native Language Support' CONFIG_NCPFS_NLS
-bool ' Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
+dep_mbool ' Packet signatures' CONFIG_NCPFS_PACKET_SIGNING $CONFIG_NCP_FS
+dep_mbool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING $CONFIG_NCP_FS
+dep_mbool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG $CONFIG_NCP_FS
+dep_mbool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS $CONFIG_NCP_FS
+dep_mbool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS $CONFIG_NCP_FS
+dep_mbool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS $CONFIG_NCP_FS
+dep_mbool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR $CONFIG_NCP_FS
+dep_mbool ' NDS authentication support' CONFIG_NCPFS_NDS_DOMAINS $CONFIG_NCP_FS
+dep_mbool ' Use Native Language Support' CONFIG_NCPFS_NLS $CONFIG_NCP_FS
+dep_mbool ' Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS $CONFIG_NCP_FS
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 3c8aac510..64ef9274b 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -14,6 +14,9 @@ O_OBJS := inode.o file.o read.o write.o dir.o symlink.o proc.o \
ifdef CONFIG_ROOT_NFS
O_OBJS += nfsroot.o mount_clnt.o
endif
+ifdef CONFIG_NFS_V3
+ O_OBJS += nfs3proc.o nfs3xdr.o
+endif
M_OBJS := $(O_TARGET)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 3ca240129..7d80e6468 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -17,7 +17,6 @@
* 6 Jun 1999 Cache readdir lookups in the page cache. -DaveM
*/
-#define NFS_NEED_XDR_TYPES
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/stat.h>
@@ -28,7 +27,7 @@
#include <linux/mm.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
-#include <linux/nfs.h>
+#include <linux/nfs_mount.h>
#include <linux/pagemap.h>
#include <asm/segment.h> /* for fs functions */
@@ -71,202 +70,131 @@ struct inode_operations nfs_dir_inode_operations = {
setattr: nfs_notify_change,
};
-/* Each readdir response is composed of entries which look
- * like the following, as per the NFSv2 RFC:
- *
- * __u32 not_end zero if end of response
- * __u32 file ID opaque ino_t
- * __u32 namelen size of name string
- * VAR name string the string, padded to modulo 4 bytes
- * __u32 cookie opaque ID of next entry
- *
- * When you hit not_end being zero, the next __u32 is non-zero if
- * this is the end of the complete set of readdir entires for this
- * directory. This can be used, for example, to initiate pre-fetch.
- *
- * In order to know what to ask the server for, we only need to know
- * the final cookie of the previous page, and offset zero has cookie
- * zero, so we cache cookie to page offset translations in chunks.
- */
-#define COOKIES_PER_CHUNK (8 - ((sizeof(void *) / sizeof(__u32))))
-struct nfs_cookie_table {
- struct nfs_cookie_table *next;
- __u32 cookies[COOKIES_PER_CHUNK];
-};
-static kmem_cache_t *nfs_cookie_cachep;
+typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
-/* This whole scheme relies on the fact that dirent cookies
- * are monotonically increasing.
- *
- * Another invariant is that once we have a valid non-zero
- * EOF marker cached, we also have the complete set of cookie
- * table entries.
+/*
+ * Given a pointer to a buffer that has already been filled by a call
+ * to readdir, find the next entry.
*
- * We return the page offset assosciated with the page where
- * cookie must be if it exists at all, however if we can not
- * figure that out conclusively, we return < 0.
+ * If the end of the buffer has been reached, return -EAGAIN, if not,
+ * return the offset within the buffer of the next entry to be
+ * read.
*/
-static long __nfs_readdir_offset(struct inode *inode, __u32 cookie)
+static inline
+long find_dirent(struct page *page, loff_t offset,
+ struct nfs_entry *entry,
+ decode_dirent_t decode, int plus, int use_cookie)
{
- struct nfs_cookie_table *p;
- unsigned long ret = 0;
-
- for(p = NFS_COOKIES(inode); p != NULL; p = p->next) {
- int i;
-
- for (i = 0; i < COOKIES_PER_CHUNK; i++) {
- __u32 this_cookie = p->cookies[i];
-
- /* End of known cookies, EOF is our only hope. */
- if (!this_cookie)
- goto check_eof;
-
- /* Next cookie is larger, must be in previous page. */
- if (this_cookie > cookie)
- return ret;
-
- ret += 1;
-
- /* Exact cookie match, it must be in this page :-) */
- if (this_cookie == cookie)
- return ret;
+ u8 *p = (u8 *)kmap(page),
+ *start = p;
+ unsigned long base = page_offset(page),
+ pg_offset = 0;
+ int loop_count = 0;
+
+ if (!p)
+ return -EIO;
+ for(;;) {
+ p = (u8*)decode((__u32*)p, entry, plus);
+ if (IS_ERR(p))
+ break;
+ pg_offset = p - start;
+ entry->prev = entry->offset;
+ entry->offset = base + pg_offset;
+ if ((use_cookie ? entry->cookie : entry->offset) > offset)
+ break;
+ if (loop_count++ > 200) {
+ loop_count = 0;
+ schedule();
}
}
-check_eof:
- if (NFS_DIREOF(inode) != 0)
- return ret;
- return -1L;
-}
-
-static __inline__ long nfs_readdir_offset(struct inode *inode, __u32 cookie)
-{
- /* Cookie zero is always at page offset zero. Optimize the
- * other common case since most directories fit entirely
- * in one page.
- */
- if (!cookie || (!NFS_COOKIES(inode) && NFS_DIREOF(inode)))
- return 0;
- return __nfs_readdir_offset(inode, cookie);
+ kunmap(page);
+ return (IS_ERR(p)) ? PTR_ERR(p) : (long)pg_offset;
}
-/* Since a cookie of zero is declared special by the NFS
- * protocol, we easily can tell if a cookie in an existing
- * table chunk is valid or not.
+/*
+ * Find the given page, and call find_dirent() in order to try to
+ * return the next entry.
*
- * NOTE: The cookies are indexed off-by-one because zero
- * need not an entry.
+ * Returns -EIO if the page is not available, or up to date.
*/
-static __inline__ __u32 *find_cookie(struct inode *inode, unsigned long off)
+static inline
+long find_dirent_page(struct inode *inode, loff_t offset,
+ struct nfs_entry *entry)
{
- static __u32 cookie_zero = 0;
- struct nfs_cookie_table *p;
- __u32 *ret;
-
- if (!off)
- return &cookie_zero;
- off -= 1;
- p = NFS_COOKIES(inode);
- while(off >= COOKIES_PER_CHUNK && p) {
- off -= COOKIES_PER_CHUNK;
- p = p->next;
- }
- ret = NULL;
- if (p) {
- ret = &p->cookies[off];
- if (!*ret)
- ret = NULL;
- }
- return ret;
-}
+ decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent;
+ struct page *page;
+ unsigned long index = entry->offset >> PAGE_CACHE_SHIFT;
+ long status = -EIO;
+ int plus = NFS_USE_READDIRPLUS(inode),
+ use_cookie = NFS_MONOTONE_COOKIES(inode);
-#define NFS_NAMELEN_ALIGN(__len) ((((__len)+3)>>2)<<2)
-static int create_cookie(__u32 cookie, unsigned long off, struct inode *inode)
-{
- struct nfs_cookie_table **cpp;
+ dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", entry->offset & PAGE_CACHE_MASK);
- cpp = (struct nfs_cookie_table **) &NFS_COOKIES(inode);
- while (off >= COOKIES_PER_CHUNK && *cpp) {
- off -= COOKIES_PER_CHUNK;
- cpp = &(*cpp)->next;
- }
- if (*cpp) {
- (*cpp)->cookies[off] = cookie;
- } else {
- struct nfs_cookie_table *new;
- int i;
-
- new = kmem_cache_alloc(nfs_cookie_cachep, SLAB_ATOMIC);
- if(!new)
- return -1;
- *cpp = new;
- new->next = NULL;
- for(i = 0; i < COOKIES_PER_CHUNK; i++) {
- if (i == off) {
- new->cookies[i] = cookie;
- } else {
- new->cookies[i] = 0;
- }
- }
- }
- return 0;
+ if (entry->page)
+ page_cache_release(entry->page);
+
+ page = find_get_page(&inode->i_data, index);
+
+ if (page && Page_Uptodate(page))
+ status = find_dirent(page, offset, entry, decode, plus, use_cookie);
+
+ /* NB: on successful return we will be holding the page */
+ if (status < 0) {
+ entry->page = NULL;
+ if (page)
+ page_cache_release(page);
+ } else
+ entry->page = page;
+
+ dfprintk(VFS, "NFS: find_dirent_page() returns %ld\n", status);
+ return status;
}
-static struct page *try_to_get_dirent_page(struct file *, __u32, int);
-/* Recover from a revalidation flush. The case here is that
- * the inode for the directory got invalidated somehow, and
- * all of our cached information is lost. In order to get
- * a correct cookie for the current readdir request from the
- * user, we must (re-)fetch older readdir page cache entries.
+/*
+ * Recurse through the page cache pages, and return a
+ * filled nfs_entry structure of the next directory entry if possible.
*
- * Returns < 0 if some error occurrs, else it is the page offset
- * to fetch.
+ * The target for the search is position 'offset'.
+ * The latter may either be an offset into the page cache, or (better)
+ * a cookie depending on whether we're interested in strictly following
+ * the RFC wrt. not assuming monotonicity of cookies or not.
+ *
+ * For most systems, the latter is more reliable since it naturally
+ * copes with holes in the directory.
*/
-static long refetch_to_readdir_cookie(struct file *file, struct inode *inode)
+static inline
+long search_cached_dirent_pages(struct inode *inode, loff_t offset,
+ struct nfs_entry *entry)
{
- struct page *page;
- u32 goal_cookie = file->f_pos;
- long cur_off, ret = -1L;
+ long res = 0;
+ int loop_count = 0;
-again:
- cur_off = 0;
+ dfprintk(VFS, "NFS: search_cached_dirent_pages() searching for cookie %Ld\n", (long long)offset);
for (;;) {
- page = find_get_page(&inode->i_data, cur_off);
- if (page) {
- if (!Page_Uptodate(page))
- goto out_error;
- } else {
- __u32 *cp = find_cookie(inode, cur_off);
-
- if (!cp)
- goto out_error;
-
- page = try_to_get_dirent_page(file, *cp, 0);
- if (!page) {
- if (!cur_off)
- goto out_error;
-
- /* Someone touched the dir on us. */
- goto again;
- }
+ res = find_dirent_page(inode, offset, entry);
+ if (res == -EAGAIN) {
+ /* Align to beginning of next page */
+ entry->offset &= PAGE_CACHE_MASK;
+ entry->offset += PAGE_CACHE_SIZE;
+ }
+ if (res != -EAGAIN)
+ break;
+ if (loop_count++ > 200) {
+ loop_count = 0;
+ schedule();
}
- page_cache_release(page);
-
- if ((ret = nfs_readdir_offset(inode, goal_cookie)) >= 0)
- goto out;
-
- cur_off += 1;
}
-out:
- return ret;
-
-out_error:
- if (page)
- page_cache_release(page);
- goto out;
+ if (res < 0 && entry->page) {
+ page_cache_release(entry->page);
+ entry->page = NULL;
+ }
+ dfprintk(VFS, "NFS: search_cached_dirent_pages() returned %ld\n", res);
+ return res;
}
+
/* Now we cache directories properly, by stuffing the dirent
* data directly in the page cache.
*
@@ -279,198 +207,240 @@ out_error:
* page-in of the RPC reply, nowhere else, this simplies
* things substantially.
*/
-
-static int nfs_dir_filler(struct dentry *dentry, struct page *page)
+static inline
+long try_to_get_dirent_page(struct file *file, struct inode *inode,
+ struct nfs_entry *entry)
{
- struct nfs_readdirargs rd_args;
- struct nfs_readdirres rd_res;
- struct inode *inode = dentry->d_inode;
- long offset = page->index;
- __u32 *cookiep;
- int err;
+ struct dentry *dir = file->f_dentry;
+ struct page *page;
+ __u32 *p;
+ unsigned long index = entry->offset >> PAGE_CACHE_SHIFT;
+ long res = 0;
+ unsigned int dtsize = NFS_SERVER(inode)->dtsize;
+ int plus = NFS_USE_READDIRPLUS(inode);
- kmap(page);
+ dfprintk(VFS, "NFS: try_to_get_dirent_page() reading directory page @ index %ld\n", index);
- err = -EIO;
- cookiep = find_cookie(inode, offset);
- if (!cookiep)
- goto fail;
+ page = grab_cache_page(&inode->i_data, index);
- rd_args.fh = NFS_FH(dentry);
- rd_res.buffer = (char *)page_address(page);
- rd_res.bufsiz = PAGE_CACHE_SIZE;
- rd_res.cookie = *cookiep;
- do {
- rd_args.buffer = rd_res.buffer;
- rd_args.bufsiz = rd_res.bufsiz;
- rd_args.cookie = rd_res.cookie;
- err = rpc_call(NFS_CLIENT(inode),
- NFSPROC_READDIR, &rd_args, &rd_res, 0);
- if (err < 0)
- goto fail;
- } while(rd_res.bufsiz > 0);
-
- err = -EIO;
- if (rd_res.bufsiz < 0)
- NFS_DIREOF(inode) = rd_res.cookie;
- else if (create_cookie(rd_res.cookie, offset, inode))
- goto fail;
+ if (!page) {
+ res = -ENOMEM;
+ goto out;
+ }
- SetPageUptodate(page);
- kunmap(page);
- UnlockPage(page);
- return 0;
-fail:
- SetPageError(page);
- kunmap(page);
- UnlockPage(page);
- return err;
-}
+ if (Page_Uptodate(page)) {
+ dfprintk(VFS, "NFS: try_to_get_dirent_page(): page already up to date.\n");
+ goto unlock_out;
+ }
-static struct page *try_to_get_dirent_page(struct file *file, __u32 cookie, int refetch_ok)
-{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct page *page;
- long offset;
+ p = (__u32 *)kmap(page);
- if ((offset = nfs_readdir_offset(inode, cookie)) < 0) {
- if (!refetch_ok ||
- (offset = refetch_to_readdir_cookie(file, inode)) < 0) {
- goto fail;
- }
- }
+ if (dtsize > PAGE_CACHE_SIZE)
+ dtsize = PAGE_CACHE_SIZE;
+ res = NFS_PROTO(inode)->readdir(dir, entry->cookie, p, dtsize, plus);
+
+ kunmap(page);
- page = read_cache_page(&inode->i_data, offset,
- (filler_t *)nfs_dir_filler, dentry);
- if (IS_ERR(page))
- goto fail;
- if (!Page_Uptodate(page))
- goto fail2;
- return page;
+ if (res < 0)
+ goto error;
+ if (PageError(page))
+ ClearPageError(page);
+ SetPageUptodate(page);
-fail2:
+ unlock_out:
+ UnlockPage(page);
page_cache_release(page);
-fail:
- return NULL;
+ out:
+ dfprintk(VFS, "NFS: try_to_get_dirent_page() returns %ld\n", res);
+ return res;
+ error:
+ SetPageError(page);
+ goto unlock_out;
}
-/* Seek up to dirent assosciated with the passed in cookie,
- * then fill in dirents found. Return the last cookie
- * actually given to the user, to update the file position.
+/* Recover from a revalidation flush. The case here is that
+ * the inode for the directory got invalidated somehow, and
+ * all of our cached information is lost. In order to get
+ * a correct cookie for the current readdir request from the
+ * user, we must (re-)fetch all the older readdir page cache
+ * entries.
+ *
+ * Returns < 0 if some error occurs.
*/
-static __inline__ u32 nfs_do_filldir(__u32 *p, u32 cookie,
- void *dirent, filldir_t filldir)
+static inline
+long refetch_to_readdir(struct file *file, struct inode *inode,
+ loff_t off, struct nfs_entry *entry)
{
- u32 end;
-
- while((end = *p++) != 0) {
- __u32 fileid, len, skip, this_cookie;
- char *name;
+ struct nfs_entry my_dirent,
+ *dirent = &my_dirent;
+ long res;
+ int plus = NFS_USE_READDIRPLUS(inode),
+ use_cookie = NFS_MONOTONE_COOKIES(inode),
+ loop_count = 0;
+
+ dfprintk(VFS, "NFS: refetch_to_readdir() searching for cookie %Ld\n", (long long)off);
+ *dirent = *entry;
+ entry->page = NULL;
+
+ for (res = 0;res >= 0;) {
+ if (loop_count++ > 200) {
+ loop_count = 0;
+ schedule();
+ }
- fileid = *p++;
- len = *p++;
- name = (char *) p;
- skip = NFS_NAMELEN_ALIGN(len);
- p += (skip >> 2);
- this_cookie = *p++;
+ /* Search for last cookie in page cache */
+ res = search_cached_dirent_pages(inode, off, dirent);
- if (this_cookie < cookie)
+ if (res >= 0) {
+ /* Cookie was found */
+ if ((use_cookie?dirent->cookie:dirent->offset) > off) {
+ *entry = *dirent;
+ dirent->page = NULL;
+ break;
+ }
continue;
+ }
+
+ if (dirent->page)
+ page_cache_release(dirent->page);
+ dirent->page = NULL;
- cookie = this_cookie;
- if (filldir(dirent, name, len, cookie, fileid) < 0)
+ if (res != -EIO) {
+ *entry = *dirent;
break;
+ }
+
+ /* Read in a new page */
+ res = try_to_get_dirent_page(file, inode, dirent);
+ if (res == -EBADCOOKIE) {
+ memset(dirent, 0, sizeof(*dirent));
+ nfs_zap_caches(inode);
+ res = 0;
+ }
+ /* We requested READDIRPLUS, but the server doesn't grok it */
+ if (plus && res == -ENOTSUPP) {
+ NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+ memset(dirent, 0, sizeof(*dirent));
+ nfs_zap_caches(inode);
+ plus = 0;
+ res = 0;
+ }
}
+ if (dirent->page)
+ page_cache_release(dirent->page);
- return cookie;
+ dfprintk(VFS, "NFS: refetch_to_readdir() returns %ld\n", res);
+ return res;
}
-/* The file offset position is represented in pure bytes, to
- * make the page cache interface straight forward.
- *
- * However, some way is needed to make the connection between the
- * opaque NFS directory entry cookies and our offsets, so a per-inode
- * cookie cache table is used.
+/*
+ * Once we've found the start of the dirent within a page: fill 'er up...
*/
-static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static
+int nfs_do_filldir(struct file *file, struct inode *inode,
+ struct nfs_entry *entry, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct page *page;
- long offset;
- int res;
-
- res = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
- if (res < 0)
- return res;
-
- if (NFS_DIREOF(inode) && filp->f_pos >= NFS_DIREOF(inode))
- return 0;
-
- if ((offset = nfs_readdir_offset(inode, filp->f_pos)) < 0)
- goto no_dirent_page;
-
- page = find_get_page(&inode->i_data, offset);
- if (!page)
- goto no_dirent_page;
- if (!Page_Uptodate(page))
- goto dirent_read_error;
-success:
- kmap(page);
- filp->f_pos = nfs_do_filldir((__u32 *) page_address(page),
- filp->f_pos, dirent, filldir);
+ decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent;
+ struct page *page = entry->page;
+ __u8 *p,
+ *start;
+ unsigned long base = page_offset(page),
+ offset = entry->offset,
+ pg_offset,
+ fileid;
+ int plus = NFS_USE_READDIRPLUS(inode),
+ use_cookie = NFS_MONOTONE_COOKIES(inode),
+ loop_count = 0,
+ res = 0;
+
+ dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ offset %ld\n", entry->offset);
+ pg_offset = offset & ~PAGE_CACHE_MASK;
+ start = (u8*)kmap(page);
+ p = start + pg_offset;
+
+ for(;;) {
+ /* Note: entry->prev contains the offset of the start of the
+ * current dirent */
+ fileid = nfs_fileid_to_ino_t(entry->ino);
+ if (use_cookie)
+ res = filldir(dirent, entry->name, entry->len, entry->prev_cookie, fileid);
+ else
+ res = filldir(dirent, entry->name, entry->len, entry->prev, fileid);
+ if (res < 0)
+ break;
+ file->f_pos = (use_cookie) ? entry->cookie : entry->offset;
+ p = (u8*)decode((__u32*)p, entry, plus);
+ if (!p || IS_ERR(p))
+ break;
+ pg_offset = p - start;
+ entry->prev = entry->offset;
+ entry->offset = base + pg_offset;
+ if (loop_count++ > 200) {
+ loop_count = 0;
+ schedule();
+ }
+ }
kunmap(page);
- page_cache_release(page);
- return 0;
-
-no_dirent_page:
- page = try_to_get_dirent_page(filp, filp->f_pos, 1);
- if (!page)
- goto no_page;
- if (Page_Uptodate(page))
- goto success;
-dirent_read_error:
- page_cache_release(page);
-no_page:
- return -EIO;
+ dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ offset %ld; returning = %d\n", entry->offset, res);
+ return res;
}
-/* Flush directory cookie and EOF caches for an inode.
- * So we don't thrash allocating/freeing cookie tables,
- * we keep the cookies around until the inode is
- * deleted/reused.
+/* The file offset position is now represented as a true offset into the
+ * page cache as is the case in most of the other filesystems.
*/
-__inline__ void nfs_flush_dircache(struct inode *inode)
+static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct nfs_cookie_table *p = NFS_COOKIES(inode);
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct page *page;
+ struct nfs_entry my_entry,
+ *entry = &my_entry;
+ loff_t offset;
+ long res;
+
+ res = nfs_revalidate(dentry);
+ if (res < 0)
+ return res;
- while (p != NULL) {
- int i;
+ /*
+ * filp->f_pos points to the file offset in the page cache.
+ * but if the cache has meanwhile been zapped, we need to
+ * read from the last dirent to revalidate f_pos
+ * itself.
+ */
+ memset(entry, 0, sizeof(*entry));
- for(i = 0; i < COOKIES_PER_CHUNK; i++)
- p->cookies[i] = 0;
+ offset = filp->f_pos;
- p = p->next;
- }
- NFS_DIREOF(inode) = 0;
-}
+ while(!entry->eof) {
+ res = search_cached_dirent_pages(inode, offset, entry);
-/* Free up directory cache state, this happens when
- * nfs_delete_inode is called on an NFS directory.
- */
-void nfs_free_dircache(struct inode *inode)
-{
- struct nfs_cookie_table *p = NFS_COOKIES(inode);
+ if (res < 0) {
+ if (entry->eof)
+ break;
+ res = refetch_to_readdir(filp, inode, offset, entry);
+ if (res < 0)
+ break;
+ }
- while (p != NULL) {
- struct nfs_cookie_table *next = p->next;
- kmem_cache_free(nfs_cookie_cachep, p);
- p = next;
+ page = entry->page;
+ if (!page)
+ printk(KERN_ERR "NFS: Missing page...\n");
+ res = nfs_do_filldir(filp, inode, entry, dirent, filldir);
+ page_cache_release(page);
+ entry->page = NULL;
+ if (res < 0) {
+ res = 0;
+ break;
+ }
+ offset = filp->f_pos;
}
- NFS_COOKIES(inode) = NULL;
- NFS_DIREOF(inode) = 0;
+ if (entry->page)
+ page_cache_release(entry->page);
+ if (res < 0 && res != -EBADCOOKIE)
+ return res;
+ return 0;
}
/*
@@ -540,7 +510,8 @@ static inline int nfs_neg_need_reval(struct dentry *dentry)
*/
static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{
- struct dentry * parent = dentry->d_parent;
+ struct dentry *dir = dentry->d_parent;
+ struct inode *dir_i = dir->d_inode;
struct inode * inode = dentry->d_inode;
int error;
struct nfs_fh fhandle;
@@ -559,7 +530,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
if (is_bad_inode(inode)) {
dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
- parent->d_name.name, dentry->d_name.name);
+ dir->d_name.name, dentry->d_name.name);
goto out_bad;
}
@@ -574,13 +545,14 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
/*
* Do a new lookup and check the dentry attributes.
*/
- error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
- dentry->d_name.name, &fhandle, &fattr);
+ error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
+ &fattr);
if (error)
goto out_bad;
/* Inode number matches? */
- if (NFS_FSID(inode) != fattr.fsid ||
+ if (!(fattr.valid & NFS_ATTR_FATTR) ||
+ NFS_FSID(inode) != fattr.fsid ||
NFS_FILEID(inode) != fattr.fileid)
goto out_bad;
@@ -603,10 +575,9 @@ out_bad:
goto out_valid;
d_drop(dentry);
/* Purge readdir caches. */
- if (dentry->d_parent->d_inode) {
- nfs_zap_caches(dentry->d_parent->d_inode);
- NFS_CACHEINV(dentry->d_parent->d_inode);
- }
+ nfs_zap_caches(dir_i);
+ if (inode && S_ISDIR(inode->i_mode))
+ nfs_zap_caches(inode);
return 0;
}
@@ -687,18 +658,19 @@ static void show_dentry(struct list_head * dlist)
#endif /* NFS_PARANOIA */
#endif /* 0 */
-static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
{
+ struct dentry *dir = dentry->d_parent;
struct inode *inode;
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
dfprintk(VFS, "NFS: lookup(%s/%s)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+ dir->d_name.name, dentry->d_name.name);
error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
+ if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
goto out;
error = -ENOMEM;
@@ -709,8 +681,8 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
}
dentry->d_op = &nfs_dentry_operations;
- error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &fhandle, &fattr);
+ error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
+ &fattr);
inode = NULL;
if (error == -ENOENT)
goto no_entry;
@@ -743,6 +715,7 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
nfs_renew_times(dentry);
error = 0;
}
+ NFS_CACHEINV(dentry->d_parent->d_inode);
return error;
}
@@ -752,29 +725,32 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
* that the operation succeeded on the server, but an error in the
* reply path made it appear to have failed.
*/
-static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
+static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
{
- int error;
+ struct dentry *dir = dentry->d_parent;
struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, dentry->d_name.name);
+ dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
/*
- * Invalidate the dir cache before the operation to avoid a race.
+ * The 0 argument passed into the create function should one day
+ * contain the O_EXCL flag if requested. This allows NFSv3 to
+ * select the appropriate create strategy. Currently open_namei
+ * does not pass the create flags.
*/
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &attr, &fhandle, &fattr);
- if (!error)
+ nfs_zap_caches(dir_i);
+ error = NFS_PROTO(dir_i)->create(dir, &dentry->d_name,
+ &attr, 0, &fhandle, &fattr);
+ if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
- if (error)
+ if (error || fhandle.size == 0)
d_drop(dentry);
return error;
}
@@ -782,31 +758,26 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
/*
* See comments for nfs_proc_create regarding failed operations.
*/
-static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
+static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
{
- int error;
+ struct dentry *dir = dentry->d_parent;
struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, dentry->d_name.name);
+ dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
- /* FIXME: move this to a special nfs_proc_mknod() */
- if (S_ISCHR(mode) || S_ISBLK(mode)) {
- attr.ia_size = rdev; /* get out your barf bag */
- attr.ia_valid |= ATTR_SIZE;
- }
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &attr, &fhandle, &fattr);
- if (!error)
+ nfs_zap_caches(dir_i);
+ error = NFS_PROTO(dir_i)->mknod(dir, &dentry->d_name, &attr, rdev,
+ &fhandle, &fattr);
+ if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
- if (error)
+ if (error || fhandle.size == 0)
d_drop(dentry);
return error;
}
@@ -814,19 +785,21 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
/*
* See comments for nfs_proc_create regarding failed operations.
*/
-static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
{
- int error;
+ struct dentry *dir = dentry->d_parent;
struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
+ int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, dentry->d_name.name);
+ dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;
+#if 0
/*
* Always drop the dentry, we can't always depend on
* the fattr returned by the server (AIX seems to be
@@ -834,44 +807,48 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
* depending on potentially bogus information.
*/
d_drop(dentry);
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &attr, &fhandle, &fattr);
- if (!error)
- dir->i_nlink++;
+#endif
+ nfs_zap_caches(dir_i);
+ dir_i->i_nlink++;
+ error = NFS_PROTO(dir_i)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
+ &fattr);
+ if (!error && fhandle.size != 0)
+ error = nfs_instantiate(dentry, &fhandle, &fattr);
+ if (error || fhandle.size == 0)
+ d_drop(dentry);
return error;
}
-static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
{
+ struct dentry *dir = dentry->d_parent;
int error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
- dir->i_dev, dir->i_ino, dentry->d_name.name);
+ dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name);
+ nfs_zap_caches(dir_i);
+ error = NFS_PROTO(dir_i)->rmdir(dir, &dentry->d_name);
/* Update i_nlink and invalidate dentry. */
if (!error) {
d_drop(dentry);
- if (dir->i_nlink)
- dir->i_nlink--;
+ if (dir_i->i_nlink)
+ dir_i->i_nlink--;
}
return error;
}
-static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
+static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
{
+ struct dentry *dir = dentry->d_parent;
static unsigned int sillycounter = 0;
- const int i_inosize = sizeof(dir->i_ino)*2;
+ const int i_inosize = sizeof(dir_i->i_ino)*2;
const int countersize = sizeof(sillycounter)*2;
const int slen = strlen(".nfs") + i_inosize + countersize;
char silly[slen+1];
+ struct qstr qsilly;
struct dentry *sdentry;
int error = -EIO;
@@ -923,11 +900,10 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
goto out;
} while(sdentry->d_inode != NULL); /* need negative lookup */
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_rename(NFS_SERVER(dir),
- NFS_FH(dentry->d_parent), dentry->d_name.name,
- NFS_FH(dentry->d_parent), silly);
+ nfs_zap_caches(dir_i);
+ qsilly.name = silly;
+ qsilly.len = strlen(silly);
+ error = NFS_PROTO(dir_i)->rename(dir, &dentry->d_name, dir, &qsilly);
if (!error) {
nfs_renew_times(dentry);
d_move(dentry, sdentry);
@@ -948,7 +924,8 @@ out:
*/
static int nfs_safe_remove(struct dentry *dentry)
{
- struct inode *dir = dentry->d_parent->d_inode;
+ struct dentry *dir = dentry->d_parent;
+ struct inode *dir_i = dir->d_inode;
struct inode *inode = dentry->d_inode;
int error, rehash = 0;
@@ -979,22 +956,22 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
d_drop(dentry);
rehash = 1;
}
+ nfs_zap_caches(dir_i);
+ error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
+ if (error < 0)
+ goto out;
/*
- * Update i_nlink and free the inode before unlinking.
+ * Update i_nlink and free the inode
*/
if (inode) {
if (inode->i_nlink)
inode->i_nlink --;
d_delete(dentry);
}
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name);
/*
* Rehash the negative dentry if the operation succeeded.
*/
- if (!error && rehash)
+ if (rehash)
d_add(dentry, NULL);
out:
return error;
@@ -1023,16 +1000,22 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
}
static int
-nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
{
+ struct dentry *dir = dentry->d_parent;
struct iattr attr;
+ struct nfs_fattr sym_attr;
+ struct nfs_fh sym_fh;
+ struct qstr qsymname;
+ unsigned int maxlen;
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
- dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
+ dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
error = -ENAMETOOLONG;
- if (strlen(symname) > NFS_MAXPATHLEN)
+ maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
+ if (strlen(symname) > maxlen)
goto out;
#ifdef NFS_PARANOIA
@@ -1047,21 +1030,19 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
attr.ia_valid = ATTR_MODE;
attr.ia_mode = S_IFLNK | S_IRWXUGO;
- /*
- * Drop the dentry in advance to force a new lookup.
- * Since nfs_proc_symlink doesn't return a fattr, we
- * can't instantiate the new inode.
- */
- d_drop(dentry);
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, symname, &attr);
- if (!error) {
- nfs_renew_times(dentry->d_parent);
- } else if (error == -EEXIST) {
- printk("nfs_proc_symlink: %s/%s already exists??\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+ qsymname.name = symname;
+ qsymname.len = strlen(symname);
+
+ nfs_zap_caches(dir_i);
+ error = NFS_PROTO(dir_i)->symlink(dir, &dentry->d_name, &qsymname,
+ &attr, &sym_fh, &sym_attr);
+ if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) {
+ error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
+ } else {
+ if (error == -EEXIST)
+ printk("nfs_proc_symlink: %s/%s already exists??\n",
+ dir->d_name.name, dentry->d_name.name);
+ d_drop(dentry);
}
out:
@@ -1069,8 +1050,9 @@ out:
}
static int
-nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
{
+ struct dentry *dir = dentry->d_parent;
struct inode *inode = old_dentry->d_inode;
int error;
@@ -1084,10 +1066,8 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
* we can't use the existing dentry.
*/
d_drop(dentry);
- invalidate_inode_pages(dir);
- nfs_flush_dircache(dir);
- error = nfs_proc_link(NFS_DSERVER(old_dentry), NFS_FH(old_dentry),
- NFS_FH(dentry->d_parent), dentry->d_name.name);
+ nfs_zap_caches(dir_i);
+ error = NFS_PROTO(dir_i)->link(old_dentry, dir, &dentry->d_name);
if (!error) {
/*
* Update the link count immediately, as some apps
@@ -1197,14 +1177,12 @@ go_ahead:
if (new_inode)
d_delete(new_dentry);
- invalidate_inode_pages(new_dir);
- nfs_flush_dircache(new_dir);
- invalidate_inode_pages(old_dir);
- nfs_flush_dircache(old_dir);
- error = nfs_proc_rename(NFS_DSERVER(old_dentry),
- NFS_FH(old_dentry->d_parent), old_dentry->d_name.name,
- NFS_FH(new_dentry->d_parent), new_dentry->d_name.name);
-
+ nfs_zap_caches(new_dir);
+ nfs_zap_caches(old_dir);
+ error = NFS_PROTO(old_dir)->rename(old_dentry->d_parent,
+ &old_dentry->d_name,
+ new_dentry->d_parent,
+ &new_dentry->d_name);
NFS_CACHEINV(old_dir);
NFS_CACHEINV(new_dir);
/* Update the dcache if needed */
@@ -1229,16 +1207,15 @@ int nfs_init_fhcache(void)
if (nfs_fh_cachep == NULL)
return -ENOMEM;
- nfs_cookie_cachep = kmem_cache_create("nfs_dcookie",
- sizeof(struct nfs_cookie_table),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (nfs_cookie_cachep == NULL)
- return -ENOMEM;
-
return 0;
}
+void nfs_destroy_fhcache(void)
+{
+ if (kmem_cache_destroy(nfs_fh_cachep))
+ printk(KERN_INFO "nfs_fh: not all structures were freed\n");
+}
+
/*
* Local variables:
* version-control: t
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 32d290c73..d5c3d0944 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -22,6 +22,7 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/pagemap.h>
@@ -215,10 +216,10 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
struct inode * inode = filp->f_dentry->d_inode;
int status = 0;
- dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n",
+ dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
inode->i_dev, inode->i_ino,
fl->fl_type, fl->fl_flags,
- fl->fl_start, fl->fl_end);
+ (long long)fl->fl_start, (long long)fl->fl_end);
if (!inode)
return -EINVAL;
diff --git a/fs/nfs/flushd.c b/fs/nfs/flushd.c
index d36c3a9ae..800a42171 100644
--- a/fs/nfs/flushd.c
+++ b/fs/nfs/flushd.c
@@ -299,6 +299,5 @@ nfs_flushd_exit(struct rpc_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 ca7e1b944..14c43cd24 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_mount.h>
#include <linux/nfs_flushd.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
@@ -58,7 +59,32 @@ static struct super_operations nfs_sops = {
umount_begin: nfs_umount_begin,
};
+/*
+ * RPC cruft for NFS
+ */
struct rpc_stat nfs_rpcstat = { &nfs_program };
+static struct rpc_version * nfs_version[] = {
+ NULL,
+ NULL,
+ &nfs_version2,
+#ifdef CONFIG_NFS_V3
+ &nfs_version3,
+#endif
+};
+
+struct rpc_program nfs_program = {
+ "nfs",
+ NFS_PROGRAM,
+ sizeof(nfs_version) / sizeof(nfs_version[0]),
+ nfs_version,
+ &nfs_rpcstat,
+};
+
+static inline unsigned long
+nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
+{
+ return nfs_fileid_to_ino_t(fattr->fileid);
+}
/*
* The "read_inode" function doesn't actually do anything:
@@ -83,6 +109,7 @@ nfs_read_inode(struct inode * inode)
inode->u.nfs_i.npages = 0;
NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
static void
@@ -101,18 +128,12 @@ nfs_delete_inode(struct inode * inode)
{
dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
- lock_kernel();
- if (S_ISDIR(inode->i_mode)) {
- nfs_free_dircache(inode);
- } else {
- /*
- * The following can never actually happen...
- */
- if (nfs_have_writebacks(inode)) {
- printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
- }
+ /*
+ * The following can never actually happen...
+ */
+ if (nfs_have_writebacks(inode)) {
+ printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
}
- unlock_kernel();
clear_inode(inode);
}
@@ -153,33 +174,68 @@ nfs_umount_begin(struct super_block *sb)
rpc_killall_tasks(rpc);
}
-/*
- * Compute and set NFS server blocksize
- */
-static unsigned int
-nfs_block_size(unsigned int bsize, unsigned char *nrbitsp)
-{
- if (bsize < 1024)
- bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
- else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
- bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+static inline unsigned long
+nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
+{
/* make sure blocksize is a power of two */
if ((bsize & (bsize - 1)) || nrbitsp) {
- unsigned int nrbits;
+ unsigned char nrbits;
for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
;
bsize = 1 << nrbits;
if (nrbitsp)
*nrbitsp = nrbits;
- if (bsize < NFS_DEF_FILE_IO_BUFFER_SIZE)
- bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
}
return bsize;
}
+/*
+ * Calculate the number of 512byte blocks used.
+ */
+static inline unsigned long
+nfs_calc_block_size(u64 tsize)
+{
+ loff_t used = (tsize + 511) / 512;
+ return (used > ULONG_MAX) ? ULONG_MAX : used;
+}
+
+/*
+ * Compute and set NFS server blocksize
+ */
+static inline unsigned long
+nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
+{
+ if (bsize < 1024)
+ bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+ else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
+ bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+
+ return nfs_block_bits(bsize, nrbitsp);
+}
+
+/*
+ * Obtain the root inode of the file system.
+ */
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
+{
+ struct nfs_server *server = &sb->u.nfs_sb.s_server;
+ struct nfs_fattr fattr;
+ struct inode *inode;
+ int error;
+
+ if ((error = server->rpc_ops->getroot(server, rootfh, &fattr)) < 0) {
+ printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
+ return NULL;
+ }
+
+ inode = __nfs_fhget(sb, &fattr);
+ return inode;
+}
+
extern struct nfs_fh *nfs_fh_alloc(void);
extern void nfs_fh_free(struct nfs_fh *p);
@@ -194,19 +250,20 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
{
struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data;
struct nfs_server *server;
- struct rpc_xprt *xprt;
- struct rpc_clnt *clnt;
- struct nfs_fh *root_fh;
- struct inode *root_inode;
+ struct rpc_xprt *xprt = NULL;
+ struct rpc_clnt *clnt = NULL;
+ struct nfs_fh *root = &data->root, *root_fh, fh;
+ struct inode *root_inode = NULL;
unsigned int authflavor;
- int tcp;
struct sockaddr_in srvaddr;
struct rpc_timeout timeparms;
- struct nfs_fattr fattr;
+ struct nfs_fsinfo fsinfo;
+ int tcp, version, maxlen;
if (!data)
goto out_miss_args;
+ memset(&fh, 0, sizeof(fh));
if (data->version != NFS_MOUNT_VERSION) {
printk("nfs warning: mount version %s than kernel\n",
data->version < NFS_MOUNT_VERSION ? "older" : "newer");
@@ -214,6 +271,12 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
data->namlen = 0;
if (data->version < 3)
data->bsize = 0;
+ if (data->version < 4) {
+ data->flags &= ~NFS_MOUNT_VER3;
+ root = &fh;
+ root->size = NFS2_FHSIZE;
+ memcpy(root->data, data->old_root.data, NFS2_FHSIZE);
+ }
}
/* We now require that the mount process passes the remote address */
@@ -225,12 +288,12 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_op = &nfs_sops;
+ sb->s_blocksize_bits = 0;
sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
- sb->u.nfs_sb.s_root = data->root;
server = &sb->u.nfs_sb.s_server;
server->rsize = nfs_block_size(data->rsize, NULL);
server->wsize = nfs_block_size(data->wsize, NULL);
- server->flags = data->flags;
+ server->flags = data->flags & NFS_MOUNT_FLAGMASK;
if (data->flags & NFS_MOUNT_NOAC) {
data->acregmin = data->acregmax = 0;
@@ -241,11 +304,32 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
+ server->namelen = data->namlen;
server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
if (!server->hostname)
goto out_unlock;
strcpy(server->hostname, data->hostname);
+ nfsv3_try_again:
+ /* Check NFS protocol revision and initialize RPC op vector
+ * and file handle pool. */
+ if (data->flags & NFS_MOUNT_VER3) {
+#ifdef CONFIG_NFS_V3
+ server->rpc_ops = &nfs_v3_clientops;
+ version = 3;
+ if (data->version < 4) {
+ printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
+ goto out_unlock;
+ }
+#else
+ printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
+ goto out_unlock;
+#endif
+ } else {
+ server->rpc_ops = &nfs_v2_clientops;
+ version = 2;
+ }
+
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
@@ -255,6 +339,11 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
timeparms.to_maxval = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
timeparms.to_exponential = 1;
+ if (!timeparms.to_initval)
+ timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10;
+ if (!timeparms.to_retries)
+ timeparms.to_retries = 5;
+
/* Now create transport and client */
xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
&srvaddr, &timeparms);
@@ -269,7 +358,7 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
authflavor = RPC_AUTH_KRB;
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
- NFS_VERSION, authflavor);
+ version, authflavor);
if (clnt == NULL)
goto out_no_client;
@@ -289,20 +378,68 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
root_fh = nfs_fh_alloc();
if (!root_fh)
goto out_no_fh;
- *root_fh = data->root;
-
- if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
- goto out_no_fattr;
+ memcpy((u8*)root_fh, (u8*)root, sizeof(*root));
+
+ /* Did getting the root inode fail? */
+ if (!(root_inode = nfs_get_root(sb, root))
+ && (data->flags & NFS_MOUNT_VER3)) {
+ data->flags &= ~NFS_MOUNT_VER3;
+ nfs_fh_free(root_fh);
+ rpciod_down();
+ rpc_shutdown_client(server->client);
+ goto nfsv3_try_again;
+ }
- root_inode = __nfs_fhget(sb, &fattr);
if (!root_inode)
goto out_no_root;
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root)
goto out_no_root;
+
sb->s_root->d_op = &nfs_dentry_operations;
sb->s_root->d_fsdata = root_fh;
+ /* Get some general file system info */
+ if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
+ if (server->namelen == 0)
+ server->namelen = fsinfo.namelen;
+ } else {
+ printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
+ goto out_no_root;
+ }
+
+ /* Work out a lot of parameters */
+ if (data->rsize == 0)
+ server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+ if (data->wsize == 0)
+ server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+ server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+ /* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
+ if (!fsinfo.bsize)
+ fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
+ /* Also make sure we don't go below rsize/wsize since
+ * RPC calls are expensive */
+ if (fsinfo.bsize < server->rsize)
+ fsinfo.bsize = server->rsize;
+ if (fsinfo.bsize < server->wsize)
+ fsinfo.bsize = server->wsize;
+
+ if (data->bsize == 0)
+ sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
+ if (server->rsize > fsinfo.rtmax)
+ server->rsize = fsinfo.rtmax;
+ if (server->rsize > PAGE_CACHE_SIZE)
+ server->rsize = PAGE_CACHE_SIZE;
+ if (server->wsize > fsinfo.wtmax)
+ server->wsize = fsinfo.wtmax;
+ if (server->wsize > NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT)
+ server->wsize = NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT;
+
+ maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
+
+ if (server->namelen == 0 || server->namelen > maxlen)
+ server->namelen = maxlen;
+
/* Fire up the writeback cache */
if (nfs_reqlist_alloc(server) < 0) {
printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
@@ -322,11 +459,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
out_no_root:
printk("nfs_read_super: get root inode failed\n");
iput(root_inode);
- goto out_free_fh;
-
-out_no_fattr:
- printk("nfs_read_super: get root fattr failed\n");
-out_free_fh:
nfs_fh_free(root_fh);
out_no_fh:
rpciod_down();
@@ -366,21 +498,33 @@ out_fail:
static int
nfs_statfs(struct super_block *sb, struct statfs *buf)
{
- int error;
+ struct nfs_server *server = &sb->u.nfs_sb.s_server;
+ unsigned char blockbits;
+ unsigned long blockres;
struct nfs_fsinfo res;
+ int error;
- error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
- &res);
- if (error) {
- printk("nfs_statfs: statfs error = %d\n", -error);
- res.bsize = res.blocks = res.bfree = res.bavail = -1;
- }
+ error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
buf->f_type = NFS_SUPER_MAGIC;
- buf->f_bsize = res.bsize;
- buf->f_blocks = res.blocks;
- buf->f_bfree = res.bfree;
- buf->f_bavail = res.bavail;
- buf->f_namelen = NAME_MAX;
+ if (error < 0)
+ goto out_err;
+
+ if (res.bsize == 0)
+ res.bsize = sb->s_blocksize;
+ buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
+ blockres = (1 << blockbits) - 1;
+ buf->f_blocks = (res.tbytes + blockres) >> blockbits;
+ buf->f_bfree = (res.fbytes + blockres) >> blockbits;
+ buf->f_bavail = (res.abytes + blockres) >> blockbits;
+ buf->f_files = res.tfiles;
+ buf->f_ffree = res.afiles;
+ if (res.namelen == 0 || res.namelen > server->namelen)
+ res.namelen = server->namelen;
+ buf->f_namelen = res.namelen;
+ return 0;
+ out_err:
+ printk("nfs_statfs: statfs error = %d\n", -error);
+ buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
return 0;
}
@@ -429,11 +573,12 @@ void
nfs_zap_caches(struct inode *inode)
{
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
- NFS_CACHEINV(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
invalidate_inode_pages(inode);
- if (S_ISDIR(inode->i_mode))
- nfs_flush_dircache(inode);
+
+ memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+ NFS_CACHEINV(inode);
}
/*
@@ -481,9 +626,16 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
* Preset the size and mtime, as there's no need
* to invalidate the caches.
*/
- inode->i_size = fattr->size;
- inode->i_mtime = fattr->mtime.seconds;
- NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+ inode->i_size = nfs_size_to_loff_t(fattr->size);
+ inode->i_mtime = nfs_time_to_secs(fattr->mtime);
+ inode->i_atime = nfs_time_to_secs(fattr->atime);
+ inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+ NFS_CACHE_CTIME(inode) = fattr->ctime;
+ NFS_CACHE_MTIME(inode) = fattr->mtime;
+ NFS_CACHE_ATIME(inode) = fattr->atime;
+ NFS_CACHE_ISIZE(inode) = fattr->size;
+ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
nfs_refresh_inode(inode, fattr);
}
@@ -551,9 +703,9 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
{
struct super_block *sb = dentry->d_sb;
- dprintk("NFS: nfs_fhget(%s/%s fileid=%d)\n",
+ dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- fattr->fileid);
+ (long long)fattr->fileid);
/* Install the file handle in the dentry */
*((struct nfs_fh *) dentry->d_fsdata) = *fhandle;
@@ -572,7 +724,7 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
inode->i_sb = sb;
inode->i_dev = sb->s_dev;
inode->i_flags = 0;
- inode->i_ino = fattr->fileid;
+ inode->i_ino = nfs_fattr_to_ino_t(fattr);
nfs_read_inode(inode);
nfs_fill_inode(inode, fattr);
inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
@@ -598,12 +750,15 @@ __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
struct inode *inode = NULL;
unsigned long ino;
+ if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+ goto out_no_inode;
+
if (!fattr->nlink) {
printk("NFS: Buggy server - nlink == 0!\n");
goto out_no_inode;
}
- ino = fattr->fileid;
+ ino = nfs_fattr_to_ino_t(fattr);
while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
@@ -666,8 +821,7 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error);
if (error)
goto out;
- error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
- &fattr, attr);
+ error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
if (error)
goto out;
/*
@@ -676,13 +830,21 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error);
*/
if (attr->ia_valid & ATTR_SIZE) {
if (attr->ia_size != fattr.size)
- printk("nfs_notify_change: attr=%Ld, fattr=%d??\n",
- (long long) attr->ia_size, fattr.size);
- inode->i_mtime = fattr.mtime.seconds;
+ printk("nfs_notify_change: attr=%Ld, fattr=%Ld??\n",
+ (long long) attr->ia_size, (long long)fattr.size);
vmtruncate(inode, attr->ia_size);
}
- if (attr->ia_valid & ATTR_MTIME)
- inode->i_mtime = fattr.mtime.seconds;
+
+ /*
+ * If we changed the size or mtime, update the inode
+ * now to avoid invalidating the page cache.
+ */
+ if (!(fattr.valid & NFS_ATTR_WCC)) {
+ fattr.pre_size = NFS_CACHE_ISIZE(inode);
+ fattr.pre_mtime = NFS_CACHE_MTIME(inode);
+ fattr.pre_ctime = NFS_CACHE_CTIME(inode);
+ fattr.valid |= NFS_ATTR_WCC;
+ }
error = nfs_refresh_inode(inode, &fattr);
out:
return error;
@@ -695,24 +857,13 @@ out:
int
nfs_wait_on_inode(struct inode *inode, int flag)
{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
- int intr, error = 0;
-
- intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR;
- add_wait_queue(&inode->i_wait, &wait);
- for (;;) {
- set_task_state(tsk, (intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE));
- error = 0;
- if (!(NFS_FLAGS(inode) & flag))
- break;
- error = -ERESTARTSYS;
- if (intr && signalled())
- break;
- schedule();
- }
- set_task_state(tsk, TASK_RUNNING);
- remove_wait_queue(&inode->i_wait, &wait);
+ struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ int error;
+ if (!(NFS_FLAGS(inode) & flag))
+ return 0;
+ inode->i_count++;
+ error = nfs_wait_event(clnt, inode->i_wait, !(NFS_FLAGS(inode) & flag));
+ iput(inode);
return error;
}
@@ -768,30 +919,32 @@ __nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
}
NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
- status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
+ status = NFS_PROTO(inode)->getattr(dentry, &fattr);
if (status) {
+ struct dentry *dir = dentry->d_parent;
+ struct inode *dir_i = dir->d_inode;
int error;
u32 *fh;
struct nfs_fh fhandle;
dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, inode->i_ino, status);
+ dir->d_name.name, dentry->d_name.name,
+ inode->i_ino, status);
if (status != -ESTALE)
goto out;
/*
* A "stale filehandle" error ... show the current fh
* and find out what the filehandle should be.
*/
- fh = (u32 *) NFS_FH(dentry);
+ fh = (u32 *) NFS_FH(dentry)->data;
dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
- error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent),
- dentry->d_name.name, &fhandle, &fattr);
+ error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name,
+ &fhandle, &fattr);
if (error) {
dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
goto out;
}
- fh = (u32 *) &fhandle;
+ fh = (u32 *) fhandle.data;
dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n",
fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
goto out;
@@ -827,19 +980,37 @@ out:
int
nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
- int invalid = 0;
- int error = -EIO;
-
- dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino, inode->i_count);
+ __u64 new_size, new_mtime;
+ loff_t new_isize;
+ int invalid = 0;
+ int error = -EIO;
if (!inode || !fattr) {
- printk("nfs_refresh_inode: inode or fattr is NULL\n");
+ printk(KERN_ERR "nfs_refresh_inode: inode or fattr is NULL\n");
+ goto out;
+ }
+ if (inode->i_mode == 0) {
+ printk(KERN_ERR "nfs_refresh_inode: empty inode\n");
goto out;
}
- if (inode->i_ino != fattr->fileid) {
- printk("nfs_refresh_inode: mismatch, ino=%ld, fattr=%d\n",
- inode->i_ino, fattr->fileid);
+
+ if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+ goto out;
+
+ if (is_bad_inode(inode))
+ goto out;
+
+ dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
+ inode->i_dev, inode->i_ino, inode->i_count,
+ fattr->valid);
+
+
+ if (NFS_FSID(inode) != fattr->fsid ||
+ NFS_FILEID(inode) != fattr->fileid) {
+ printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
+ "expected (0x%Lx/0x%Lx), got (0x%Lx/0x%Lx)\n",
+ (long long)NFS_FSID(inode), (long long)NFS_FILEID(inode),
+ (long long)fattr->fsid, (long long)fattr->fileid);
goto out;
}
@@ -849,54 +1020,101 @@ nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
goto out_changed;
- inode->i_mode = fattr->mode;
- inode->i_nlink = fattr->nlink;
- inode->i_uid = fattr->uid;
- inode->i_gid = fattr->gid;
+ new_mtime = fattr->mtime;
+ new_size = fattr->size;
+ new_isize = nfs_size_to_loff_t(fattr->size);
- inode->i_blocks = fattr->blocks;
- inode->i_atime = fattr->atime.seconds;
- inode->i_ctime = fattr->ctime.seconds;
+ error = 0;
/*
* Update the read time so we don't revalidate too often.
*/
NFS_READTIME(inode) = jiffies;
- error = 0;
/*
- * If we have pending write-back entries, we don't want
- * to look at the size or the mtime the server sends us
- * too closely, as we're in the middle of modifying them.
+ * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
+ * NOT inode->i_size!!!
*/
- if (nfs_have_writebacks(inode))
- goto out;
-
- if (inode->i_size != fattr->size) {
+ if (NFS_CACHE_ISIZE(inode) != new_size) {
#ifdef NFS_DEBUG_VERBOSE
-printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino);
+ printk(KERN_DEBUG "NFS: isize change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
- inode->i_size = fattr->size;
invalid = 1;
}
- if (inode->i_mtime != fattr->mtime.seconds) {
+ /*
+ * Note: we don't check inode->i_mtime since pipes etc.
+ * can change this value in VFS without requiring a
+ * cache revalidation.
+ */
+ if (NFS_CACHE_MTIME(inode) != new_mtime) {
#ifdef NFS_DEBUG_VERBOSE
-printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
+ printk(KERN_DEBUG "NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
- inode->i_mtime = fattr->mtime.seconds;
invalid = 1;
}
- if (invalid)
- goto out_invalid;
+ /* Check Weak Cache Consistency data.
+ * If size and mtime match the pre-operation values, we can
+ * assume that any attribute changes were caused by our NFS
+ * operation, so there's no need to invalidate the caches.
+ */
+ if ((fattr->valid & NFS_ATTR_WCC)
+ && NFS_CACHE_ISIZE(inode) == fattr->pre_size
+ && NFS_CACHE_MTIME(inode) == fattr->pre_mtime) {
+ invalid = 0;
+ }
+
+ /*
+ * If we have pending writebacks, things can get
+ * messy.
+ */
+ if (nfs_have_writebacks(inode) && new_isize < inode->i_size)
+ new_isize = inode->i_size;
+
+ NFS_CACHE_CTIME(inode) = fattr->ctime;
+ inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+ /* If we've been messing around with atime, don't
+ * update it. Save the server value in NFS_CACHE_ATIME.
+ */
+ NFS_CACHE_ATIME(inode) = fattr->atime;
+ if (time_before(inode->i_atime, nfs_time_to_secs(fattr->atime)))
+ inode->i_atime = nfs_time_to_secs(fattr->atime);
+ NFS_CACHE_MTIME(inode) = new_mtime;
+ inode->i_mtime = nfs_time_to_secs(new_mtime);
+
+ NFS_CACHE_ISIZE(inode) = new_size;
+ inode->i_size = new_isize;
+
+ inode->i_mode = fattr->mode;
+ inode->i_nlink = fattr->nlink;
+ inode->i_uid = fattr->uid;
+ inode->i_gid = fattr->gid;
+
+ if (fattr->valid & NFS_ATTR_FATTR_V3) {
+ /*
+ * report the blocks in 512byte units
+ */
+ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+ inode->i_blksize = inode->i_sb->s_blocksize;
+ } else {
+ inode->i_blocks = fattr->du.nfs2.blocks;
+ inode->i_blksize = fattr->du.nfs2.blocksize;
+ }
+ inode->i_rdev = 0;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+
/* Update attrtimeo value */
- if (fattr->mtime.seconds == NFS_OLDMTIME(inode)) {
+ if (!invalid && time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) {
if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
- NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+
+ if (invalid)
+ nfs_zap_caches(inode);
out:
return error;
@@ -906,22 +1124,16 @@ out_changed:
* Big trouble! The inode has become a different object.
*/
#ifdef NFS_PARANOIA
-printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
-inode->i_ino, inode->i_mode, fattr->mode);
+ printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
+ inode->i_ino, inode->i_mode, fattr->mode);
#endif
/*
* No need to worry about unhashing the dentry, as the
* lookup validation will know that the inode is bad.
+ * (But we fall through to invalidate the caches.)
*/
nfs_invalidate_inode(inode);
goto out;
-
-out_invalid:
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
-#endif
- nfs_zap_caches(inode);
- goto out;
}
/*
@@ -930,7 +1142,9 @@ 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 void nfs_destroy_fhcache(void);
extern int nfs_init_nfspagecache(void);
+extern void nfs_destroy_nfspagecache(void);
/*
* Initialize NFS
@@ -972,6 +1186,8 @@ init_module(void)
void
cleanup_module(void)
{
+ nfs_destroy_nfspagecache();
+ nfs_destroy_fhcache();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index f74984de2..0adfacd3e 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -30,7 +30,9 @@
#define MOUNT_UMNT 3
*/
-static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *);
+static int nfs_gen_mount(struct sockaddr_in *,
+ char *, struct nfs_fh *, int);
+static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *, int);
extern struct rpc_program mnt_program;
struct mnt_fhstatus {
@@ -44,24 +46,38 @@ struct mnt_fhstatus {
int
nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
{
+ return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION);
+}
+
+int
+nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+{
+ return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION);
+}
+
+static int
+nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version)
+{
struct rpc_clnt *mnt_clnt;
struct mnt_fhstatus result = { 0, fh };
char hostname[32];
int status;
+ int call;
dprintk("NFS: nfs_mount(%08x:%s)\n",
(unsigned)ntohl(addr->sin_addr.s_addr), path);
strcpy(hostname, in_ntoa(addr->sin_addr.s_addr));
- if (!(mnt_clnt = mnt_create(hostname, addr)))
+ if (!(mnt_clnt = mnt_create(hostname, addr, version)))
return -EACCES;
- status = rpc_call(mnt_clnt, NFS_MNTPROC_MNT, path, &result, 0);
+ call = (version == 3) ? MOUNTPROC3_MNT : MNTPROC_MNT;
+ status = rpc_call(mnt_clnt, call, path, &result, 0);
return status < 0? status : (result.status? -EACCES : 0);
}
static struct rpc_clnt *
-mnt_create(char *hostname, struct sockaddr_in *srvaddr)
+mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version)
{
struct rpc_xprt *xprt;
struct rpc_clnt *clnt;
@@ -70,7 +86,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr)
return NULL;
clnt = rpc_create_client(xprt, hostname,
- &mnt_program, NFS_MNT_VERSION,
+ &mnt_program, version,
RPC_AUTH_NULL);
if (!clnt) {
xprt_destroy(xprt);
@@ -104,8 +120,26 @@ xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
static int
xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
{
- if ((res->status = ntohl(*p++)) == 0)
- memcpy(res->fh, p, sizeof(*res->fh));
+ memset((u8 *)res, 0, sizeof(*res));
+ if ((res->status = ntohl(*p++)) == 0) {
+ res->fh->size = NFS2_FHSIZE;
+ memcpy(res->fh->data, p, NFS2_FHSIZE);
+ }
+ return 0;
+}
+
+static int
+xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+{
+ memset((u8 *)res, 0, sizeof(*res));
+ if ((res->status = ntohl(*p++)) == 0) {
+ int size = ntohl(*p++);
+ if (size <= NFS3_FHSIZE) {
+ res->fh->size = size;
+ memcpy(res->fh->data, p, res->fh->size);
+ } else
+ res->status = -EBADHANDLE;
+ }
return 0;
}
@@ -122,13 +156,30 @@ static struct rpc_procinfo mnt_procedures[2] = {
MNT_dirpath_sz << 2, 0 },
};
+static struct rpc_procinfo mnt3_procedures[2] = {
+ { "mnt3_null",
+ (kxdrproc_t) xdr_error,
+ (kxdrproc_t) xdr_error, 0, 0 },
+ { "mnt3_mount",
+ (kxdrproc_t) xdr_encode_dirpath,
+ (kxdrproc_t) xdr_decode_fhstatus3,
+ MNT_dirpath_sz << 2, 0 },
+};
+
+
static struct rpc_version mnt_version1 = {
1, 2, mnt_procedures
};
+static struct rpc_version mnt_version3 = {
+ 3, 2, mnt3_procedures
+};
+
static struct rpc_version * mnt_version[] = {
NULL,
&mnt_version1,
+ NULL,
+ &mnt_version3,
};
static struct rpc_stat mnt_stats;
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 5ad2aaa67..1dd1553ba 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -1,14 +1,14 @@
/*
- * linux/fs/nfs/xdr.c
+ * linux/fs/nfs/nfs2xdr.c
*
* XDR functions to encode/decode NFS RPC arguments and results.
*
* Copyright (C) 1992, 1993, 1994 Rick Sladkey
* Copyright (C) 1996 Olaf Kirch
+ * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
+ * FIFO's need special handling in NFSv2
*/
-#define NFS_NEED_XDR_TYPES
-
#include <linux/param.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -20,6 +20,8 @@
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
/* Uncomment this to support servers requiring longword lengths */
@@ -28,8 +30,7 @@
#define NFSDBG_FACILITY NFSDBG_XDR
/* #define NFS_PARANOIA 1 */
-#define QUADLEN(len) (((len) + 3) >> 2)
-static int nfs_stat_to_errno(int stat);
+extern int nfs_stat_to_errno(int stat);
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO
@@ -40,8 +41,8 @@ static int nfs_stat_to_errno(int stat);
*/
#define NFS_fhandle_sz 8
#define NFS_sattr_sz 8
-#define NFS_filename_sz 1+(NFS_MAXNAMLEN>>2)
-#define NFS_path_sz 1+(NFS_MAXPATHLEN>>2)
+#define NFS_filename_sz 1+(NFS2_MAXNAMLEN>>2)
+#define NFS_path_sz 1+(NFS2_MAXPATHLEN>>2)
#define NFS_fattr_sz 17
#define NFS_info_sz 5
#define NFS_entry_sz NFS_filename_sz+3
@@ -49,6 +50,7 @@ static int nfs_stat_to_errno(int stat);
#define NFS_enc_void_sz 0
#define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
#define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
+#define NFS_readlinkargs_sz NFS_fhandle_sz
#define NFS_readargs_sz NFS_fhandle_sz+3
#define NFS_writeargs_sz NFS_fhandle_sz+4
#define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
@@ -56,14 +58,13 @@ static int nfs_stat_to_errno(int stat);
#define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
#define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
#define NFS_readdirargs_sz NFS_fhandle_sz+2
-#define NFS_readlinkargs_sz NFS_fhandle_sz
#define NFS_dec_void_sz 0
#define NFS_attrstat_sz 1+NFS_fattr_sz
#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_writeres_sz NFS_attrstat_sz
#define NFS_stat_sz 1
#define NFS_readdirres_sz 1
#define NFS_statfsres_sz 1+NFS_info_sz
@@ -74,15 +75,19 @@ static int nfs_stat_to_errno(int stat);
static inline u32 *
xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
{
- *((struct nfs_fh *) p) = *fhandle;
- return p + QUADLEN(sizeof(*fhandle));
+ memcpy(p, fhandle->data, NFS2_FHSIZE);
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
}
static inline u32 *
xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
{
- *fhandle = *((struct nfs_fh *) p);
- return p + QUADLEN(sizeof(*fhandle));
+ /* Zero handle first to allow comparisons */
+ memset(fhandle, 0, sizeof(*fhandle));
+ /* NFSv2 handles have a fixed length */
+ fhandle->size = NFS2_FHSIZE;
+ memcpy(fhandle->data, p, NFS2_FHSIZE);
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
}
static inline u32 *
@@ -93,7 +98,14 @@ xdr_decode_string2(u32 *p, char **string, unsigned int *len,
if (*len > maxlen)
return NULL;
*string = (char *) p;
- return p + QUADLEN(*len);
+ return p + XDR_QUADLEN(*len);
+}
+
+static inline u32*
+xdr_decode_time(u32 *p, u64 *timep)
+{
+ *timep = ((u64)ntohl(*p++) << 32) + (u64)ntohl(*p++);
+ return p;
}
static inline u32 *
@@ -105,21 +117,23 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
fattr->uid = ntohl(*p++);
fattr->gid = ntohl(*p++);
fattr->size = ntohl(*p++);
- fattr->blocksize = ntohl(*p++);
+ fattr->du.nfs2.blocksize = ntohl(*p++);
fattr->rdev = ntohl(*p++);
- fattr->blocks = ntohl(*p++);
+ fattr->du.nfs2.blocks = ntohl(*p++);
fattr->fsid = ntohl(*p++);
fattr->fileid = ntohl(*p++);
- fattr->atime.seconds = ntohl(*p++);
- fattr->atime.useconds = ntohl(*p++);
- fattr->mtime.seconds = ntohl(*p++);
- fattr->mtime.useconds = ntohl(*p++);
- fattr->ctime.seconds = ntohl(*p++);
- fattr->ctime.useconds = ntohl(*p++);
+ p = xdr_decode_time(p, &fattr->atime);
+ p = xdr_decode_time(p, &fattr->mtime);
+ p = xdr_decode_time(p, &fattr->ctime);
+ fattr->valid |= NFS_ATTR_FATTR;
+ if (fattr->type == NFCHR && fattr->rdev == NFS2_FIFO_DEV) {
+ fattr->type = NFFIFO;
+ fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
+ fattr->rdev = 0;
+ }
return p;
}
-
#define SATTR(p, attr, flag, field) \
*p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
static inline u32 *
@@ -194,7 +208,7 @@ static int
nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_string(p, args->name);
+ p = xdr_encode_array(p, args->name, args->len);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
@@ -208,7 +222,8 @@ static int
nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
- int replen, buflen;
+ int buflen, replen;
+ unsigned int nr;
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->offset);
@@ -216,16 +231,25 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
*p++ = htonl(args->count);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ /* Get the number of buffers in the receive iovec */
+ nr = args->nriov;
+
+ if (nr+2 > MAX_IOVEC) {
+ printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
+ return -EINVAL;
+ }
+
/* set up reply iovec */
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
buflen = req->rq_rvec[0].iov_len;
req->rq_rvec[0].iov_len = replen;
- req->rq_rvec[1].iov_base = args->buffer;
- req->rq_rvec[1].iov_len = args->count;
- req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
- req->rq_rvec[2].iov_len = buflen - replen;
+ /* Copy the iovec */
+ memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
+
+ req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+ req->rq_rvec[nr+1].iov_len = buflen - replen;
req->rq_rlen = args->count + buflen;
- req->rq_rnr = 3;
+ req->rq_rnr += nr+1;
return 0;
}
@@ -239,7 +263,6 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
struct iovec *iov = req->rq_rvec;
int status, count, recvd, hdrlen;
- dprintk("RPC: readres OK status %lx\n", (long)ntohl(*p));
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
p = xdr_decode_fattr(p, res->fattr);
@@ -247,22 +270,26 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
count = ntohl(*p++);
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
recvd = req->rq_rlen - hdrlen;
- if (p != iov[2].iov_base) {
+ if (p != iov[req->rq_rnr-1].iov_base) {
/* Unexpected reply header size. Punt.
* XXX: Move iovec contents to align data on page
* boundary and adjust RPC header size guess */
- printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen);
+ printk(KERN_WARNING "NFS: Odd RPC header size in read reply: %d\n", hdrlen);
return -errno_NFSERR_IO;
}
if (count > recvd) {
- printk("NFS: server cheating in read reply: "
+ printk(KERN_WARNING "NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd);
count = recvd;
}
dprintk("RPC: readres OK count %d\n", count);
- if (count < res->count)
- memset((u8 *)(iov[1].iov_base+count), 0, res->count-count);
+ if (count < res->count) {
+ xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+ res->count = count;
+ res->eof = 1; /* Silly NFSv3ism which can't be helped */
+ } else
+ res->eof = 0;
return count;
}
@@ -288,13 +315,13 @@ nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
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;
- }
+ 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));
+ memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
#ifdef NFS_PAD_WRITES
/*
@@ -325,7 +352,7 @@ static int
nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_string(p, args->name);
+ p = xdr_encode_array(p, args->name, args->len);
p = xdr_encode_sattr(p, args->sattr);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
@@ -338,9 +365,9 @@ static int
nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_string(p, args->fromname);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
p = xdr_encode_fhandle(p, args->tofh);
- p = xdr_encode_string(p, args->toname);
+ p = xdr_encode_array(p, args->toname, args->tolen);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
@@ -353,7 +380,7 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_fhandle(p, args->tofh);
- p = xdr_encode_string(p, args->toname);
+ p = xdr_encode_array(p, args->toname, args->tolen);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
@@ -365,8 +392,8 @@ static int
nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_string(p, args->fromname);
- p = xdr_encode_string(p, args->topath);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
+ p = xdr_encode_array(p, args->topath, args->tolen);
p = xdr_encode_sattr(p, args->sattr);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
@@ -380,108 +407,113 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
{
struct rpc_task *task = req->rq_task;
struct rpc_auth *auth = task->tk_auth;
- int bufsiz = args->bufsiz;
- int replen;
-
- p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->cookie);
+ u32 bufsiz = args->bufsiz;
+ int buflen, replen;
- /* Some servers (e.g. HP OS 9.5) seem to expect the buffer size
+ /*
+ * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
* to be in longwords ... check whether to convert the size.
*/
if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
- *p++ = htonl(bufsiz >> 2);
- else
- *p++ = htonl(bufsiz);
+ bufsiz = bufsiz >> 2;
+ p = xdr_encode_fhandle(p, args->fh);
+ *p++ = htonl(args->cookie);
+ *p++ = htonl(bufsiz); /* see above */
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
/* set up reply iovec */
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
+ buflen = req->rq_rvec[0].iov_len;
req->rq_rvec[0].iov_len = replen;
req->rq_rvec[1].iov_base = args->buffer;
- req->rq_rvec[1].iov_len = bufsiz;
- req->rq_rlen = replen + bufsiz;
- req->rq_rnr = 2;
+ req->rq_rvec[1].iov_len = args->bufsiz;
+ req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+ req->rq_rvec[2].iov_len = buflen - replen;
+ req->rq_rlen = buflen + args->bufsiz;
+ req->rq_rnr += 2;
return 0;
}
/*
* Decode the result of a readdir call.
+ * We're not really decoding anymore, we just leave the buffer untouched
+ * and only check that it is syntactically correct.
+ * The real decoding happens in nfs_decode_entry below, called directly
+ * from nfs_readdir for each entry.
*/
-#define NFS_DIRENT_MAXLEN (5 * sizeof(u32) + (NFS_MAXNAMLEN + 1))
static int
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
struct iovec *iov = req->rq_rvec;
int status, nr;
- u32 *end;
- u32 last_cookie = res->cookie;
+ u32 *end, *entry, len;
- status = ntohl(*p++);
- if (status) {
- nr = -nfs_stat_to_errno(status);
- goto error;
- }
+ if ((status = ntohl(*p++)))
+ return -nfs_stat_to_errno(status);
if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) {
/* Unexpected reply header size. Punt. */
- printk("NFS: Odd RPC header size in readdirres reply\n");
- nr = -errno_NFSERR_IO;
- goto error;
+ printk(KERN_WARNING "NFS: Odd RPC header size in readdirres reply\n");
+ return -errno_NFSERR_IO;
}
- /* Get start and end address of XDR readdir response. */
+ /* Get start and end address of XDR data */
p = (u32 *) iov[1].iov_base;
end = (u32 *) ((u8 *) p + iov[1].iov_len);
- for (nr = 0; *p++; nr++) {
- __u32 len;
-
- /* Convert fileid. */
- *p = ntohl(*p);
- p++;
- /* Convert and capture len */
- len = *p = ntohl(*p);
- p++;
-
- if ((p + QUADLEN(len) + 3) > end) {
- struct rpc_clnt *clnt = req->rq_task->tk_client;
+ /* Get start and end of dirent buffer */
+ if (res->buffer != p) {
+ printk(KERN_ERR "NFS: Bad result buffer in readdir\n");
+ return -errno_NFSERR_IO;
+ }
- clnt->cl_flags |= NFS_CLNTF_BUFSIZE;
- p -= 2;
- p[-1] = 0;
- p[0] = 0;
- break;
+ for (nr = 0; *p++; nr++) {
+ entry = p - 1;
+ p++; /* fileid */
+ len = ntohl(*p++);
+ p += XDR_QUADLEN(len) + 1; /* name plus cookie */
+ if (len > NFS2_MAXNAMLEN) {
+ printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
+ len);
+ return -errno_NFSERR_IO;
}
- if (len > NFS_MAXNAMLEN) {
- nr = -errno_NFSERR_IO;
- goto error;
+ if (p + 2 > end) {
+ printk(KERN_NOTICE
+ "NFS: short packet in readdir reply!\n");
+ entry[0] = entry[1] = 0;
+ break;
}
- p += QUADLEN(len);
-
- /* Convert and capture cookie. */
- last_cookie = *p = ntohl(*p);
- p++;
}
- p -= 1;
- status = ((end - p) << 2);
- if (!p[1] && (status >= NFS_DIRENT_MAXLEN)) {
- status = ((__u8 *)p - (__u8 *)iov[1].iov_base);
- res->buffer += status;
- res->bufsiz -= status;
- } else if (p[1]) {
- status = (int)((long)p & ~PAGE_CACHE_MASK);
- res->bufsiz = -status;
- } else {
- res->bufsiz = 0;
+ p++; /* EOF flag */
+
+ if (p > end) {
+ printk(KERN_NOTICE
+ "NFS: short packet in readdir reply!\n");
+ return -errno_NFSERR_IO;
}
- res->cookie = last_cookie;
return nr;
+}
-error:
- res->bufsiz = 0;
- return nr;
+u32 *
+nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+ if (!*p++) {
+ if (!*p)
+ return ERR_PTR(-EAGAIN);
+ entry->eof = 1;
+ return ERR_PTR(-EBADCOOKIE);
+ }
+
+ entry->ino = ntohl(*p++);
+ entry->len = ntohl(*p++);
+ entry->name = (const char *) p;
+ p += XDR_QUADLEN(entry->len);
+ entry->prev_cookie = entry->cookie;
+ entry->cookie = ntohl(*p++);
+ entry->eof = !p[0] && p[1];
+
+ return p;
}
/*
@@ -518,12 +550,9 @@ nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
{
int status;
- dprintk("RPC: attrstat status %lx\n", (long)ntohl(*p));
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
xdr_decode_fattr(p, fattr);
- dprintk("RPC: attrstat OK type %d mode %o dev %x ino %x\n",
- fattr->type, fattr->mode, fattr->fsid, fattr->fileid);
return 0;
}
@@ -536,36 +565,34 @@ nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
{
int status;
- dprintk("RPC: diropres status %lx\n", (long)ntohl(*p));
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
p = xdr_decode_fhandle(p, res->fh);
xdr_decode_fattr(p, res->fattr);
- dprintk("RPC: diropres OK type %x mode %o dev %x ino %x\n",
- res->fattr->type, res->fattr->mode,
- res->fattr->fsid, res->fattr->fileid);
return 0;
}
/*
- * Encode arguments to readlink call
+ * Encode READLINK args
*/
-static int nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
+static int
+nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
{
struct rpc_task *task = req->rq_task;
struct rpc_auth *auth = task->tk_auth;
- int bufsiz = NFS_MAXPATHLEN;
- int replen;
+ int buflen, replen;
p = xdr_encode_fhandle(p, args->fh);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
- req->rq_rvec[0].iov_len = replen;
- req->rq_rvec[1].iov_base = (void *) args->buffer;
- req->rq_rvec[1].iov_len = bufsiz;
- req->rq_rlen = replen + bufsiz;
- req->rq_rnr = 2;
-
+ buflen = req->rq_rvec[0].iov_len;
+ req->rq_rvec[0].iov_len = replen;
+ req->rq_rvec[1].iov_base = args->buffer;
+ req->rq_rvec[1].iov_len = args->bufsiz;
+ req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+ req->rq_rvec[2].iov_len = buflen - replen;
+ req->rq_rlen = buflen + args->bufsiz;
+ req->rq_rnr += 2;
return 0;
}
@@ -573,31 +600,24 @@ static int nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlin
* Decode READLINK reply
*/
static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
{
- struct iovec *iov = req->rq_rvec;
- int status, len;
- char *name;
+ u32 *strlen;
+ char *string;
+ int status;
+ unsigned int len;
- /* Verify OK status. */
- if ((status = ntohl(*p++)) != 0)
+ if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
-
- /* Verify OK response length. */
- if ((__u8 *)p != ((u8 *) iov->iov_base + iov->iov_len))
- return -errno_NFSERR_IO;
-
- /* Convert and verify that string length is in range. */
- p = iov[1].iov_base;
- len = *p = ntohl(*p);
- p++;
- if (len > iov[1].iov_len)
- return -errno_NFSERR_IO;
-
- /* NULL terminate the string we got. */
- name = (char *) p;
- name[len] = 0;
-
+ strlen = (u32*)res->buffer;
+ /* Convert length of symlink */
+ len = ntohl(*strlen);
+ if (len > res->bufsiz - 5)
+ len = res->bufsiz - 5;
+ *strlen = len;
+ /* NULL terminate the string we got */
+ string = (char *)(strlen + 1);
+ string[len] = 0;
return 0;
}
@@ -618,14 +638,34 @@ static int
nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
{
int status;
+ u32 xfer_size;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
- res->tsize = ntohl(*p++);
- res->bsize = ntohl(*p++);
- res->blocks = ntohl(*p++);
- res->bfree = ntohl(*p++);
- res->bavail = ntohl(*p++);
+
+ /* For NFSv2, we more or less have to guess the preferred
+ * read/write/readdir sizes from the single 'transfer size'
+ * value.
+ */
+ xfer_size = ntohl(*p++); /* tsize */
+ res->rtmax = 8 * 1024;
+ res->rtpref = xfer_size;
+ res->rtmult = xfer_size;
+ res->wtmax = 8 * 1024;
+ res->wtpref = xfer_size;
+ res->wtmult = xfer_size;
+ res->dtpref = PAGE_CACHE_SIZE;
+ res->maxfilesize = 0x7FFFFFFF; /* just a guess */
+ res->bsize = ntohl(*p++);
+
+ res->tbytes = ntohl(*p++) * res->bsize;
+ res->fbytes = ntohl(*p++) * res->bsize;
+ res->abytes = ntohl(*p++) * res->bsize;
+ res->tfiles = 0;
+ res->ffiles = 0;
+ res->afiles = 0;
+ res->namelen = 0;
+
return 0;
}
@@ -642,7 +682,7 @@ static struct {
{ NFSERR_NOENT, ENOENT },
{ NFSERR_IO, errno_NFSERR_IO },
{ NFSERR_NXIO, ENXIO },
- { NFSERR_EAGAIN, EAGAIN },
+/* { NFSERR_EAGAIN, EAGAIN }, */
{ NFSERR_ACCES, EACCES },
{ NFSERR_EXIST, EEXIST },
{ NFSERR_XDEV, EXDEV },
@@ -653,18 +693,31 @@ static struct {
{ NFSERR_FBIG, EFBIG },
{ NFSERR_NOSPC, ENOSPC },
{ NFSERR_ROFS, EROFS },
- { NFSERR_OPNOTSUPP, EOPNOTSUPP },
+ { NFSERR_MLINK, EMLINK },
{ NFSERR_NAMETOOLONG, ENAMETOOLONG },
{ NFSERR_NOTEMPTY, ENOTEMPTY },
{ NFSERR_DQUOT, EDQUOT },
{ NFSERR_STALE, ESTALE },
+ { NFSERR_REMOTE, EREMOTE },
#ifdef EWFLUSH
{ NFSERR_WFLUSH, EWFLUSH },
#endif
+ { NFSERR_BADHANDLE, EBADHANDLE },
+ { NFSERR_NOT_SYNC, ENOTSYNC },
+ { NFSERR_BAD_COOKIE, EBADCOOKIE },
+ { NFSERR_NOTSUPP, ENOTSUPP },
+ { NFSERR_TOOSMALL, ETOOSMALL },
+ { NFSERR_SERVERFAULT, ESERVERFAULT },
+ { NFSERR_BADTYPE, EBADTYPE },
+ { NFSERR_JUKEBOX, EJUKEBOX },
{ -1, EIO }
};
-static int
+/*
+ * Convert an NFS error code to a local one.
+ * This one is used jointly by NFSv2 and NFSv3.
+ */
+int
nfs_stat_to_errno(int stat)
{
int i;
@@ -673,7 +726,7 @@ nfs_stat_to_errno(int stat)
if (nfs_errtbl[i].stat == stat)
return nfs_errtbl[i].errno;
}
- printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
+ printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
return nfs_errtbl[i].errno;
}
@@ -685,7 +738,8 @@ nfs_stat_to_errno(int stat)
{ "nfs_" #proc, \
(kxdrproc_t) nfs_xdr_##argtype, \
(kxdrproc_t) nfs_xdr_##restype, \
- MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2 \
+ MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
+ 0 \
}
static struct rpc_procinfo nfs_procedures[18] = {
@@ -709,22 +763,8 @@ static struct rpc_procinfo nfs_procedures[18] = {
PROC(statfs, fhandle, statfsres),
};
-static struct rpc_version nfs_version2 = {
+struct rpc_version nfs_version2 = {
2,
sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
nfs_procedures
};
-
-static struct rpc_version * nfs_version[] = {
- NULL,
- NULL,
- &nfs_version2
-};
-
-struct rpc_program nfs_program = {
- "nfs",
- NFS_PROGRAM,
- sizeof(nfs_version) / sizeof(nfs_version[0]),
- nfs_version,
- &nfs_rpcstat,
-};
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
new file mode 100644
index 000000000..67de662a6
--- /dev/null
+++ b/fs/nfs/nfs3proc.c
@@ -0,0 +1,477 @@
+/*
+ * linux/fs/nfs/nfs3proc.c
+ *
+ * Client-side NFSv3 procedures stubs.
+ *
+ * Copyright (C) 1997, Olaf Kirch
+ */
+
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include <asm/segment.h>
+
+#define NFSDBG_FACILITY NFSDBG_PROC
+
+/*
+ * Bare-bones access to getattr: this is for nfs_read_super.
+ */
+static int
+nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ int status;
+
+ dprintk("NFS call getroot\n");
+ fattr->valid = 0;
+ status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0);
+ dprintk("NFS reply getroot\n");
+ return status;
+}
+
+/*
+ * One function for each procedure in the NFS protocol.
+ */
+static int
+nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
+{
+ int status;
+
+ dprintk("NFS call getattr\n");
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR,
+ NFS_FH(dentry), fattr, 0);
+ dprintk("NFS reply getattr\n");
+ return status;
+}
+
+static int
+nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+ struct iattr *sattr)
+{
+ struct nfs3_sattrargs arg = { NFS_FH(dentry), sattr, 0, 0 };
+ int status;
+
+ dprintk("NFS call setattr\n");
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0);
+ dprintk("NFS reply setattr\n");
+ return status;
+}
+
+static int
+nfs3_proc_lookup(struct dentry *dir, struct qstr *name,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len };
+ struct nfs3_diropres res = { &dir_attr, fhandle, fattr };
+ int status;
+
+ dprintk("NFS call lookup %s\n", name->name);
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0);
+ if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR))
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR,
+ fhandle, fattr, 0);
+ dprintk("NFS reply lookup: %d\n", status);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ return status;
+}
+
+static int
+nfs3_proc_access(struct dentry *dentry, int mode, int ruid)
+{
+ struct nfs_fattr fattr;
+ struct nfs3_accessargs arg = { NFS_FH(dentry), 0 };
+ struct nfs3_accessres res = { &fattr, 0 };
+ int status, flags;
+
+ dprintk("NFS call access\n");
+ fattr.valid = 0;
+
+ if (mode & MAY_READ)
+ arg.access |= NFS3_ACCESS_READ;
+ if (S_ISDIR(dentry->d_inode->i_mode)) {
+ if (mode & MAY_WRITE)
+ arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
+ if (mode & MAY_EXEC)
+ arg.access |= NFS3_ACCESS_LOOKUP;
+ } else {
+ if (mode & MAY_WRITE)
+ arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND;
+ if (mode & MAY_EXEC)
+ arg.access |= NFS3_ACCESS_EXECUTE;
+ }
+ flags = (ruid) ? RPC_CALL_REALUID : 0;
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags);
+ nfs_refresh_inode(dentry->d_inode, &fattr);
+ dprintk("NFS reply access\n");
+
+ if (status == 0 && (arg.access & res.access) != arg.access)
+ status = -EACCES;
+ return status;
+}
+
+static int
+nfs3_proc_readlink(struct dentry *dentry, void *buffer, unsigned int buflen)
+{
+ struct nfs_fattr fattr;
+ struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen };
+ struct nfs3_readlinkres res = { &fattr, buffer, buflen };
+ int status;
+
+ dprintk("NFS call readlink\n");
+ fattr.valid = 0;
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK,
+ &args, &res, 0);
+ nfs_refresh_inode(dentry->d_inode, &fattr);
+ dprintk("NFS reply readlink: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+ loff_t offset, unsigned int count, void *buffer, int *eofp)
+{
+ struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1,
+ {{buffer, count}, {0,0}, {0,0}, {0,0},
+ {0,0}, {0,0}, {0,0}, {0,0}} };
+ struct nfs_readres res = { fattr, count, 0 };
+ struct rpc_message msg = { NFS3PROC_READ, &arg, &res, NULL };
+ int status;
+
+ dprintk("NFS call read %d @ %Ld\n", count, (long long)offset);
+ fattr->valid = 0;
+ status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+ dprintk("NFS reply read: %d\n", status);
+ *eofp = res.eof;
+ return status;
+}
+
+static int
+nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+ loff_t offset, unsigned int count,
+ void *buffer, struct nfs_writeverf *verf)
+{
+ struct nfs_writeargs arg = { NFS_FH(dentry), offset, count,
+ NFS_FILE_SYNC, 1,
+ {{buffer, count}, {0,0}, {0,0}, {0,0},
+ {0,0}, {0,0}, {0,0}, {0,0}} };
+ struct nfs_writeres res = { fattr, verf, 0 };
+ struct rpc_message msg = { NFS3PROC_WRITE, &arg, &res, NULL };
+ int status, rpcflags = 0;
+
+ dprintk("NFS call write %d @ %Ld\n", count, (long long)offset);
+ fattr->valid = 0;
+ if (flags & NFS_RW_SWAP)
+ rpcflags |= NFS_RPC_SWAPFLAGS;
+ arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
+
+ status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags);
+
+ dprintk("NFS reply read: %d\n", status);
+ return status < 0? status : res.count;
+}
+
+/*
+ * Create a regular file.
+ * For now, we don't implement O_EXCL.
+ */
+static int
+nfs3_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+ int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_createargs arg = { NFS_FH(dir), name->name, name->len,
+ sattr, 0, { 0, 0 } };
+ struct nfs3_diropres res = { &dir_attr, fhandle, fattr };
+ int status;
+
+ dprintk("NFS call create %s\n", name->name);
+ arg.createmode = NFS3_CREATE_UNCHECKED;
+ if (flags & O_EXCL) {
+ arg.createmode = NFS3_CREATE_EXCLUSIVE;
+ arg.verifier[0] = jiffies;
+ arg.verifier[1] = current->pid;
+ }
+
+again:
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+
+ /* If the server doesn't support the exclusive creation semantics,
+ * try again with simple 'guarded' mode. */
+ if (status == NFSERR_NOTSUPP) {
+ switch (arg.createmode) {
+ case NFS3_CREATE_EXCLUSIVE:
+ arg.createmode = NFS3_CREATE_GUARDED;
+ break;
+
+ case NFS3_CREATE_GUARDED:
+ arg.createmode = NFS3_CREATE_UNCHECKED;
+ break;
+
+ case NFS3_CREATE_UNCHECKED:
+ goto exit;
+ }
+ goto again;
+ }
+
+exit:
+ dprintk("NFS reply create: %d\n", status);
+
+ /* When we created the file with exclusive semantics, make
+ * sure we set the attributes afterwards. */
+ if (status == 0 && arg.createmode == NFS3_CREATE_EXCLUSIVE) {
+ struct nfs3_sattrargs arg = { fhandle, sattr, 0, 0 };
+ dprintk("NFS call setattr (post-create)\n");
+
+ /* Note: we could use a guarded setattr here, but I'm
+ * not sure this buys us anything (and I'd have
+ * to revamp the NFSv3 XDR code) */
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR,
+ &arg, fattr, 0);
+ dprintk("NFS reply setattr (post-create): %d\n", status);
+ }
+
+ return status;
+}
+
+static int
+nfs3_proc_remove(struct dentry *dir, struct qstr *name)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len };
+ struct rpc_message msg = { NFS3PROC_REMOVE, &arg, &dir_attr, NULL };
+ int status;
+
+ dprintk("NFS call remove %s\n", name->name);
+ dir_attr.valid = 0;
+ status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ dprintk("NFS reply remove: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name,
+ struct dentry *new_dir, struct qstr *new_name)
+{
+ struct nfs_fattr old_dir_attr, new_dir_attr;
+ struct nfs3_renameargs arg = { NFS_FH(old_dir),
+ old_name->name, old_name->len,
+ NFS_FH(new_dir),
+ new_name->name, new_name->len };
+ struct nfs3_renameres res = { &old_dir_attr, &new_dir_attr };
+ int status;
+
+ dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name);
+ old_dir_attr.valid = 0;
+ new_dir_attr.valid = 0;
+ status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0);
+ nfs_refresh_inode(old_dir->d_inode, &old_dir_attr);
+ nfs_refresh_inode(new_dir->d_inode, &new_dir_attr);
+ dprintk("NFS reply rename: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name)
+{
+ struct nfs_fattr dir_attr, fattr;
+ struct nfs3_linkargs arg = { NFS_FH(dentry), NFS_FH(dir),
+ name->name, name->len };
+ struct nfs3_linkres res = { &dir_attr, &fattr };
+ int status;
+
+ dprintk("NFS call link %s\n", name->name);
+ dir_attr.valid = 0;
+ fattr.valid = 0;
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ nfs_refresh_inode(dentry->d_inode, &fattr);
+ dprintk("NFS reply link: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
+ struct iattr *sattr, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_symlinkargs arg = { NFS_FH(dir), name->name, name->len,
+ path->name, path->len, sattr };
+ struct nfs3_diropres res = { &dir_attr, fhandle, fattr };
+ int status;
+
+ dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ dprintk("NFS reply symlink: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_createargs arg = { NFS_FH(dir), name->name, name->len,
+ sattr, 0, { 0, 0 } };
+ struct nfs3_diropres res = { &dir_attr, fhandle, fattr };
+ int status;
+
+ dprintk("NFS call mkdir %s\n", name->name);
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ dprintk("NFS reply mkdir: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_rmdir(struct dentry *dir, struct qstr *name)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len };
+ int status;
+
+ dprintk("NFS call rmdir %s\n", name->name);
+ dir_attr.valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, &dir_attr, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ dprintk("NFS reply rmdir: %d\n", status);
+ return status;
+}
+
+/*
+ * The READDIR implementation is somewhat hackish - we pass the user buffer
+ * to the encode function, which installs it in the receive iovec.
+ * The decode function itself doesn't perform any decoding, it just makes
+ * sure the reply is syntactically correct.
+ *
+ * Also note that this implementation handles both plain readdir and
+ * readdirplus.
+ */
+static int
+nfs3_proc_readdir(struct dentry *dir, u64 cookie, void *entry,
+ unsigned int size, int plus)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
+ struct nfs3_readdirres res = { &dir_attr, 0, 0, 0, 0 };
+ struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, NULL };
+ u32 *verf = NFS_COOKIEVERF(dir->d_inode);
+ int status;
+
+ arg.buffer = entry;
+ arg.bufsiz = size;
+ arg.verf[0] = verf[0];
+ arg.verf[1] = verf[1];
+ arg.plus = plus;
+ res.buffer = entry;
+ res.bufsiz = size;
+ res.verf = verf;
+ res.plus = plus;
+
+ if (plus)
+ msg.rpc_proc = NFS3PROC_READDIRPLUS;
+
+ dprintk("NFS call readdir%s %d\n",
+ plus? "plus" : "", (unsigned int) cookie);
+
+ dir_attr.valid = 0;
+ status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ dprintk("NFS reply readdir: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+ dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+ struct nfs_fattr dir_attr;
+ struct nfs3_mknodargs arg = { NFS_FH(dir), name->name, name->len, 0,
+ sattr, rdev };
+ struct nfs3_diropres res = { &dir_attr, fh, fattr };
+ int status;
+
+ switch (sattr->ia_mode & S_IFMT) {
+ case S_IFBLK: arg.type = NF3BLK; break;
+ case S_IFCHR: arg.type = NF3CHR; break;
+ case S_IFIFO: arg.type = NF3FIFO; break;
+ case S_IFSOCK: arg.type = NF3SOCK; break;
+ default: return -EINVAL;
+ }
+
+ dprintk("NFS call mknod %s %x\n", name->name, rdev);
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0);
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
+ dprintk("NFS reply mknod: %d\n", status);
+ return status;
+}
+
+/*
+ * This is a combo call of fsstat and fsinfo
+ */
+static int
+nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *info)
+{
+ int status;
+
+ dprintk("NFS call fsstat\n");
+ memset((char *)info, 0, sizeof(*info));
+ status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0);
+ if (status < 0)
+ goto error;
+ status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0);
+
+error:
+ dprintk("NFS reply statfs: %d\n", status);
+ return status;
+}
+
+extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
+
+struct nfs_rpc_ops nfs_v3_clientops = {
+ 3, /* protocol version */
+ nfs3_proc_get_root,
+ nfs3_proc_getattr,
+ nfs3_proc_setattr,
+ nfs3_proc_lookup,
+ nfs3_proc_access,
+ nfs3_proc_readlink,
+ nfs3_proc_read,
+ nfs3_proc_write,
+ NULL, /* commit */
+ nfs3_proc_create,
+ nfs3_proc_remove,
+ nfs3_proc_rename,
+ nfs3_proc_link,
+ nfs3_proc_symlink,
+ nfs3_proc_mkdir,
+ nfs3_proc_rmdir,
+ nfs3_proc_readdir,
+ nfs3_proc_mknod,
+ nfs3_proc_statfs,
+ nfs3_decode_dirent,
+};
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index beed6ec1e..ef8580c02 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -1,94 +1,158 @@
/*
- * linux/fs/nfs/nfs2xdr.c
+ * linux/fs/nfs/nfs3xdr.c
*
* XDR functions to encode/decode NFSv3 RPC arguments and results.
- * Note: this is incomplete!
*
- * Copyright (C) 1996 Olaf Kirch
+ * Copyright (C) 1996, 1997 Olaf Kirch
*/
-#define NFS_NEED_XDR_TYPES
-
#include <linux/param.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#include <linux/nfs_fs.h>
#include <linux/utsname.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/in.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
+#include <linux/kdev_t.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
-#ifdef RPC_DEBUG
-# define RPC_FACILITY RPCDBG_NFS
-#endif
+/* Uncomment this to support servers requiring longword lengths */
+#define NFS_PAD_WRITES 1
-#define QUADLEN(len) (((len) + 3) >> 2)
-static int nfs_stat_to_errno(int stat);
+#define NFSDBG_FACILITY NFSDBG_XDR
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO
+extern int nfs_stat_to_errno(int);
+
/*
* Declare the space requirements for NFS arguments and replies as
* number of 32bit-words
*/
-#define NFS_fhandle_sz (1+16)
-#define NFS_sattr_sz 8
-#define NFS_filename_sz 1+(NFS_MAXNAMLEN>>2)
-#define NFS_path_sz 1+(NFS_MAXPATHLEN>>2)
-#define NFS_fattr_sz 17
-#define NFS_info_sz 5
-#define NFS_entry_sz NFS_filename_sz+3
-
-#define NFS_enc_void_sz 0
-#define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
-#define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
-#define NFS_readargs_sz NFS_fhandle_sz+3
-#define NFS_writeargs_sz NFS_fhandle_sz+4
-#define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
-#define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
-#define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
-#define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
-#define NFS_readdirargs_sz NFS_fhandle_sz+2
-
-#define NFS_dec_void_sz 0
-#define NFS_attrstat_sz 1+NFS_fattr_sz
-#define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
-#define NFS_readlinkres_sz 1+NFS_path_sz
-#define NFS_readres_sz 1+NFS_fattr_sz+1
-#define NFS_stat_sz 1
-#define NFS_readdirres_sz 1
-#define NFS_statfsres_sz 1+NFS_info_sz
+#define NFS3_fhandle_sz 1+16
+#define NFS3_fh_sz NFS3_fhandle_sz /* shorthand */
+#define NFS3_sattr_sz 15
+#define NFS3_filename_sz 1+(NFS3_MAXNAMLEN>>2)
+#define NFS3_path_sz 1+(NFS3_MAXPATHLEN>>2)
+#define NFS3_fattr_sz 21
+#define NFS3_wcc_attr_sz 6
+#define NFS3_pre_op_attr_sz 1+NFS3_wcc_attr_sz
+#define NFS3_post_op_attr_sz 1+NFS3_fattr_sz
+#define NFS3_wcc_data_sz NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
+#define NFS3_fsstat_sz
+#define NFS3_fsinfo_sz
+#define NFS3_pathconf_sz
+#define NFS3_entry_sz NFS3_filename_sz+3
+
+#define NFS3_enc_void_sz 0
+#define NFS3_sattrargs_sz NFS3_fh_sz+NFS3_sattr_sz+3
+#define NFS3_diropargs_sz NFS3_fh_sz+NFS3_filename_sz
+#define NFS3_accessargs_sz NFS3_fh_sz+1
+#define NFS3_readlinkargs_sz NFS3_fh_sz
+#define NFS3_readargs_sz NFS3_fh_sz+3
+#define NFS3_writeargs_sz NFS3_fh_sz+5
+#define NFS3_createargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
+#define NFS3_mkdirargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
+#define NFS3_symlinkargs_sz NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
+#define NFS3_mknodargs_sz NFS3_diropargs_sz+2+NFS3_sattr_sz
+#define NFS3_renameargs_sz NFS3_diropargs_sz+NFS3_diropargs_sz
+#define NFS3_linkargs_sz NFS3_fh_sz+NFS3_diropargs_sz
+#define NFS3_readdirargs_sz NFS3_fh_sz+2
+#define NFS3_commitargs_sz NFS3_fh_sz+3
+
+#define NFS3_dec_void_sz 0
+#define NFS3_attrstat_sz 1+NFS3_fattr_sz
+#define NFS3_wccstat_sz 1+NFS3_wcc_data_sz
+#define NFS3_lookupres_sz 1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
+#define NFS3_accessres_sz 1+NFS3_post_op_attr_sz+1
+#define NFS3_readlinkres_sz 1+NFS3_post_op_attr_sz
+#define NFS3_readres_sz 1+NFS3_post_op_attr_sz+3
+#define NFS3_writeres_sz 1+NFS3_wcc_data_sz+4
+#define NFS3_createres_sz 1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
+#define NFS3_renameres_sz 1+(2 * NFS3_wcc_data_sz)
+#define NFS3_linkres_sz 1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
+#define NFS3_readdirres_sz 1+NFS3_post_op_attr_sz+2
+#define NFS3_fsstatres_sz 1+NFS3_post_op_attr_sz+13
+#define NFS3_fsinfores_sz 1+NFS3_post_op_attr_sz+12
+#define NFS3_pathconfres_sz 1+NFS3_post_op_attr_sz+6
+#define NFS3_commitres_sz 1+NFS3_wcc_data_sz+2
+
+/*
+ * Map file type to S_IFMT bits
+ */
+static struct {
+ unsigned int mode;
+ unsigned int nfs2type;
+} nfs_type2fmt[] = {
+ { 0, NFNON },
+ { S_IFREG, NFREG },
+ { S_IFDIR, NFDIR },
+ { S_IFBLK, NFBLK },
+ { S_IFCHR, NFCHR },
+ { S_IFLNK, NFLNK },
+ { S_IFSOCK, NFSOCK },
+ { S_IFIFO, NFFIFO },
+ { 0, NFBAD }
+};
/*
* Common NFS XDR functions as inlines
*/
static inline u32 *
-xdr_encode_fhandle(u32 *p, struct nfs3_fh *fh)
+xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
{
*p++ = htonl(fh->size);
memcpy(p, fh->data, fh->size);
- return p + QUADLEN(fh->size);
+ return p + XDR_QUADLEN(fh->size);
}
static inline u32 *
-xdr_decode_fhandle(u32 *p, struct nfs3_fh *fh)
+xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
{
+ /*
+ * Zero all nonused bytes
+ */
+ memset((u8 *)fh, 0, sizeof(*fh));
if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
memcpy(fh->data, p, fh->size);
- return p + QUADLEN(fh->size);
+ return p + XDR_QUADLEN(fh->size);
}
return NULL;
}
-static inline enum nfs_ftype
-xdr_decode_ftype(u32 type)
+/*
+ * Encode/decode time.
+ * Since the VFS doesn't care for fractional times, we ignore the
+ * nanosecond field.
+ */
+static inline u32 *
+xdr_encode_time(u32 *p, time_t time)
+{
+ *p++ = htonl(time);
+ *p++ = 0;
+ return p;
+}
+
+static inline u32 *
+xdr_decode_time3(u32 *p, u64 *timep)
{
- return (type == NF3FIFO)? NFFIFO : (enum nfs_ftype) type;
+ *timep = ((u64)ntohl(*p++) << 32) + (u64)ntohl(*p++);
+ return p;
+}
+
+static inline u32 *
+xdr_encode_time3(u32 *p, u64 time)
+{
+ *p++ = htonl(time >> 32);
+ *p++ = htonl(time & 0xFFFFFFFF);
+ return p;
}
static inline u32 *
@@ -99,47 +163,119 @@ xdr_decode_string2(u32 *p, char **string, unsigned int *len,
if (*len > maxlen)
return NULL;
*string = (char *) p;
- return p + QUADLEN(*len);
+ return p + XDR_QUADLEN(*len);
}
static inline u32 *
-xdr_decode_fattr(u32 *p, struct nfs3_fattr *fattr)
+xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
{
- fattr->type = xdr_decode_ftype(ntohl(*p++));
- fattr->mode = ntohl(*p++);
+ unsigned int type;
+ int fmode;
+
+ type = ntohl(*p++);
+ if (type >= NF3BAD)
+ type = NF3BAD;
+ fmode = nfs_type2fmt[type].mode;
+ fattr->type = nfs_type2fmt[type].nfs2type;
+ fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
fattr->nlink = ntohl(*p++);
fattr->uid = ntohl(*p++);
fattr->gid = ntohl(*p++);
- fattr->size = ((u64) ntohl(*p++) << 32) | ntohl(*p++);
- fattr->used = ((u64) ntohl(*p++) << 32) | ntohl(*p++);
- fattr->rdev_maj = ntohl(*p++);
- fattr->rdev_min = ntohl(*p++);
- fattr->fsid = ntohl(*p++);
- fattr->fileid = ntohl(*p++);
- fattr->atime.seconds = ntohl(*p++);
- fattr->atime.useconds = ntohl(*p++);
- fattr->mtime.seconds = ntohl(*p++);
- fattr->mtime.useconds = ntohl(*p++);
- fattr->ctime.seconds = ntohl(*p++);
- fattr->ctime.useconds = ntohl(*p++);
+ p = xdr_decode_hyper(p, &fattr->size);
+ p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
+ /* Turn remote device info into Linux-specific dev_t */
+ fattr->rdev = (ntohl(*p++) << MINORBITS) | (ntohl(*p++) & MINORMASK);
+ p = xdr_decode_hyper(p, &fattr->fsid);
+ p = xdr_decode_hyper(p, &fattr->fileid);
+ p = xdr_decode_time3(p, &fattr->atime);
+ p = xdr_decode_time3(p, &fattr->mtime);
+ p = xdr_decode_time3(p, &fattr->ctime);
+
+ /* Update the mode bits */
+ fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
+ return p;
+}
+
+static inline u32 *
+xdr_encode_sattr(u32 *p, struct iattr *attr)
+{
+ if (attr->ia_valid & ATTR_MODE) {
+ *p++ = xdr_one;
+ *p++ = htonl(attr->ia_mode);
+ } else {
+ *p++ = xdr_zero;
+ }
+ if (attr->ia_valid & ATTR_UID) {
+ *p++ = xdr_one;
+ *p++ = htonl(attr->ia_uid);
+ } else {
+ *p++ = xdr_zero;
+ }
+ if (attr->ia_valid & ATTR_GID) {
+ *p++ = xdr_one;
+ *p++ = htonl(attr->ia_gid);
+ } else {
+ *p++ = xdr_zero;
+ }
+ if (attr->ia_valid & ATTR_SIZE) {
+ *p++ = xdr_one;
+ p = xdr_encode_hyper(p, (__u64) attr->ia_size);
+ } else {
+ *p++ = xdr_zero;
+ }
+ if (attr->ia_valid & ATTR_ATIME_SET) {
+ *p++ = xdr_two;
+ p = xdr_encode_time(p, attr->ia_atime);
+ } else if (attr->ia_valid & ATTR_ATIME) {
+ *p++ = xdr_one;
+ } else {
+ *p++ = xdr_zero;
+ }
+ if (attr->ia_valid & ATTR_MTIME_SET) {
+ *p++ = xdr_two;
+ p = xdr_encode_time(p, attr->ia_mtime);
+ } else if (attr->ia_valid & ATTR_MTIME) {
+ *p++ = xdr_one;
+ } else {
+ *p++ = xdr_zero;
+ }
+ return p;
+}
+
+static inline u32 *
+xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
+{
+ p = xdr_decode_hyper(p, &fattr->pre_size);
+ p = xdr_decode_time3(p, &fattr->pre_mtime);
+ p = xdr_decode_time3(p, &fattr->pre_ctime);
+ fattr->valid |= NFS_ATTR_WCC;
return p;
}
static inline u32 *
-xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
-{
- *p++ = htonl(sattr->mode);
- *p++ = htonl(sattr->uid);
- *p++ = htonl(sattr->gid);
- *p++ = htonl(sattr->size >> 32);
- *p++ = htonl(sattr->size & 0xFFFFFFFF);
- *p++ = htonl(sattr->atime.seconds);
- *p++ = htonl(sattr->atime.useconds);
- *p++ = htonl(sattr->mtime.seconds);
- *p++ = htonl(sattr->mtime.useconds);
+xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
+{
+ if (*p++)
+ p = xdr_decode_fattr(p, fattr);
return p;
}
+static inline u32 *
+xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
+{
+ if (*p++)
+ return xdr_decode_wcc_attr(p, fattr);
+ return p;
+}
+
+
+static inline u32 *
+xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
+{
+ p = xdr_decode_pre_op_attr(p, fattr);
+ return xdr_decode_post_op_attr(p, fattr);
+}
+
/*
* NFS encode functions
*/
@@ -147,7 +283,7 @@ xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
* Encode void argument
*/
static int
-nfs_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
{
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
@@ -155,10 +291,9 @@ nfs_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
/*
* Encode file handle argument
- * GETATTR, READLINK, STATFS
*/
static int
-nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs3_fh *fh)
+nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
{
p = xdr_encode_fhandle(p, fh);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -169,23 +304,37 @@ nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs3_fh *fh)
* Encode SETATTR arguments
*/
static int
-nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
+nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_sattr(p, args->sattr);
+ *p++ = htonl(args->guard);
+ if (args->guard)
+ p = xdr_encode_time3(p, args->guardtime);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
/*
* Encode directory ops argument
- * LOOKUP, REMOVE, RMDIR
*/
static int
-nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
+nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
+{
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+/*
+ * Encode access() argument
+ */
+static int
+nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_string(p, args->name);
+ *p++ = htonl(args->access);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
@@ -193,149 +342,181 @@ nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
/*
* Arguments to a READ call. Since we read data directly into the page
* cache, we also set up the reply iovec here so that iov[1] points
- * exactly to the page wewant to fetch.
+ * exactly to the page we want to fetch.
*/
static int
-nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
+nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
- int replen, buflen;
+ int buflen, replen;
+ unsigned int nr;
p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->offset);
- *p++ = htonl(args->count);
+ p = xdr_encode_hyper(p, args->offset);
*p++ = htonl(args->count);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-#if 1
+ /* Get the number of buffers in the receive iovec */
+ nr = args->nriov;
+
+ if (nr+2 > MAX_IOVEC) {
+ printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
+ return -EINVAL;
+ }
+
/* set up reply iovec */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
buflen = req->rq_rvec[0].iov_len;
req->rq_rvec[0].iov_len = replen;
- req->rq_rvec[1].iov_base = args->buffer;
- req->rq_rvec[1].iov_len = args->count;
- req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
- req->rq_rvec[2].iov_len = buflen - replen;
+
+ /* Copy the iovec */
+ memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
+
+ req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+ req->rq_rvec[nr+1].iov_len = buflen - replen;
req->rq_rlen = args->count + buflen;
- req->rq_rnr = 3;
-#else
- replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
- req->rq_rvec[0].iov_len = replen;
-#endif
+ req->rq_rnr += nr+1;
return 0;
}
/*
- * Decode READ reply
+ * Write arguments. Splice the buffer to be written into the iovec.
*/
static int
-nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
+nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
{
- struct iovec *iov = req->rq_rvec;
- int status, count, recvd, hdrlen;
+ unsigned int nr;
+ u32 count = args->count;
- dprintk("RPC: readres OK status %lx\n", ntohl(*p));
- if ((status = ntohl(*p++)))
- return -nfs_stat_to_errno(status);
- p = xdr_decode_fattr(p, res->fattr);
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_hyper(p, args->offset);
+ *p++ = htonl(count);
+ *p++ = htonl(args->stable);
+ *p++ = htonl(count);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- count = ntohl(*p++);
- hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- recvd = req->rq_rlen - hdrlen;
- if (p != iov[2].iov_base) {
- /* Unexpected reply header size. Punt.
- * XXX: Move iovec contents to align data on page
- * boundary and adjust RPC header size guess */
- printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen);
- return -errno_NFSERR_IO;
- }
- if (count > recvd) {
- printk("NFS: server cheating in read reply: "
- "count %d > recvd %d\n", count, recvd);
- count = recvd;
+ /* 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\n");
+ return -EINVAL;
}
- dprintk("RPC: readres OK count %d\n", count);
- if (count < res->count)
- memset((u8 *)(iov[1].iov_base+count), 0, res->count-count);
+ /* Copy the iovec */
+ memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
- return count;
-}
+#ifdef NFS_PAD_WRITES
+ /*
+ * Some old servers require that the message length
+ * be a multiple of 4, so we pad it here if needed.
+ */
+ 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;
+}
/*
- * Write arguments. Splice the buffer to be written into the iovec.
+ * Encode CREATE arguments
*/
static int
-nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->offset);
- *p++ = htonl(args->offset);
- *p++ = htonl(args->count);
- *p++ = htonl(args->count);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ p = xdr_encode_array(p, args->name, args->len);
- req->rq_svec[1].iov_base = (void *) args->buffer;
- req->rq_svec[1].iov_len = args->count;
- req->rq_slen += args->count;
- req->rq_snr = 2;
+ *p++ = htonl(args->createmode);
+ if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
+ *p++ = args->verifier[0];
+ *p++ = args->verifier[1];
+ } else
+ p = xdr_encode_sattr(p, args->sattr);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
/*
- * Encode create arguments
- * CREATE, MKDIR
+ * Encode MKDIR arguments
*/
static int
-nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
+nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_string(p, args->name);
+ p = xdr_encode_array(p, args->name, args->len);
p = xdr_encode_sattr(p, args->sattr);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
/*
- * Encode RENAME arguments
+ * Encode SYMLINK arguments
*/
static int
-nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
+nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_string(p, args->fromname);
- p = xdr_encode_fhandle(p, args->tofh);
- p = xdr_encode_string(p, args->toname);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
+ p = xdr_encode_sattr(p, args->sattr);
+ p = xdr_encode_array(p, args->topath, args->tolen);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
/*
- * Encode LINK arguments
+ * Encode MKNOD arguments
+ */
+static int
+nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
+{
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name, args->len);
+ *p++ = htonl(args->type);
+ p = xdr_encode_sattr(p, args->sattr);
+ if (args->type == NF3CHR || args->type == NF3BLK) {
+ *p++ = htonl(args->rdev >> MINORBITS);
+ *p++ = htonl(args->rdev & MINORMASK);
+ }
+
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+/*
+ * Encode RENAME arguments
*/
static int
-nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
+nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
+ p = xdr_encode_array(p, args->fromname, args->fromlen);
p = xdr_encode_fhandle(p, args->tofh);
- p = xdr_encode_string(p, args->toname);
+ p = xdr_encode_array(p, args->toname, args->tolen);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
/*
- * Encode SYMLINK arguments
+ * Encode LINK arguments
*/
static int
-nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
+nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_string(p, args->fromname);
- p = xdr_encode_string(p, args->topath);
- p = xdr_encode_sattr(p, args->sattr);
+ p = xdr_encode_fhandle(p, args->tofh);
+ p = xdr_encode_array(p, args->toname, args->tolen);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
@@ -344,131 +525,164 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
* Encode arguments to readdir call
*/
static int
-nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
+nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
- int replen;
+ int buflen, replen;
p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->cookie);
+ p = xdr_encode_hyper(p, args->cookie);
+ *p++ = args->verf[0];
+ *p++ = args->verf[1];
+ if (args->plus) {
+ /* readdirplus: need dircount + buffer size.
+ * We just make sure we make dircount big enough */
+ *p++ = htonl(args->bufsiz >> 3);
+ }
*p++ = htonl(args->bufsiz);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
/* set up reply iovec */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
- /*
- dprintk("RPC: readdirargs: slack is 4 * (%d + %d + %d) = %d\n",
- RPC_REPHDRSIZE, auth->au_rslack, NFS_readdirres_sz, replen);
- */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
+ buflen = req->rq_rvec[0].iov_len;
req->rq_rvec[0].iov_len = replen;
req->rq_rvec[1].iov_base = args->buffer;
req->rq_rvec[1].iov_len = args->bufsiz;
- req->rq_rlen = replen + args->bufsiz;
- req->rq_rnr = 2;
-
- /*
- dprintk("RPC: readdirargs set up reply vec:\n");
- dprintk(" rvec[0] = %p/%d\n",
- req->rq_rvec[0].iov_base,
- req->rq_rvec[0].iov_len);
- dprintk(" rvec[1] = %p/%d\n",
- req->rq_rvec[1].iov_base,
- req->rq_rvec[1].iov_len);
- */
+ req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+ req->rq_rvec[2].iov_len = buflen - replen;
+ req->rq_rlen = buflen + args->bufsiz;
+ req->rq_rnr += 2;
return 0;
}
/*
- * Decode the result of a readdir call. We decode the result in place
- * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
- * After decoding, the layout in memory looks like this:
- * entry1 entry2 ... entryN <space> stringN ... string2 string1
- * Each entry consists of three __u32 values, the same space as NFS uses.
- * Note that the strings are not null-terminated so that the entire number
- * of entries returned by the server should fit into the buffer.
+ * Decode the result of a readdir call.
+ * We just check for syntactical correctness.
*/
static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
+nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
{
- struct iovec *iov = req->rq_rvec;
- int status, nr, len;
- char *string, *start;
- u32 *end;
- __u32 fileid, cookie, *entry;
-
- if ((status = ntohl(*p++)))
+ struct iovec *iov = req->rq_rvec;
+ int hdrlen;
+ int status, nr;
+ unsigned int len;
+ u32 *entry, *end;
+
+ status = ntohl(*p++);
+ /* Decode post_op_attrs */
+ p = xdr_decode_post_op_attr(p, res->dir_attr);
+ if (status)
return -nfs_stat_to_errno(status);
- if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) {
- /* Unexpected reply header size. Punt. */
- printk("NFS: Odd RPC header size in readdirres reply\n");
- return -errno_NFSERR_IO;
+ /* Decode verifier cookie */
+ if (res->verf) {
+ res->verf[0] = *p++;
+ res->verf[1] = *p++;
+ } else {
+ p += 2;
}
- p = (u32 *) iov[1].iov_base;
- end = (u32 *) ((u8 *) p + iov[1].iov_len);
-
- if (p != res->buffer) {
- printk("NFS: p != res->buffer in %s:%d!!!\n",
- __FILE__, __LINE__);
- return -errno_NFSERR_IO;
+ hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+ if (iov->iov_len > hdrlen) {
+ dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
+ xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
}
- entry = (__u32 *) res->buffer;
- start = (char *) res->buffer;
- string = start + res->bufsiz;
+ p = (u32 *) iov[1].iov_base;
+ end = (u32 *) ((u8 *) p + iov[1].iov_len);
for (nr = 0; *p++; nr++) {
- fileid = ntohl(*p++);
-
- len = ntohl(*p++);
- if ((p + QUADLEN(len) + 3) > end) {
- printk(KERN_NOTICE
- "NFS: short packet in readdir reply!\n");
- break;
- }
- if (len > NFS_MAXNAMLEN) {
- printk("NFS: giant filename in readdir (len %x)!\n",
+ entry = p - 1;
+ p += 2; /* inode # */
+ len = ntohl(*p++); /* string length */
+ p += XDR_QUADLEN(len) + 2; /* name + cookie */
+ if (len > NFS3_MAXNAMLEN) {
+ printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
len);
return -errno_NFSERR_IO;
}
- string -= len;
- if ((void *) (entry+3) > (void *) string) {
- /*
- * This error is impossible as long as the temp
- * buffer is no larger than the user buffer. The
- * current packing algorithm uses the same amount
- * of space in the user buffer as in the XDR data,
- * so it's guaranteed to fit.
- */
- printk("NFS: incorrect buffer size in %s!\n",
- __FUNCTION__);
- break;
+
+ if (res->plus) {
+ /* post_op_attr */
+ if (*p++)
+ p += 21;
+ /* post_op_fh3 */
+ if (*p++) {
+ len = ntohl(*p++);
+ if (len > NFS3_FHSIZE) {
+ printk(KERN_WARNING "NFS: giant filehandle in "
+ "readdir (len %x)!\n", len);
+ return -errno_NFSERR_IO;
+ }
+ p += XDR_QUADLEN(len);
+ }
}
- memmove(string, p, len);
- p += QUADLEN(len);
- cookie = ntohl(*p++);
- /*
- * To make everything fit, we encode the length, offset,
- * and eof flag into 32 bits. This works for filenames
- * up to 32K and PAGE_SIZE up to 64K.
- */
- status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
- *entry++ = fileid;
- *entry++ = cookie;
- *entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
- /*
- dprintk("NFS: decoded dirent %.*s cookie %d eof %d\n",
- len, string, cookie, status);
- */
+ if (p + 2 > end) {
+ printk(KERN_NOTICE
+ "NFS: short packet in readdir reply!\n");
+ /* truncate listing */
+ entry[0] = entry[1] = 0;
+ break;
+ }
}
-#ifdef NFS_PARANOIA
-printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
-nr, ((char *) entry - start), (start + res->bufsiz - string));
-#endif
+
return nr;
}
+u32 *
+nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+ struct nfs_entry old = *entry;
+
+ if (!*p++) {
+ if (!*p)
+ return ERR_PTR(-EAGAIN);
+ entry->eof = 1;
+ return ERR_PTR(-EBADCOOKIE);
+ }
+
+ p = xdr_decode_hyper(p, &entry->ino);
+ entry->len = ntohl(*p++);
+ entry->name = (const char *) p;
+ p += XDR_QUADLEN(entry->len);
+ entry->prev_cookie = entry->cookie;
+ p = xdr_decode_hyper(p, &entry->cookie);
+
+ if (plus) {
+ p = xdr_decode_post_op_attr(p, &entry->fattr);
+ /* In fact, a post_op_fh3: */
+ if (*p++) {
+ p = xdr_decode_fhandle(p, &entry->fh);
+ /* Ugh -- server reply was truncated */
+ if (p == NULL) {
+ dprintk("NFS: FH truncated\n");
+ *entry = old;
+ return ERR_PTR(-EAGAIN);
+ }
+ } else {
+ /* If we don't get a file handle, the attrs
+ * aren't worth a lot. */
+ entry->fattr.valid = 0;
+ }
+ }
+
+ entry->eof = !p[0] && p[1];
+ return p;
+}
+
+/*
+ * Encode COMMIT arguments
+ */
+static int
+nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+{
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_hyper(p, args->offset);
+ *p++ = htonl(args->count);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
/*
* NFS XDR decode functions
*/
@@ -476,59 +690,92 @@ nr, ((char *) entry - start), (start + res->bufsiz - string));
* Decode void reply
*/
static int
-nfs_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
{
return 0;
}
/*
- * Decode simple status reply
+ * Decode attrstat reply.
*/
static int
-nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
{
int status;
- if ((status = ntohl(*p++)) != 0)
- status = -nfs_stat_to_errno(status);
- return status;
+ if ((status = ntohl(*p++)))
+ return -nfs_stat_to_errno(status);
+ xdr_decode_fattr(p, fattr);
+ return 0;
}
/*
- * Decode attrstat reply
- * GETATTR, SETATTR, WRITE
+ * Decode status+wcc_data reply
+ * SATTR, REMOVE, RMDIR
*/
static int
-nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
{
int status;
- dprintk("RPC: attrstat status %lx\n", ntohl(*p));
if ((status = ntohl(*p++)))
- return -nfs_stat_to_errno(status);
- xdr_decode_fattr(p, fattr);
- dprintk("RPC: attrstat OK type %d mode %o dev %x ino %x\n",
- fattr->type, fattr->mode, fattr->fsid, fattr->fileid);
- return 0;
+ status = -nfs_stat_to_errno(status);
+ xdr_decode_wcc_data(p, fattr);
+ return status;
}
/*
- * Decode diropres reply
- * LOOKUP, CREATE, MKDIR
+ * Decode LOOKUP reply
*/
static int
-nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
+nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
{
int status;
- dprintk("RPC: diropres status %lx\n", ntohl(*p));
- if ((status = ntohl(*p++)))
+ if ((status = ntohl(*p++))) {
+ status = -nfs_stat_to_errno(status);
+ } else {
+ if (!(p = xdr_decode_fhandle(p, res->fh)))
+ return -errno_NFSERR_IO;
+ p = xdr_decode_post_op_attr(p, res->fattr);
+ }
+ xdr_decode_post_op_attr(p, res->dir_attr);
+ return status;
+}
+
+/*
+ * Decode ACCESS reply
+ */
+static int
+nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
+{
+ int status = ntohl(*p++);
+
+ p = xdr_decode_post_op_attr(p, res->fattr);
+ if (status)
return -nfs_stat_to_errno(status);
- p = xdr_decode_fhandle(p, res->fh);
- xdr_decode_fattr(p, res->fattr);
- dprintk("RPC: diropres OK type %x mode %o dev %x ino %x\n",
- res->fattr->type, res->fattr->mode,
- res->fattr->fsid, res->fattr->fileid);
+ res->access = ntohl(*p++);
+ return 0;
+}
+
+static int
+nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
+{
+ struct rpc_task *task = req->rq_task;
+ struct rpc_auth *auth = task->tk_auth;
+ int buflen, replen;
+
+ p = xdr_encode_fhandle(p, args->fh);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
+ buflen = req->rq_rvec[0].iov_len;
+ req->rq_rvec[0].iov_len = replen;
+ req->rq_rvec[1].iov_base = args->buffer;
+ req->rq_rvec[1].iov_len = args->bufsiz;
+ req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+ req->rq_rvec[2].iov_len = buflen - replen;
+ req->rq_rlen = buflen + args->bufsiz;
+ req->rq_rnr += 2;
return 0;
}
@@ -536,155 +783,299 @@ nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
* Decode READLINK reply
*/
static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
{
+ struct iovec *iov = req->rq_rvec;
+ int hdrlen;
+ u32 *strlen;
+ char *string;
int status;
+ unsigned int len;
- if ((status = ntohl(*p++)))
+ status = ntohl(*p++);
+ p = xdr_decode_post_op_attr(p, res->fattr);
+
+ if (status != 0)
return -nfs_stat_to_errno(status);
- xdr_decode_string2(p, res->string, res->lenp, res->maxlen);
- /* Caller takes over the buffer here to avoid extra copy */
- res->buffer = req->rq_task->tk_buffer;
- req->rq_task->tk_buffer = NULL;
+ hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+ if (iov->iov_len > hdrlen) {
+ dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
+ xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+ }
+
+ strlen = (u32*)res->buffer;
+ /* Convert length of symlink */
+ len = ntohl(*strlen);
+ if (len > res->bufsiz - 5)
+ len = res->bufsiz - 5;
+ *strlen = len;
+ /* NULL terminate the string we got */
+ string = (char *)(strlen + 1);
+ string[len] = 0;
return 0;
}
/*
- * Decode STATFS reply
+ * Decode READ reply
*/
static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
{
- int status;
+ struct iovec *iov = req->rq_rvec;
+ int status, count, ocount, recvd, hdrlen;
- if ((status = ntohl(*p++)))
+ status = ntohl(*p++);
+ p = xdr_decode_post_op_attr(p, res->fattr);
+
+ if (status != 0)
return -nfs_stat_to_errno(status);
- res->tsize = ntohl(*p++);
- res->bsize = ntohl(*p++);
- res->blocks = ntohl(*p++);
- res->bfree = ntohl(*p++);
- res->bavail = ntohl(*p++);
- return 0;
+
+ /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
+ * in that it puts the count both in the res struct and in the
+ * opaque data count. */
+ count = ntohl(*p++);
+ res->eof = ntohl(*p++);
+ ocount = ntohl(*p++);
+
+ if (ocount != count) {
+ printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
+ return -errno_NFSERR_IO;
+ }
+
+ hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+ if (iov->iov_len > hdrlen) {
+ dprintk("NFS: READ header is short. iovec will be shifted.\n");
+ xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+ }
+
+ recvd = req->rq_rlen - hdrlen;
+ if (count > recvd) {
+ printk(KERN_WARNING "NFS: server cheating in read reply: "
+ "count %d > recvd %d\n", count, recvd);
+ count = recvd;
+ }
+
+ if (count < res->count) {
+ xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+ res->count = count;
+ }
+
+ return count;
}
/*
- * We need to translate between nfs status return values and
- * the local errno values which may not be the same.
+ * Decode WRITE response
*/
-static struct {
- int stat;
- int errno;
-} nfs_errtbl[] = {
- { NFS_OK, 0 },
- { NFSERR_PERM, EPERM },
- { NFSERR_NOENT, ENOENT },
- { NFSERR_IO, errno_NFSERR_IO },
- { NFSERR_NXIO, ENXIO },
- { NFSERR_EAGAIN, EAGAIN },
- { NFSERR_ACCES, EACCES },
- { NFSERR_EXIST, EEXIST },
- { NFSERR_XDEV, EXDEV },
- { NFSERR_NODEV, ENODEV },
- { NFSERR_NOTDIR, ENOTDIR },
- { NFSERR_ISDIR, EISDIR },
- { NFSERR_INVAL, EINVAL },
- { NFSERR_FBIG, EFBIG },
- { NFSERR_NOSPC, ENOSPC },
- { NFSERR_ROFS, EROFS },
- { NFSERR_NAMETOOLONG, ENAMETOOLONG },
- { NFSERR_NOTEMPTY, ENOTEMPTY },
- { NFSERR_DQUOT, EDQUOT },
- { NFSERR_STALE, ESTALE },
-#ifdef EWFLUSH
- { NFSERR_WFLUSH, EWFLUSH },
-#endif
- { -1, EIO }
-};
+static int
+nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+{
+ int status;
+
+ status = ntohl(*p++);
+ p = xdr_decode_wcc_data(p, res->fattr);
+ if (status != 0)
+ return -nfs_stat_to_errno(status);
+
+ res->count = ntohl(*p++);
+ res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
+ res->verf->verifier[0] = *p++;
+ res->verf->verifier[1] = *p++;
+
+ return res->count;
+}
+
+/*
+ * Decode a CREATE response
+ */
static int
-nfs_stat_to_errno(int stat)
+nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
{
- int i;
+ int status;
- for (i = 0; nfs_errtbl[i].stat != -1; i++) {
- if (nfs_errtbl[i].stat == stat)
- return nfs_errtbl[i].errno;
+ status = ntohl(*p++);
+ if (status == 0) {
+ if (*p++) {
+ if (!(p = xdr_decode_fhandle(p, res->fh)))
+ return -errno_NFSERR_IO;
+ p = xdr_decode_post_op_attr(p, res->fattr);
+ } else {
+ memset(res->fh, 0, sizeof(*res->fh));
+ /* Do decode post_op_attr but set it to NULL */
+ p = xdr_decode_post_op_attr(p, res->fattr);
+ res->fattr->valid = 0;
+ }
+ } else {
+ status = -nfs_stat_to_errno(status);
}
- printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
- return nfs_errtbl[i].errno;
+ p = xdr_decode_wcc_data(p, res->dir_attr);
+ return status;
}
-#ifndef MAX
-# define MAX(a, b) (((a) > (b))? (a) : (b))
-#endif
+/*
+ * Decode RENAME reply
+ */
+static int
+nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
+{
+ int status;
-#define PROC(proc, argtype, restype) \
- { "nfs_" #proc, \
- (kxdrproc_t) nfs_xdr_##argtype, \
- (kxdrproc_t) nfs_xdr_##restype, \
- MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2 \
- }
+ if ((status = ntohl(*p++)) != 0)
+ status = -nfs_stat_to_errno(status);
+ p = xdr_decode_wcc_data(p, res->fromattr);
+ p = xdr_decode_wcc_data(p, res->toattr);
+ return status;
+}
-static struct rpc_procinfo nfs_procedures[18] = {
- PROC(null, enc_void, dec_void),
- PROC(getattr, fhandle, attrstat),
- PROC(setattr, sattrargs, attrstat),
- PROC(root, enc_void, dec_void),
- PROC(lookup, diropargs, diropres),
- PROC(readlink, fhandle, readlinkres),
- PROC(read, readargs, readres),
- PROC(writecache, enc_void, dec_void),
- PROC(write, writeargs, attrstat),
- PROC(create, createargs, diropres),
- PROC(remove, diropargs, stat),
- PROC(rename, renameargs, stat),
- PROC(link, linkargs, stat),
- PROC(symlink, symlinkargs, stat),
- PROC(mkdir, createargs, diropres),
- PROC(rmdir, diropargs, stat),
- PROC(readdir, readdirargs, readdirres),
- PROC(statfs, fhandle, statfsres),
-};
+/*
+ * Decode LINK reply
+ */
+static int
+nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
+{
+ int status;
-static struct rpc_version nfs_version2 = {
- 2,
- sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
- nfs_procedures
-};
+ if ((status = ntohl(*p++)) != 0)
+ status = -nfs_stat_to_errno(status);
+ p = xdr_decode_post_op_attr(p, res->fattr);
+ p = xdr_decode_wcc_data(p, res->dir_attr);
+ return status;
+}
-static struct rpc_version * nfs_version[] = {
- NULL,
- NULL,
- &nfs_version2
-};
+/*
+ * Decode FSSTAT reply
+ */
+static int
+nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+{
+ struct nfs_fattr dummy;
+ int status;
-struct rpc_program nfs_program = {
- "nfs",
- NFS_PROGRAM,
- sizeof(nfs_version) / sizeof(nfs_version[0]),
- nfs_version,
- &nfs_rpcstat,
-};
+ status = ntohl(*p++);
+
+ p = xdr_decode_post_op_attr(p, &dummy);
+ if (status != 0)
+ return -nfs_stat_to_errno(status);
+
+ p = xdr_decode_hyper(p, &res->tbytes);
+ p = xdr_decode_hyper(p, &res->fbytes);
+ p = xdr_decode_hyper(p, &res->abytes);
+ p = xdr_decode_hyper(p, &res->tfiles);
+ p = xdr_decode_hyper(p, &res->ffiles);
+ p = xdr_decode_hyper(p, &res->afiles);
+
+ /* ignore invarsec */
+ return 0;
+}
+
+/*
+ * Decode FSINFO reply
+ */
+static int
+nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+{
+ struct nfs_fattr dummy;
+ int status;
+
+ status = ntohl(*p++);
+
+ p = xdr_decode_post_op_attr(p, &dummy);
+ if (status != 0)
+ return -nfs_stat_to_errno(status);
+
+ res->rtmax = ntohl(*p++);
+ res->rtpref = ntohl(*p++);
+ res->rtmult = ntohl(*p++);
+ res->wtmax = ntohl(*p++);
+ res->wtpref = ntohl(*p++);
+ res->wtmult = ntohl(*p++);
+ res->dtpref = ntohl(*p++);
+ p = xdr_decode_hyper(p, &res->maxfilesize);
+
+ /* ignore time_delta and properties */
+ return 0;
+}
+
+/*
+ * Decode PATHCONF reply
+ */
+static int
+nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+{
+ struct nfs_fattr dummy;
+ int status;
+
+ status = ntohl(*p++);
+
+ p = xdr_decode_post_op_attr(p, &dummy);
+ if (status != 0)
+ return -nfs_stat_to_errno(status);
+ res->linkmax = ntohl(*p++);
+ res->namelen = ntohl(*p++);
+
+ /* ignore remaining fields */
+ return 0;
+}
/*
- * RPC stats support
+ * Decode COMMIT reply
*/
static int
-nfs_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
{
- return rpcstat_get_info(&nfs_rpcstat, buffer, start, offset, length);
+ int status;
+
+ status = ntohl(*p++);
+ p = xdr_decode_wcc_data(p, res->fattr);
+ if (status != 0)
+ return -nfs_stat_to_errno(status);
+
+ res->verf->verifier[0] = *p++;
+ res->verf->verifier[1] = *p++;
+ return 0;
}
-static struct proc_dir_entry proc_nfsclnt = {
- 0, 3, "nfs",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 6, NULL,
- nfs_get_info
+#ifndef MAX
+# define MAX(a, b) (((a) > (b))? (a) : (b))
+#endif
+
+#define PROC(proc, argtype, restype) \
+ { "nfs3_" #proc, \
+ (kxdrproc_t) nfs3_xdr_##argtype, \
+ (kxdrproc_t) nfs3_xdr_##restype, \
+ MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
+ 0 \
+ }
+
+static struct rpc_procinfo nfs3_procedures[22] = {
+ PROC(null, enc_void, dec_void),
+ PROC(getattr, fhandle, attrstat),
+ PROC(setattr, sattrargs, wccstat),
+ PROC(lookup, diropargs, lookupres),
+ PROC(access, accessargs, accessres),
+ PROC(readlink, readlinkargs, readlinkres),
+ PROC(read, readargs, readres),
+ PROC(write, writeargs, writeres),
+ PROC(create, createargs, createres),
+ PROC(mkdir, mkdirargs, createres),
+ PROC(symlink, symlinkargs, createres),
+ PROC(mknod, mknodargs, createres),
+ PROC(remove, diropargs, wccstat),
+ PROC(rmdir, diropargs, wccstat),
+ PROC(rename, renameargs, renameres),
+ PROC(link, linkargs, linkres),
+ PROC(readdir, readdirargs, readdirres),
+ PROC(readdirplus, readdirargs, readdirres),
+ PROC(fsstat, fhandle, fsstatres),
+ PROC(fsinfo, fhandle, fsinfores),
+ PROC(pathconf, fhandle, pathconfres),
+ PROC(commit, commitargs, commitres),
};
-struct rpc_stat nfs_rpcstat = {
- NULL, /* next */
- &proc_nfsclnt, /* /proc/net directory entry */
- &nfs_program, /* RPC program */
+struct rpc_version nfs_version3 = {
+ 3,
+ sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
+ nfs3_procedures
};
+
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index a592608be..b632cf175 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -61,8 +61,12 @@
* Martin Mares : Use root_server_addr appropriately during setup.
* Martin Mares : Rewrote parameter parsing, now hopefully giving
* correct overriding.
+ * Trond Myklebust : Add in preliminary support for NFSv3 and TCP.
+ * Fix bug in root_nfs_addr(). nfs_data.namlen
+ * is NOT for the length of the hostname.
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -147,6 +151,12 @@ static struct nfs_bool_opts {
{ "noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC },
{ "lock", ~NFS_MOUNT_NONLM, 0 },
{ "nolock", ~NFS_MOUNT_NONLM, NFS_MOUNT_NONLM },
+#ifdef CONFIG_NFS_V3
+ { "v2", ~NFS_MOUNT_VER3, 0 },
+ { "v3", ~NFS_MOUNT_VER3, NFS_MOUNT_VER3 },
+#endif
+ { "udp", ~NFS_MOUNT_TCP, 0 },
+ { "tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP },
{ NULL, 0, 0 }
};
@@ -271,7 +281,6 @@ static int __init root_nfs_addr(void)
}
strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1);
- nfs_data.namlen = strlen(nfs_data.hostname);
return 0;
}
@@ -360,14 +369,14 @@ set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port)
/*
* Query server portmapper for the port of a daemon program.
*/
-static int __init root_nfs_getport(int program, int version)
+static int __init root_nfs_getport(int program, int version, int proto)
{
struct sockaddr_in sin;
printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n",
program, version, in_ntoa(servaddr));
set_sockaddr(&sin, servaddr, 0);
- return rpc_getport_external(&sin, program, version, IPPROTO_UDP);
+ return rpc_getport_external(&sin, program, version, proto);
}
@@ -379,22 +388,39 @@ static int __init root_nfs_getport(int program, int version)
static int __init root_nfs_ports(void)
{
int port;
+ int nfsd_ver, mountd_ver;
+ int nfsd_port, mountd_port;
+ int proto;
+
+ if (nfs_data.flags & NFS_MOUNT_VER3) {
+ nfsd_ver = NFS3_VERSION;
+ mountd_ver = NFS_MNT3_VERSION;
+ nfsd_port = NFS_PORT;
+ mountd_port = NFS_MNT_PORT;
+ } else {
+ nfsd_ver = NFS2_VERSION;
+ mountd_ver = NFS_MNT_VERSION;
+ nfsd_port = NFS_PORT;
+ mountd_port = NFS_MNT_PORT;
+ }
+
+ proto = (nfs_data.flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
if (nfs_port < 0) {
- if ((port = root_nfs_getport(NFS_PROGRAM, NFS_VERSION)) < 0) {
+ if ((port = root_nfs_getport(NFS_PROGRAM, nfsd_ver, proto)) < 0) {
printk(KERN_ERR "Root-NFS: Unable to get nfsd port "
"number from server, using default\n");
- port = NFS_PORT;
+ port = nfsd_port;
}
nfs_port = htons(port);
dprintk("Root-NFS: Portmapper on server returned %d "
"as nfsd port\n", port);
}
- if ((port = root_nfs_getport(NFS_MNT_PROGRAM, NFS_MNT_VERSION)) < 0) {
+ if ((port = root_nfs_getport(NFS_MNT_PROGRAM, nfsd_ver, proto)) < 0) {
printk(KERN_ERR "Root-NFS: Unable to get mountd port "
"number from server, using default\n");
- port = NFS_MNT_PORT;
+ port = mountd_port;
}
mount_port = htons(port);
dprintk("Root-NFS: mountd port is %d\n", port);
@@ -413,7 +439,10 @@ static int __init root_nfs_get_handle(void)
int status;
set_sockaddr(&sin, servaddr, mount_port);
- status = nfs_mount(&sin, nfs_path, &nfs_data.root);
+ if (nfs_data.flags & NFS_MOUNT_VER3)
+ status = nfs3_mount(&sin, nfs_path, &nfs_data.root);
+ else
+ status = nfs_mount(&sin, nfs_path, &nfs_data.root);
if (status < 0)
printk(KERN_ERR "Root-NFS: Server returned error %d "
"while mounting %s\n", status, nfs_path);
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 3823c3118..d6d532217 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -13,10 +13,6 @@
* Note: Error returns are optimized for NFS_OK, which isn't translated via
* nfs_stat_to_errno(), but happens to be already the right return code.
*
- * FixMe: We ought to define a sensible small max size for
- * things like getattr that are tiny packets and use the
- * old get_free_page stuff with it.
- *
* Also, the code currently doesn't check the size of the packet, when
* it decodes the packet.
*
@@ -25,209 +21,357 @@
* Completely rewritten to support the new RPC call interface;
* rewrote and moved the entire XDR stuff to xdr.c
* --Olaf Kirch June 1996
+ *
+ * The code below initializes all auto variables explicitly, otherwise
+ * it will fail to work as a module (gcc generates a memset call for an
+ * incomplete struct).
*/
-#define NFS_NEED_XDR_TYPES
-
+#include <linux/types.h>
#include <linux/param.h>
+#include <linux/malloc.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
#include <linux/utsname.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/in.h>
#include <linux/pagemap.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
#include <asm/segment.h>
-#ifdef NFS_DEBUG
-# define NFSDBG_FACILITY NFSDBG_PROC
-#endif
+#define NFSDBG_FACILITY NFSDBG_PROC
+
+/*
+ * Bare-bones access to getattr: this is for nfs_read_super.
+ */
+static int
+nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ int status;
+ dprintk("NFS call getroot\n");
+ fattr->valid = 0;
+ status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
+ dprintk("NFS reply getroot\n");
+ return status;
+}
/*
* One function for each procedure in the NFS protocol.
*/
-int
-nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+static int
+nfs_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
{
int status;
dprintk("NFS call getattr\n");
- status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR,
+ NFS_FH(dentry), fattr, 0);
dprintk("NFS reply getattr\n");
return status;
}
-int
-nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr, struct iattr *sattr)
+static int
+nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+ struct iattr *sattr)
{
- struct nfs_sattrargs arg = { fhandle, sattr };
+ struct nfs_sattrargs arg = { NFS_FH(dentry), sattr };
int status;
dprintk("NFS call setattr\n");
- status = rpc_call(server->client, NFSPROC_SETATTR, &arg, fattr, 0);
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0);
dprintk("NFS reply setattr\n");
return status;
}
-int
-nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_lookup(struct dentry *dir, struct qstr *name,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
- struct nfs_diropargs arg = { dir, name };
+ struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len };
struct nfs_diropok res = { fhandle, fattr };
int status;
- dprintk("NFS call lookup %s\n", name);
- status = rpc_call(server->client, NFSPROC_LOOKUP, &arg, &res, 0);
+ dprintk("NFS call lookup %s\n", name->name);
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0);
dprintk("NFS reply lookup: %d\n", status);
return status;
}
-int
-nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, int swap,
- unsigned long offset, unsigned int count,
- void *buffer, struct nfs_fattr *fattr)
+static int
+nfs_proc_readlink(struct dentry *dentry, void *buffer, unsigned int bufsiz)
{
- struct nfs_readargs arg = { fhandle, offset, count, buffer };
- struct nfs_readres res = { fattr, count };
+ struct nfs_readlinkargs args = { NFS_FH(dentry), buffer, bufsiz };
+ struct nfs_readlinkres res = { buffer, bufsiz };
int status;
- dprintk("NFS call read %d @ %ld\n", count, offset);
- status = rpc_call(server->client, NFSPROC_READ, &arg, &res,
- swap? NFS_RPC_SWAPFLAGS : 0);
- dprintk("NFS reply read: %d\n", status);
+ dprintk("NFS call readlink\n");
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
+ &args, &res, 0);
+ dprintk("NFS reply readlink: %d\n", status);
return status;
}
-int
-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)
+static int
+nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+ loff_t offset, unsigned int count, void *buffer, int *eofp)
{
- 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};
+ struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1,
+ {{ buffer, count }, {0,0}, {0,0}, {0,0},
+ {0,0}, {0,0}, {0,0}, {0,0}} };
+ struct nfs_readres res = { fattr, count, 0};
+ struct rpc_message msg = { NFSPROC_READ, &arg, &res, NULL };
int status;
- dprintk("NFS call write %d @ %ld\n", count, offset);
- status = rpc_call(server->client, NFSPROC_WRITE, &arg, &res,
- swap? (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) : 0);
+ dprintk("NFS call read %d @ %Ld\n", count, (long long)offset);
+ fattr->valid = 0;
+ status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+
dprintk("NFS reply read: %d\n", status);
+ *eofp = res.eof;
+ return status;
+}
+
+static int
+nfs_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int how,
+ loff_t offset, unsigned int count,
+ void *buffer, struct nfs_writeverf *verf)
+{
+ struct nfs_writeargs arg = {NFS_FH(dentry), offset, count,
+ NFS_FILE_SYNC, 1,
+ {{buffer, count}, {0,0}, {0,0}, {0,0},
+ {0,0}, {0,0}, {0,0}, {0,0}}};
+ struct nfs_writeres res = {fattr, verf, count};
+ struct rpc_message msg = { NFSPROC_WRITE, &arg, &res, NULL };
+ int status, flags = 0;
+
+ dprintk("NFS call write %d @ %Ld\n", count, (long long)offset);
+ fattr->valid = 0;
+ if (how & NFS_RW_SWAP)
+ flags |= NFS_RPC_SWAPFLAGS;
+ status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+
+ dprintk("NFS reply write: %d\n", status);
+ verf->committed = NFS_FILE_SYNC; /* NFSv2 always syncs data */
return status < 0? status : count;
}
-int
-nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct iattr *sattr,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+ int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
- struct nfs_createargs arg = { dir, name, sattr };
+ struct nfs_createargs arg = { NFS_FH(dir), name->name,
+ name->len, sattr };
struct nfs_diropok res = { fhandle, fattr };
int status;
- dprintk("NFS call create %s\n", name);
- status = rpc_call(server->client, NFSPROC_CREATE, &arg, &res, 0);
+ fattr->valid = 0;
+ dprintk("NFS call create %s\n", name->name);
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
dprintk("NFS reply create: %d\n", status);
return status;
}
-int
-nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+/*
+ * In NFSv2, mknod is grafted onto the create call.
+ */
+static int
+nfs_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+ dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
- struct nfs_diropargs arg = { dir, name };
+ struct nfs_createargs arg = { NFS_FH(dir), name->name,
+ name->len, sattr };
+ struct nfs_diropok res = { fhandle, fattr };
+ int status, mode;
+
+ dprintk("NFS call mknod %s\n", name->name);
+
+ mode = sattr->ia_mode;
+ if (S_ISFIFO(mode)) {
+ sattr->ia_mode = (mode & ~S_IFMT) | S_IFCHR;
+ sattr->ia_valid &= ~ATTR_SIZE;
+ } else if (S_ISCHR(rdev) || S_ISBLK(rdev)) {
+ sattr->ia_valid |= ATTR_SIZE;
+ sattr->ia_size = rdev; /* get out your barf bag */
+ }
+
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+
+ if (status == -EINVAL && S_ISFIFO(mode)) {
+ sattr->ia_mode = mode;
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+ }
+ dprintk("NFS reply mknod: %d\n", status);
+ return status;
+}
+
+static int
+nfs_proc_remove(struct dentry *dir, struct qstr *name)
+{
+ struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len };
+ struct rpc_message msg = { NFSPROC_REMOVE, &arg, NULL, NULL };
int status;
- dprintk("NFS call remove %s\n", name);
- status = rpc_call(server->client, NFSPROC_REMOVE, &arg, NULL, 0);
+ dprintk("NFS call remove %s\n", name->name);
+ status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+
dprintk("NFS reply remove: %d\n", status);
return status;
}
-int
-nfs_proc_rename(struct nfs_server *server,
- struct nfs_fh *old_dir, const char *old_name,
- struct nfs_fh *new_dir, const char *new_name)
+static int
+nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name,
+ struct dentry *new_dir, struct qstr *new_name)
{
- struct nfs_renameargs arg = { old_dir, old_name, new_dir, new_name };
+ struct nfs_renameargs arg = { NFS_FH(old_dir), old_name->name,
+ old_name->len,
+ NFS_FH(new_dir), new_name->name,
+ new_name->len};
int status;
- dprintk("NFS call rename %s -> %s\n", old_name, new_name);
- status = rpc_call(server->client, NFSPROC_RENAME, &arg, NULL, 0);
+ dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name);
+ status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0);
dprintk("NFS reply rename: %d\n", status);
return status;
}
-int
-nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fh *dir, const char *name)
+static int
+nfs_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name)
{
- struct nfs_linkargs arg = { fhandle, dir, name };
+ struct nfs_linkargs arg = { NFS_FH(dentry), NFS_FH(dir),
+ name->name, name->len };
int status;
- dprintk("NFS call link %s\n", name);
- status = rpc_call(server->client, NFSPROC_LINK, &arg, NULL, 0);
+ dprintk("NFS call link %s\n", name->name);
+ status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0);
dprintk("NFS reply link: %d\n", status);
return status;
}
-int
-nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, const char *path,
- struct iattr *sattr)
+static int
+nfs_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
+ struct iattr *sattr, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
{
- struct nfs_symlinkargs arg = { dir, name, path, sattr };
+ struct nfs_symlinkargs arg = { NFS_FH(dir), name->name, name->len,
+ path->name, path->len, sattr };
int status;
- dprintk("NFS call symlink %s -> %s\n", name, path);
- status = rpc_call(server->client, NFSPROC_SYMLINK, &arg, NULL, 0);
+ dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0);
dprintk("NFS reply symlink: %d\n", status);
return status;
}
-int
-nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct iattr *sattr,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
- struct nfs_createargs arg = { dir, name, sattr };
+ struct nfs_createargs arg = { NFS_FH(dir), name->name, name->len,
+ sattr };
struct nfs_diropok res = { fhandle, fattr };
int status;
- dprintk("NFS call mkdir %s\n", name);
- status = rpc_call(server->client, NFSPROC_MKDIR, &arg, &res, 0);
+ dprintk("NFS call mkdir %s\n", name->name);
+ fattr->valid = 0;
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
-int
-nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+static int
+nfs_proc_rmdir(struct dentry *dir, struct qstr *name)
{
- struct nfs_diropargs arg = { dir, name };
+ struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len };
int status;
- dprintk("NFS call rmdir %s\n", name);
- status = rpc_call(server->client, NFSPROC_RMDIR, &arg, NULL, 0);
+ dprintk("NFS call rmdir %s\n", name->name);
+ status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0);
dprintk("NFS reply rmdir: %d\n", status);
return status;
}
-int
+/*
+ * The READDIR implementation is somewhat hackish - we pass a temporary
+ * buffer to the encode function, which installs it in the receive
+ * the receive iovec. The decode function just parses the reply to make
+ * sure it is syntactically correct; the entries itself are decoded
+ * from nfs_readdir by calling the decode_entry function directly.
+ */
+static int
+nfs_proc_readdir(struct dentry *dir, __u64 cookie, void *entry,
+ unsigned int size, int plus)
+{
+ struct nfs_readdirargs arg;
+ struct nfs_readdirres res;
+ struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, NULL };
+ struct nfs_server *server = NFS_DSERVER(dir);
+ int status;
+
+ if (server->rsize < size)
+ size = server->rsize;
+
+ arg.fh = NFS_FH(dir);
+ arg.cookie = cookie;
+ arg.buffer = entry;
+ arg.bufsiz = size;
+ res.buffer = entry;
+ res.bufsiz = size;
+
+ dprintk("NFS call readdir %d\n", (unsigned int)cookie);
+ status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+
+ dprintk("NFS reply readdir: %d\n", status);
+ return status;
+}
+
+static int
nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
int status;
dprintk("NFS call statfs\n");
+ memset((char *)info, 0, sizeof(*info));
status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0);
dprintk("NFS reply statfs: %d\n", status);
return status;
}
+
+extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
+
+struct nfs_rpc_ops nfs_v2_clientops = {
+ 2, /* protocol version */
+ nfs_proc_get_root,
+ nfs_proc_getattr,
+ nfs_proc_setattr,
+ nfs_proc_lookup,
+ NULL, /* access */
+ nfs_proc_readlink,
+ nfs_proc_read,
+ nfs_proc_write,
+ NULL, /* commit */
+ nfs_proc_create,
+ nfs_proc_remove,
+ nfs_proc_rename,
+ nfs_proc_link,
+ nfs_proc_symlink,
+ nfs_proc_mkdir,
+ nfs_proc_rmdir,
+ nfs_proc_readdir,
+ nfs_proc_mknod,
+ nfs_proc_statfs,
+ nfs_decode_dirent,
+};
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index aa17780e5..4cf51ec8d 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -15,7 +15,6 @@
* within the RPC code when root squashing is suspected.
*/
-#define NFS_NEED_XDR_TYPES
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -52,14 +51,18 @@ struct nfs_rreq {
*/
static inline void
nfs_readreq_setup(struct nfs_rreq *req, struct nfs_fh *fh,
- unsigned long offset, void *buffer, unsigned int rsize)
+ loff_t offset, void *buffer, unsigned int rsize)
{
req->ra_args.fh = fh;
req->ra_args.offset = offset;
req->ra_args.count = rsize;
- req->ra_args.buffer = buffer;
+ req->ra_args.iov[0].iov_base = (void *)buffer;
+ req->ra_args.iov[0].iov_len = rsize;
+ req->ra_args.nriov = 1;
+ req->ra_fattr.valid = 0;
req->ra_res.fattr = &req->ra_fattr;
req->ra_res.count = rsize;
+ req->ra_res.eof = 0;
}
@@ -70,11 +73,12 @@ static int
nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
{
struct nfs_rreq rqst;
- unsigned long offset = page->index << PAGE_CACHE_SHIFT;
+ struct rpc_message msg;
+ loff_t offset = page_offset(page);
char *buffer;
int rsize = NFS_SERVER(inode)->rsize;
int result, refresh = 0;
- int count = PAGE_SIZE;
+ int count = PAGE_CACHE_SIZE;
int flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
dprintk("NFS: nfs_readpage_sync(%p)\n", page);
@@ -89,16 +93,21 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
if (count < rsize)
rsize = count;
- dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n",
+ dprintk("NFS: nfs_proc_read(%s, (%s/%s), %Ld, %d, %p)\n",
NFS_SERVER(inode)->hostname,
dentry->d_parent->d_name.name, dentry->d_name.name,
- offset, rsize, buffer);
+ (long long)offset, rsize, buffer);
/* Set up arguments and perform rpc call */
nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize);
lock_kernel();
- result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ, &rqst.ra_args, &rqst.ra_res, flags);
+ msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
+ msg.rpc_argp = &rqst.ra_args;
+ msg.rpc_resp = &rqst.ra_res;
+ msg.rpc_cred = NULL;
+ result = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
unlock_kernel();
+ nfs_refresh_inode(inode, &rqst.ra_fattr);
/*
* Even if we had a partial success we can't mark the page
@@ -124,9 +133,6 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
io_error:
kunmap(page);
UnlockPage(page);
- /* Note: we don't refresh if the call returned error */
- if (refresh && result >= 0)
- nfs_refresh_inode(inode, &rqst.ra_fattr);
return result;
}
@@ -139,19 +145,18 @@ nfs_readpage_result(struct rpc_task *task)
{
struct nfs_rreq *req = (struct nfs_rreq *) task->tk_calldata;
struct page *page = req->ra_page;
- unsigned long address = page_address(page);
+ char *address = req->ra_args.iov[0].iov_base;
int result = task->tk_status;
static int succ = 0, fail = 0;
- dprintk("NFS: %4d received callback for page %lx, result %d\n",
+ dprintk("NFS: %4d received callback for page %p, result %d\n",
task->tk_pid, address, result);
+ nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
if (result >= 0) {
result = req->ra_res.count;
- if (result < PAGE_SIZE) {
- memset((char *) address + result, 0, PAGE_SIZE - result);
- }
- nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
+ if (result < PAGE_CACHE_SIZE)
+ memset(address + result, 0, PAGE_CACHE_SIZE - result);
SetPageUptodate(page);
succ++;
} else {
@@ -161,9 +166,8 @@ nfs_readpage_result(struct rpc_task *task)
}
kunmap(page);
UnlockPage(page);
- __free_page(page);
+ page_cache_release(page);
- rpc_release_task(task);
kfree(req);
}
@@ -189,15 +193,15 @@ nfs_readpage_async(struct dentry *dentry, struct inode *inode,
address = kmap(page);
/* Initialize request */
/* N.B. Will the dentry remain valid for life of request? */
- nfs_readreq_setup(req, NFS_FH(dentry), page->index << PAGE_CACHE_SHIFT,
- (void *) address, PAGE_SIZE);
+ nfs_readreq_setup(req, NFS_FH(dentry), page_offset(page),
+ (void *) address, PAGE_CACHE_SIZE);
req->ra_inode = inode;
req->ra_page = page; /* count has been incremented by caller */
/* Start the async call */
dprintk("NFS: executing async READ request.\n");
- msg.rpc_proc = NFSPROC_READ;
+ msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
msg.rpc_argp = &req->ra_args;
msg.rpc_resp = &req->ra_res;
msg.rpc_cred = NULL;
@@ -225,7 +229,7 @@ out_free:
* We read the page synchronously in the following cases:
* - The file is a swap file. Swap-ins are always sync operations,
* so there's no need bothering to make async reads 100% fail-safe.
- * - The NFS rsize is smaller than PAGE_SIZE. We could kludge our way
+ * - The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way
* around this by creating several consecutive read requests, but
* that's hardly worth it.
* - The error flag is set for this page. This happens only when a
@@ -240,7 +244,7 @@ nfs_readpage(struct dentry *dentry, struct page *page)
lock_kernel();
dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
- page, PAGE_SIZE, page->index);
+ page, PAGE_CACHE_SIZE, page->index);
get_page(page);
/*
@@ -256,7 +260,7 @@ nfs_readpage(struct dentry *dentry, struct page *page)
error = -1;
if (!IS_SWAPFILE(inode) && !PageError(page) &&
- NFS_SERVER(inode)->rsize >= PAGE_SIZE)
+ NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
error = nfs_readpage_async(dentry, inode, page);
if (error >= 0)
goto out;
@@ -269,7 +273,7 @@ nfs_readpage(struct dentry *dentry, struct page *page)
out_error:
UnlockPage(page);
out_free:
- __free_page(page);
+ page_cache_release(page);
out:
unlock_kernel();
return error;
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 9f5a95ff9..6b4a94f44 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -14,8 +14,9 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/sunrpc/clnt.h>
-#include <linux/nfs_fs.h>
#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs_fs.h>
#include <linux/pagemap.h>
#include <linux/stat.h>
#include <linux/mm.h>
@@ -27,16 +28,17 @@
*/
static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
{
- struct nfs_readlinkargs rl_args;
- kmap(page);
+ struct inode *inode = dentry->d_inode;
+ void *buffer = (void *)kmap(page);
+ int error;
+
/* We place the length at the beginning of the page,
* in host byte order, followed by the string. The
* XDR response verification will NULL terminate it.
*/
- rl_args.fh = NFS_FH(dentry);
- rl_args.buffer = (const void *)page_address(page);
- if (rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
- &rl_args, NULL, 0) < 0)
+ error = NFS_PROTO(inode)->readlink(dentry, buffer,
+ PAGE_CACHE_SIZE - sizeof(u32)-4);
+ if (error < 0)
goto error;
SetPageUptodate(page);
kunmap(page);
@@ -85,12 +87,10 @@ static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
return res;
}
-static struct dentry *
-nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
+static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct page *page = NULL;
- struct dentry *res = vfs_follow_link(dentry, base, follow,
- nfs_getlink(dentry, &page));
+ int res = vfs_follow_link(nd, nfs_getlink(dentry,&page));
if (page) {
kunmap(page);
page_cache_release(page);
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index af023a121..651251548 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -55,6 +55,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
#include <linux/nfs_flushd.h>
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
@@ -160,7 +161,6 @@ static __inline__ void nfs_writedata_free(struct nfs_write_data *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);
}
@@ -172,6 +172,12 @@ static void nfs_writedata_release(struct rpc_task *task)
static __inline__ int
nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
{
+ if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) {
+ fattr->pre_size = NFS_CACHE_ISIZE(inode);
+ fattr->pre_mtime = NFS_CACHE_MTIME(inode);
+ fattr->pre_ctime = NFS_CACHE_CTIME(inode);
+ fattr->valid |= NFS_ATTR_WCC;
+ }
return nfs_refresh_inode(inode, fattr);
}
@@ -183,10 +189,12 @@ static int
nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
struct page *page, unsigned long offset, unsigned int count)
{
+ loff_t base;
unsigned int wsize = NFS_SERVER(inode)->wsize;
- int result, refresh = 0, written = 0;
+ int result, refresh = 0, written = 0, flags;
u8 *buffer;
struct nfs_fattr fattr;
+ struct nfs_writeverf verf;
lock_kernel();
dprintk("NFS: nfs_writepage_sync(%s/%s %d@%lu/%ld)\n",
@@ -194,15 +202,17 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
count, page->index, offset);
buffer = (u8 *) kmap(page) + offset;
- offset += page->index << PAGE_CACHE_SHIFT;
+ base = page_offset(page) + offset;
+
+ flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
do {
if (count < wsize && !IS_SWAPFILE(inode))
wsize = count;
- result = nfs_proc_write(NFS_DSERVER(dentry), NFS_FH(dentry),
- IS_SWAPFILE(inode), offset, wsize,
- buffer, &fattr);
+ result = NFS_PROTO(inode)->write(dentry, &fattr, flags,
+ base, wsize, buffer, &verf);
+ nfs_write_attributes(inode, &fattr);
if (result < 0) {
/* Must mark the page invalid after I/O error */
@@ -214,41 +224,19 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
wsize, result);
refresh = 1;
buffer += wsize;
- offset += wsize;
+ base += wsize;
written += wsize;
count -= wsize;
/*
* If we've extended the file, update the inode
* now so we don't invalidate the cache.
*/
- if (offset > inode->i_size)
- inode->i_size = offset;
+ if (base > inode->i_size)
+ inode->i_size = base;
} while (count);
io_error:
kunmap(page);
- /* Note: we don't refresh if the call failed (fattr invalid) */
- if (refresh && result >= 0) {
- /* See comments in nfs_wback_result */
- /* N.B. I don't think this is right -- sync writes in order */
- if (fattr.size < inode->i_size)
- fattr.size = inode->i_size;
- if (fattr.mtime.seconds < inode->i_mtime)
- printk("nfs_writepage_sync: prior time??\n");
- /* Solaris 2.5 server seems to send garbled
- * fattrs occasionally */
- if (inode->i_ino == fattr.fileid) {
- /*
- * We expect the mtime value to change, and
- * don't want to invalidate the caches.
- */
- inode->i_mtime = fattr.mtime.seconds;
- nfs_refresh_inode(inode, &fattr);
- }
- else
- printk("nfs_writepage_sync: inode %ld, got %u?\n",
- inode->i_ino, fattr.fileid);
- }
unlock_kernel();
return written? written : result;
@@ -290,7 +278,7 @@ static int
region_locked(struct inode *inode, struct nfs_page *req)
{
struct file_lock *fl;
- unsigned long rqstart, rqend;
+ loff_t rqstart, rqend;
/* Don't optimize writes if we don't use NLM */
if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
@@ -665,20 +653,18 @@ nfs_wait_on_request(struct nfs_page *req)
* 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)
+nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
{
struct list_head *p, *head;
- unsigned long idx_start, idx_end;
- unsigned int pages = 0;
+ unsigned long idx_end;
+ unsigned int res = 0;
int error;
- idx_start = start >> PAGE_CACHE_SHIFT;
- if (count == 0)
+ if (npages == 0)
idx_end = ~0;
- else {
- unsigned long idx_count = (count-1) >> PAGE_CACHE_SHIFT;
- idx_end = idx_start + idx_count;
- }
+ else
+ idx_end = idx_start + npages - 1;
+
spin_lock(&nfs_wreq_lock);
head = &inode->u.nfs_i.writeback;
p = head->next;
@@ -705,10 +691,10 @@ nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long start
return error;
spin_lock(&nfs_wreq_lock);
p = head->next;
- pages++;
+ res++;
}
spin_unlock(&nfs_wreq_lock);
- return pages;
+ return res;
}
/*
@@ -769,19 +755,18 @@ nfs_scan_commit_timeout(struct inode *inode, struct list_head *dst)
#endif
static int
-nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
{
struct list_head *p;
struct nfs_page *req;
- unsigned long idx_start, idx_end;
- int pages;
+ unsigned long idx_end;
+ int res;
- pages = 0;
- idx_start = start >> PAGE_CACHE_SHIFT;
- if (count == 0)
+ res = 0;
+ if (npages == 0)
idx_end = ~0;
else
- idx_end = idx_start + ((count-1) >> PAGE_CACHE_SHIFT);
+ idx_end = idx_start + npages - 1;
p = src->next;
while (p != src) {
unsigned long pg_idx;
@@ -800,36 +785,36 @@ nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, u
continue;
nfs_list_remove_request(req);
nfs_list_add_request(req, dst);
- pages++;
+ res++;
}
- return pages;
+ return res;
}
static int
-nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long start, unsigned int count)
+nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
{
- int pages;
+ int res;
spin_lock(&nfs_wreq_lock);
- pages = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, start, count);
- inode->u.nfs_i.ndirty -= pages;
+ res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, idx_start, npages);
+ inode->u.nfs_i.ndirty -= res;
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;
+ return res;
}
#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)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
{
- int pages;
+ int res;
spin_lock(&nfs_wreq_lock);
- pages = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, start, count);
- inode->u.nfs_i.ncommit -= pages;
+ res = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, idx_start, npages);
+ inode->u.nfs_i.ncommit -= res;
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;
+ return res;
}
#endif
@@ -1038,7 +1023,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page_offset(page) +offset);
+ count, (long long)(page_offset(page) +offset));
/*
* If wsize is smaller than page size, update and write
@@ -1071,7 +1056,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
if (synchronous) {
int error;
- error = nfs_sync_file(inode, file, page_offset(page) + offset, count, FLUSH_SYNC|FLUSH_STABLE);
+ error = nfs_sync_file(inode, file, page_index(page), 1, FLUSH_SYNC|FLUSH_STABLE);
if (error < 0 || (error = file->f_error) < 0)
status = error;
file->f_error = 0;
@@ -1086,7 +1071,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
nfs_release_request(req);
done:
dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n",
- status, inode->i_size);
+ status, (long long)inode->i_size);
if (status < 0)
clear_bit(PG_uptodate, &page->flags);
return status;
@@ -1173,6 +1158,8 @@ nfs_flush_one(struct list_head *head, struct file *file, int how)
/* Finalize the task. */
rpc_init_task(task, clnt, nfs_writeback_done, flags);
task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_writedata_release;
#ifdef CONFIG_NFS_V3
msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE;
@@ -1266,22 +1253,25 @@ nfs_writeback_done(struct rpc_task *task)
/* We tried a write call, but the server did not
* commit data to stable storage even though we
* requested it.
+ * Note: There is a known bug in Tru64 < 5.0 in which
+ * the server reports NFS_DATA_SYNC, but performs
+ * NFS_FILE_SYNC. We therefore implement this checking
+ * as a dprintk() in order to avoid filling syslog.
*/
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);
+ dprintk("NFS: faulty NFSv3 server %s:"
+ " (committed = %d) != (stable = %d)\n",
+ NFS_SERVER(inode)->hostname,
+ resp->verf->committed, argp->stable);
complain = jiffies + 300 * HZ;
}
}
#endif
/* Update attributes as result of writeback. */
- if (task->tk_status >= 0)
- nfs_write_attributes(inode, resp->fattr);
+ nfs_write_attributes(inode, resp->fattr);
while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next);
@@ -1293,7 +1283,7 @@ nfs_writeback_done(struct rpc_task *task)
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);
+ (long long)(page_offset(req->wb_page) + req->wb_offset));
if (task->tk_status < 0) {
req->wb_file->f_error = task->tk_status;
@@ -1318,7 +1308,6 @@ nfs_writeback_done(struct rpc_task *task)
next:
nfs_unlock_request(req);
}
- nfs_writedata_release(task);
}
@@ -1332,7 +1321,7 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
struct nfs_page *req;
struct dentry *dentry;
struct inode *inode;
- unsigned long start, end, len;
+ loff_t start, end, len;
/* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */
@@ -1346,7 +1335,7 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
inode = dentry->d_inode;
while (!list_empty(head)) {
struct nfs_page *req;
- unsigned long rqstart, rqend;
+ loff_t rqstart, rqend;
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
@@ -1360,6 +1349,7 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
data->args.fh = NFS_FH(dentry);
data->args.offset = start;
len = end - start;
+ /* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */
if (end >= inode->i_size || len > (~((u32)0) >> 1))
len = 0;
data->res.count = data->args.count = (u32)len;
@@ -1399,6 +1389,8 @@ nfs_commit_list(struct list_head *head, int how)
rpc_init_task(task, clnt, nfs_commit_done, flags);
task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_writedata_release;
msg.rpc_proc = NFS3PROC_COMMIT;
msg.rpc_argp = &data->args;
@@ -1441,11 +1433,11 @@ nfs_commit_done(struct rpc_task *task)
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
- dprintk("NFS: commit (%s/%s %d@%ld)",
+ 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);
+ (long long)(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);
@@ -1467,23 +1459,22 @@ nfs_commit_done(struct rpc_task *task)
next:
nfs_unlock_request(req);
}
- nfs_writedata_release(task);
}
#endif
-int nfs_flush_file(struct inode *inode, struct file *file, unsigned long start,
- unsigned int count, int how)
+int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start,
+ unsigned int npages, int how)
{
LIST_HEAD(head);
- int pages,
+ int res,
error = 0;
- pages = nfs_scan_dirty(inode, &head, file, start, count);
- if (pages)
+ res = nfs_scan_dirty(inode, &head, file, idx_start, npages);
+ if (res)
error = nfs_flush_list(inode, &head, how);
if (error < 0)
return error;
- return pages;
+ return res;
}
int nfs_flush_timeout(struct inode *inode, int how)
@@ -1501,19 +1492,19 @@ int nfs_flush_timeout(struct inode *inode, int how)
}
#ifdef CONFIG_NFS_V3
-int nfs_commit_file(struct inode *inode, struct file *file, unsigned long start,
- unsigned int count, int how)
+int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,
+ unsigned int npages, int how)
{
LIST_HEAD(head);
- int pages,
+ int res,
error = 0;
- pages = nfs_scan_commit(inode, &head, file, start, count);
- if (pages)
+ res = nfs_scan_commit(inode, &head, file, idx_start, npages);
+ if (res)
error = nfs_commit_list(&head, how);
if (error < 0)
return error;
- return pages;
+ return res;
}
int nfs_commit_timeout(struct inode *inode, int how)
@@ -1533,8 +1524,8 @@ int nfs_commit_timeout(struct inode *inode, int how)
}
#endif
-int nfs_sync_file(struct inode *inode, struct file *file, unsigned long start,
- unsigned int count, int how)
+int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start,
+ unsigned int npages, int how)
{
int error,
wait;
@@ -1548,12 +1539,12 @@ int nfs_sync_file(struct inode *inode, struct file *file, unsigned long start,
do {
error = 0;
if (wait)
- error = nfs_wait_on_requests(inode, file, start, count);
+ error = nfs_wait_on_requests(inode, file, idx_start, npages);
if (error == 0)
- error = nfs_flush_file(inode, file, start, count, how);
+ error = nfs_flush_file(inode, file, idx_start, npages, how);
#ifdef CONFIG_NFS_V3
if (error == 0)
- error = nfs_commit_file(inode, file, start, count, how);
+ error = nfs_commit_file(inode, file, idx_start, npages, how);
#endif
} while (error > 0);
return error;
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c6ea9074c..53bfa0bea 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -246,14 +246,11 @@ exp_export(struct nfsctl_export *nxp)
/* Look up the dentry */
err = -EINVAL;
- dentry = lookup_dentry(nxp->ex_path, NULL, 0);
+ dentry = lookup_dentry(nxp->ex_path, LOOKUP_POSITIVE);
if (IS_ERR(dentry))
goto out_unlock;
- err = -ENOENT;
inode = dentry->d_inode;
- if (!inode)
- goto finish;
err = -EINVAL;
if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
@@ -443,7 +440,7 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
err = -EPERM;
if (path) {
- if (!(dentry = lookup_dentry(path, NULL, 0))) {
+ if (!(dentry = lookup_dentry(path, 0))) {
printk("nfsd: exp_rootfh path not found %s", path);
return -EPERM;
}
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index c45d494ba..e15483e43 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -27,7 +27,8 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file *filp)
/* must initialize before using! but maxsize doesn't matter */
fh_init(&fh,0);
- memcpy((char*)&fh.fh_handle.fh_base, (char*)f, NFS_FHSIZE);
+ fh.fh_handle.fh_size = f->size;
+ memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size);
fh.fh_export = NULL;
nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 969ff54a9..61ee94a3e 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -74,22 +74,11 @@ decode_fh(u32 *p, struct svc_fh *fhp)
static inline u32 *
encode_fh(u32 *p, struct svc_fh *fhp)
{
-#if 0
int size = fhp->fh_handle.fh_size;
*p++ = htonl(size);
if (size) p[XDR_QUADLEN(size)-1]=0;
memcpy(p, &fhp->fh_handle.fh_base, size);
return p + XDR_QUADLEN(size);
-#else
- /* until locked knows about var-length file handles,
- * we always return NFS_FHSIZE handles
- */
- int size = fhp->fh_handle.fh_size;
- *p++ = htonl(NFS_FHSIZE);
- memset(p, 0, NFS_FHSIZE);
- memcpy(p, &fhp->fh_handle.fh_base, size);
- return p + XDR_QUADLEN(NFS_FHSIZE);
-#endif
}
/*
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 97b46f0c7..65c70164a 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -130,7 +130,6 @@ 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;
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 5cd55fda8..56da94aea 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -91,7 +91,8 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
int len, struct svc_fh *resfh)
{
struct svc_export *exp;
- struct dentry *dparent, *dchild;
+ struct dentry *dparent;
+ struct nameidata nd;
int err;
dprintk("nfsd: nfsd_lookup(fh %s, %s)\n", SVCFH_fmt(fhp), name);
@@ -116,49 +117,51 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
/* checking mountpoint crossing is very different when stepping up */
if (dparent == exp->ex_dentry) {
if (!EX_CROSSMNT(exp))
- dchild = dget(dparent); /* .. == . just like at / */
+ nd.dentry = dget(dparent); /* .. == . just like at / */
else
{
struct svc_export *exp2 = NULL;
struct dentry *dp;
- dchild = dparent->d_covers->d_parent;
- for (dp=dchild;
+ nd.dentry = dparent->d_covers->d_parent;
+ for (dp=nd.dentry;
exp2 == NULL && dp->d_covers->d_parent != dp;
dp=dp->d_covers->d_parent)
exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
- if (exp2==NULL || dchild->d_sb != exp2->ex_dentry->d_sb) {
- dchild = dget(dparent);
+ if (exp2==NULL || nd.dentry->d_sb != exp2->ex_dentry->d_sb) {
+ nd.dentry = dget(dparent);
} else {
- dget(dchild);
+ dget(nd.dentry);
exp = exp2;
}
}
} else
- dchild = dget(dparent->d_parent);
+ nd.dentry = dget(dparent->d_parent);
} else {
- dchild = lookup_dentry(name, dget(dparent), 0);
- if (IS_ERR(dchild))
+ nd.mnt = NULL;
+ nd.dentry = dget(dparent);
+ err = walk_name(name, 0, &nd);
+ if (err)
goto out_nfserr;
/*
* check if we have crossed a mount point ...
*/
- if (dchild->d_sb != dparent->d_sb) {
+ if (nd.dentry->d_sb != dparent->d_sb) {
struct svc_export *exp2 = NULL;
exp2 = exp_get(rqstp->rq_client,
- dchild->d_inode->i_dev,
- dchild->d_inode->i_ino);
+ nd.dentry->d_inode->i_dev,
+ nd.dentry->d_inode->i_ino);
if (exp2 && EX_CROSSMNT(exp2))
/* successfully crossed mount point */
exp = exp2;
- else if (dchild->d_covers->d_sb == dparent->d_sb) {
+ else if (nd.dentry->d_covers->d_sb == dparent->d_sb) {
/* stay in the original filesystem */
- struct dentry *tdentry = dget(dchild->d_covers);
- dput(dchild);
- dchild = tdentry;
+ struct dentry *tdentry = dget(nd.dentry->d_covers);
+ dput(nd.dentry);
+ nd.dentry = tdentry;
} else {
/* This cannot possibly happen */
- printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, dchild->d_name.name);
- dput(dchild);
+ printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, nd.dentry->d_name.name);
+ dput(nd.dentry);
err = nfserr_acces;
goto out;
@@ -169,14 +172,14 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
* Note: we compose the file handle now, but as the
* dentry may be negative, it may need to be updated.
*/
- err = fh_compose(resfh, exp, dchild);
- if (!err && !dchild->d_inode)
+ err = fh_compose(resfh, exp, nd.dentry);
+ if (!err && !nd.dentry->d_inode)
err = nfserr_noent;
out:
return err;
out_nfserr:
- err = nfserrno(PTR_ERR(dchild));
+ err = nfserrno(err);
goto out;
}
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index f06e122aa..6ec49bfd7 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -3,7 +3,7 @@
O_TARGET := ntfs.o
O_OBJS := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o
M_OBJS := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"990411\"
+EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000410\"
include $(TOPDIR)/Rules.make
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index e6abd178e..058e3a6f4 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -1,7 +1,8 @@
/*
* fs.c
- * NTFS driver for Linux 2.1
+ * NTFS driver for Linux 2.3.x
*
+ * Copyright (C) 2000, Anton Altaparmakov
* Copyright (C) 1995-1997, 1999 Martin von Löwis
* Copyright (C) 1996 Richard Russon
* Copyright (C) 1996-1997 Régis Duchesne
@@ -53,7 +54,6 @@ static void ntfs_getuser_update_vm (void *dest, ntfs_io *src, ntfs_size_t len)
{
struct ntfs_getuser_update_vm_s *p = src->param;
copy_from_user (dest, p->user, len);
- update_vm_cache (p->ino, p->off, dest, len);
p->user += len;
p->off += len;
}
diff --git a/fs/open.c b/fs/open.c
index 44202fe4e..4a56314a7 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -141,11 +141,8 @@ static inline long do_sys_ftruncate(unsigned int fd, loff_t length)
file = fget(fd);
if (!file)
goto out;
- error = -ENOENT;
- if (!(dentry = file->f_dentry))
- goto out_putf;
- if (!(inode = dentry->d_inode))
- goto out_putf;
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
error = -EACCES;
if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
goto out_putf;
@@ -330,35 +327,41 @@ asmlinkage long sys_access(const char * filename, int mode)
return res;
}
+/* MOUNT_REWRITE: pass &mnt to lookup_dentry */
asmlinkage long sys_chdir(const char * filename)
{
int error;
- struct inode *inode;
struct dentry *dentry, *tmp;
+ struct vfsmount *mnt = NULL, *tmp_mnt;
+ char *name;
lock_kernel();
- dentry = namei(filename);
+ name = getname(filename);
+ error = PTR_ERR(name);
+ if (IS_ERR(name))
+ goto out;
+
+ dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY);
+ putname(name);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out;
- inode = dentry->d_inode;
-
- error = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
- goto dput_and_out;
-
- error = permission(inode,MAY_EXEC);
+ error = permission(dentry->d_inode,MAY_EXEC);
if (error)
goto dput_and_out;
/* exchange dentries */
tmp = current->fs->pwd;
+ tmp_mnt = current->fs->pwdmnt;
current->fs->pwd = dentry;
+ current->fs->pwdmnt = mnt;
dentry = tmp;
+ mnt = tmp_mnt;
dput_and_out:
+ mntput(mnt);
dput(dentry);
out:
unlock_kernel();
@@ -370,6 +373,7 @@ asmlinkage long sys_fchdir(unsigned int fd)
struct file *file;
struct dentry *dentry;
struct inode *inode;
+ struct vfsmount *mnt;
int error;
error = -EBADF;
@@ -377,11 +381,9 @@ asmlinkage long sys_fchdir(unsigned int fd)
if (!file)
goto out;
- error = -ENOENT;
- if (!(dentry = file->f_dentry))
- goto out_putf;
- if (!(inode = dentry->d_inode))
- goto out_putf;
+ dentry = file->f_dentry;
+ mnt = file->f_vfsmnt;
+ inode = dentry->d_inode;
error = -ENOTDIR;
if (!S_ISDIR(inode->i_mode))
@@ -391,7 +393,10 @@ asmlinkage long sys_fchdir(unsigned int fd)
error = permission(inode, MAY_EXEC);
if (!error) {
struct dentry *tmp = current->fs->pwd;
+ struct vfsmount *tmp_mnt = current->fs->pwdmnt;
current->fs->pwd = dget(dentry);
+ current->fs->pwdmnt = mntget(mnt);
+ mntput(tmp_mnt);
dput(tmp);
}
unlock_kernel();
@@ -401,26 +406,28 @@ out:
return error;
}
+/* MOUNT_REWRITE: pass &mnt to lookup_dentry */
asmlinkage long sys_chroot(const char * filename)
{
int error;
- struct inode *inode;
struct dentry *dentry, *tmp;
+ struct vfsmount *mnt = NULL, *tmp_mnt;
+ char *name;
lock_kernel();
- dentry = namei(filename);
+ name = getname(filename);
+ error = PTR_ERR(name);
+ if (IS_ERR(name))
+ goto out;
+
+ dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY);
+ putname(name);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out;
- inode = dentry->d_inode;
-
- error = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
- goto dput_and_out;
-
- error = permission(inode,MAY_EXEC);
+ error = permission(dentry->d_inode,MAY_EXEC);
if (error)
goto dput_and_out;
@@ -430,11 +437,15 @@ asmlinkage long sys_chroot(const char * filename)
/* exchange dentries */
tmp = current->fs->root;
+ tmp_mnt = current->fs->rootmnt;
current->fs->root = dentry;
+ current->fs->rootmnt = mnt;
dentry = tmp;
+ mnt = tmp_mnt;
error = 0;
dput_and_out:
+ mntput(mnt);
dput(dentry);
out:
unlock_kernel();
@@ -453,11 +464,8 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
if (!file)
goto out;
- err = -ENOENT;
- if (!(dentry = file->f_dentry))
- goto out_putf;
- if (!(inode = dentry->d_inode))
- goto out_putf;
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
err = -EROFS;
if (IS_RDONLY(inode))
@@ -612,20 +620,16 @@ asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group)
asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
{
- struct dentry * dentry;
struct file * file;
int error = -EBADF;
file = fget(fd);
if (!file)
goto out;
- error = -ENOENT;
lock_kernel();
- if ((dentry = file->f_dentry) != NULL)
- error = chown_common(dentry, user, group);
+ error = chown_common(file->f_dentry, user, group);
unlock_kernel();
fput(file);
-
out:
return error;
}
@@ -644,26 +648,25 @@ out:
* for the internal routines (ie open_namei()/follow_link() etc). 00 is
* used by symlinks.
*/
-struct file *filp_open(const char * filename, int flags, int mode, struct dentry * base)
+struct file *filp_open(const char * filename, int flags, int mode)
{
- struct dentry * dentry;
- int flag,error;
+ int namei_flags, error;
+ struct nameidata nd;
- flag = flags;
- if ((flag+1) & O_ACCMODE)
- flag++;
- if (flag & O_TRUNC)
- flag |= 2;
+ namei_flags = flags;
+ if ((namei_flags+1) & O_ACCMODE)
+ namei_flags++;
+ if (namei_flags & O_TRUNC)
+ namei_flags |= 2;
- dentry = __open_namei(filename, flag, mode, base);
- error = PTR_ERR(dentry);
- if (!IS_ERR(dentry))
- return dentry_open(dentry, flags);
+ error = open_namei(filename, namei_flags, mode, &nd);
+ if (!error)
+ return dentry_open(nd.dentry, nd.mnt, flags);
return ERR_PTR(error);
}
-struct file *dentry_open(struct dentry *dentry, int flags)
+struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
{
struct file * f;
struct inode *inode;
@@ -679,15 +682,14 @@ struct file *dentry_open(struct dentry *dentry, int flags)
if (f->f_mode & FMODE_WRITE) {
error = get_write_access(inode);
if (error)
- goto cleanup_dentry;
+ goto cleanup_file;
}
f->f_dentry = dentry;
+ f->f_vfsmnt = mnt;
f->f_pos = 0;
f->f_reada = 0;
- f->f_op = NULL;
- if (inode->i_op)
- f->f_op = inode->i_fop;
+ f->f_op = inode->i_fop;
if (inode->i_sb)
file_move(f, &inode->i_sb->s_files);
if (f->f_op && f->f_op->open) {
@@ -703,9 +705,12 @@ cleanup_all:
if (f->f_mode & FMODE_WRITE)
put_write_access(inode);
f->f_dentry = NULL;
+ f->f_vfsmnt = NULL;
+cleanup_file:
+ put_filp(f);
cleanup_dentry:
dput(dentry);
- put_filp(f);
+ mntput(mnt);
return ERR_PTR(error);
}
@@ -795,7 +800,7 @@ asmlinkage long sys_open(const char * filename, int flags, int mode)
if (fd >= 0) {
struct file * f;
lock_kernel();
- f = filp_open(tmp, flags, mode, NULL);
+ f = filp_open(tmp, flags, mode);
unlock_kernel();
error = PTR_ERR(f);
if (IS_ERR(f))
@@ -833,7 +838,6 @@ asmlinkage long sys_creat(const char * pathname, int mode)
int filp_close(struct file *filp, fl_owner_t id)
{
int retval;
- struct dentry *dentry = filp->f_dentry;
if (!file_count(filp)) {
printk("VFS: Close: file count is 0\n");
@@ -842,8 +846,7 @@ int filp_close(struct file *filp, fl_owner_t id)
retval = 0;
if (filp->f_op && filp->f_op->flush)
retval = filp->f_op->flush(filp);
- if (dentry->d_inode)
- locks_remove_posix(filp, id);
+ locks_remove_posix(filp, id);
fput(filp);
return retval;
}
diff --git a/fs/partitions/Config.in b/fs/partitions/Config.in
index a0a58e3dd..c7a39b9f4 100644
--- a/fs/partitions/Config.in
+++ b/fs/partitions/Config.in
@@ -21,8 +21,8 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then
bool ' Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
bool ' Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
fi
- bool 'SGI partition support' CONFIG_SGI_PARTITION
- bool 'Ultrix partition table support' CONFIG_ULTRIX_PARTITION
+ bool ' SGI partition support' CONFIG_SGI_PARTITION
+ bool ' Ultrix partition table support' CONFIG_ULTRIX_PARTITION
bool 'Sun partition tables support' CONFIG_SUN_PARTITION
else
if [ "$ARCH" = "alpha" ]; then
@@ -36,6 +36,9 @@ else
if [ "$CONFIG_AMIGA" = "y" ]; then
define_bool CONFIG_AMIGA_PARTITION y
fi
+ if [ "$CONFIG_MAC" = "y" ]; then
+ define_bool CONFIG_MAC_PARTITION y
+ fi
if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
define_bool CONFIG_ACORN_PARTITION y
define_bool CONFIG_ACORN_PARTITION_ADFS y
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 54e594634..63a1d5828 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -574,7 +574,9 @@ ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char *
if (map->vm_file != NULL) {
dev = map->vm_file->f_dentry->d_inode->i_dev;
ino = map->vm_file->f_dentry->d_inode->i_ino;
- line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+ line = d_path(map->vm_file->f_dentry,
+ map->vm_file->f_vfsmnt,
+ buffer, PAGE_SIZE);
buffer[PAGE_SIZE-1] = '\n';
line -= maxlen;
if(line < buffer)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 4a191bfef..63bd4459b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -38,22 +38,28 @@ int proc_pid_status(struct task_struct*,char*);
int proc_pid_statm(struct task_struct*,char*);
int proc_pid_cpu(struct task_struct*,char*);
-static struct dentry *proc_fd_link(struct inode *inode)
+/* MOUNT_REWRITE: make all files have non-NULL ->f_vfsmnt (pipefs, sockfs) */
+static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
{
- if (inode->u.proc_i.file)
- return dget(inode->u.proc_i.file->f_dentry);
- return NULL;
+ if (inode->u.proc_i.file) {
+ if (inode->u.proc_i.file->f_vfsmnt) {
+ *mnt = mntget(inode->u.proc_i.file->f_vfsmnt);
+ }
+ *dentry = dget(inode->u.proc_i.file->f_dentry);
+ return 0;
+ }
+ return -ENOENT;
}
-static struct dentry *proc_exe_link(struct inode *inode)
+static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
{
struct mm_struct * mm;
struct vm_area_struct * vma;
- struct dentry *result = NULL;
+ int result = -ENOENT;
struct task_struct *task = inode->u.proc_i.task;
if (!task_lock(task))
- return NULL;
+ return result;
mm = task->mm;
if (!mm)
goto out;
@@ -62,7 +68,9 @@ static struct dentry *proc_exe_link(struct inode *inode)
while (vma) {
if ((vma->vm_flags & VM_EXECUTABLE) &&
vma->vm_file) {
- result = dget(vma->vm_file->f_dentry);
+ *mnt = mntget(vma->vm_file->f_vfsmnt);
+ *dentry = dget(vma->vm_file->f_dentry);
+ result = 0;
break;
}
vma = vma->vm_next;
@@ -73,25 +81,31 @@ out:
return result;
}
-static struct dentry *proc_cwd_link(struct inode *inode)
+static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
{
- struct dentry *result = NULL;
+ int result = -ENOENT;
if (task_lock(inode->u.proc_i.task)) {
struct fs_struct *fs = inode->u.proc_i.task->fs;
- if (fs)
- result = dget(fs->pwd);
+ if (fs) {
+ *mnt = mntget(fs->pwdmnt);
+ *dentry = dget(fs->pwd);
+ result = 0;
+ }
task_unlock(inode->u.proc_i.task);
}
return result;
}
-static struct dentry *proc_root_link(struct inode *inode)
+static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
{
- struct dentry *result = NULL;
+ int result = -ENOENT;
if (task_lock(inode->u.proc_i.task)) {
struct fs_struct *fs = inode->u.proc_i.task->fs;
- if (fs)
- result = dget(fs->root);
+ if (fs) {
+ *mnt = mntget(fs->rootmnt);
+ *dentry = dget(fs->root);
+ result = 0;
+ }
task_unlock(inode->u.proc_i.task);
}
return result;
@@ -160,16 +174,18 @@ static int proc_permission(struct inode *inode, int mask)
{
struct dentry *de, *base, *root;
struct super_block *our_sb, *sb, *below;
+ struct vfsmount *our_vfsmnt, *vfsmnt, *mnt;
if (standard_permission(inode, mask) != 0)
return -EACCES;
base = current->fs->root;
- de = root = proc_root_link(inode); /* Ewww... */
-
- if (!de)
+ our_vfsmnt = current->fs->rootmnt;
+ if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
return -ENOENT;
+ de = root;
+ mnt = vfsmnt;
our_sb = base->d_inode->i_sb;
sb = de->d_inode->i_sb;
while (sb != our_sb) {
@@ -184,9 +200,11 @@ static int proc_permission(struct inode *inode, int mask)
goto out;
dput(root);
+ mntput(mnt);
return 0;
out:
dput(root);
+ mntput(mnt);
return -EACCES;
}
@@ -345,30 +363,26 @@ static struct inode_operations proc_mem_inode_operations = {
permission: proc_permission,
};
-static struct dentry * proc_pid_follow_link(struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
+static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
- struct dentry * result;
int error;
/* We don't need a base pointer in the /proc filesystem */
- dput(base);
+ dput(nd->dentry);
+ mntput(nd->mnt);
error = proc_permission(inode, MAY_EXEC);
- result = ERR_PTR(error);
if (error)
goto out;
- result = inode->u.proc_i.op.proc_get_link(inode);
+ error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
out:
- if (!result)
- result = ERR_PTR(-ENOENT);
- return result;
+ return error;
}
-static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
+static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt,
+ char * buffer, int buflen)
{
struct inode * inode;
char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
@@ -391,7 +405,7 @@ static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
len = sprintf(tmp, pattern, inode->i_ino);
path = tmp;
} else {
- path = d_path(dentry, tmp, PAGE_SIZE);
+ path = d_path(dentry, mnt, tmp, PAGE_SIZE);
len = tmp + PAGE_SIZE - 1 - path;
}
@@ -406,22 +420,19 @@ static int proc_pid_readlink(struct dentry * dentry, char * buffer, int buflen)
{
int error;
struct inode *inode = dentry->d_inode;
+ struct vfsmount *mnt;
error = proc_permission(inode, MAY_EXEC);
if (error)
goto out;
- dentry = inode->u.proc_i.op.proc_get_link(inode);
- error = -ENOENT;
- if (!dentry)
- goto out;
-
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ error = inode->u.proc_i.op.proc_get_link(inode, &dentry, &mnt);
+ if (error)
goto out;
- error = do_proc_readlink(dentry, buffer, buflen);
+ error = do_proc_readlink(dentry, mnt, buffer, buflen);
dput(dentry);
+ mntput(mnt);
out:
return error;
}
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 28e0c08e5..4d6662780 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -201,10 +201,10 @@ static int proc_readlink(struct dentry *dentry, char *buffer, int buflen)
return vfs_readlink(dentry, buffer, buflen, s);
}
-static struct dentry *proc_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
{
char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
- return vfs_follow_link(dentry, base, flags, s);
+ return vfs_follow_link(nd, s);
}
static struct inode_operations proc_link_inode_operations = {
diff --git a/fs/proc/root.c b/fs/proc/root.c
index cce48d845..af01f0281 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -32,13 +32,11 @@ static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen)
return vfs_readlink(dentry,buffer,buflen,tmp);
}
-static struct dentry * proc_self_follow_link(struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
+static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
{
char tmp[30];
sprintf(tmp, "%d", current->pid);
- return vfs_follow_link(dentry,base,follow,tmp);
+ return vfs_follow_link(nd,tmp);
}
static struct inode_operations proc_self_inode_operations = {
diff --git a/fs/ramfs/.cvsignore b/fs/ramfs/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/fs/ramfs/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/fs/ramfs/Makefile b/fs/ramfs/Makefile
new file mode 100644
index 000000000..f57d5966c
--- /dev/null
+++ b/fs/ramfs/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux ramfs routines.
+#
+
+O_TARGET := ramfs.o
+
+O_OBJS := inode.o
+
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
new file mode 100644
index 000000000..e218051f3
--- /dev/null
+++ b/fs/ramfs/inode.c
@@ -0,0 +1,393 @@
+/*
+ * Resizable simple ram filesystem for Linux.
+ *
+ * Copyright (C) 2000 Linus Torvalds.
+ * 2000 Transmeta Corp.
+ *
+ * This file is released under the GPL.
+ */
+
+/*
+ * NOTE! This filesystem is probably most useful
+ * not as a real filesystem, but as an example of
+ * how virtual filesystems can be written.
+ *
+ * It doesn't get much simpler than this. Consider
+ * that this file implements the full semantics of
+ * a POSIX-compliant read-write filesystem.
+ *
+ * Note in particular how the filesystem does not
+ * need to implement any data structures of its own
+ * to keep track of the virtual data: using the VFS
+ * caches is sufficient.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/uaccess.h>
+
+/* some random number */
+#define RAMFS_MAGIC 0x858458f6
+
+static struct super_operations ramfs_ops;
+static struct address_space_operations ramfs_aops;
+static struct file_operations ramfs_dir_operations;
+static struct file_operations ramfs_file_operations;
+static struct inode_operations ramfs_dir_inode_operations;
+
+static int ramfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ buf->f_type = RAMFS_MAGIC;
+ buf->f_bsize = PAGE_CACHE_SIZE;
+ buf->f_namelen = 255;
+ return 0;
+}
+
+/*
+ * Lookup the data. This is trivial - if the dentry didn't already
+ * exist, we know it is negative.
+ */
+static struct dentry * ramfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+ d_add(dentry, NULL);
+ return NULL;
+}
+
+/*
+ * Read a page. Again trivial. If it didn't already exist
+ * in the page cache, it is zero-filled.
+ */
+static int ramfs_readpage(struct dentry *dentry, struct page * page)
+{
+ if (!Page_Uptodate(page)) {
+ memset((void *) page_address(page), 0, PAGE_CACHE_SIZE);
+ SetPageUptodate(page);
+ }
+ UnlockPage(page);
+ return 0;
+}
+
+/*
+ * Writing: just make sure the page gets marked dirty, so that
+ * the page stealer won't grab it.
+ */
+static int ramfs_writepage(struct dentry * dentry, struct page *page)
+{
+ SetPageDirty(page);
+ return 0;
+}
+
+static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+ void *addr;
+
+ addr = (void *) kmap(page);
+ if (!Page_Uptodate(page)) {
+ memset(addr, 0, PAGE_CACHE_SIZE);
+ SetPageUptodate(page);
+ }
+ SetPageDirty(page);
+ return 0;
+}
+
+static int ramfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+ struct inode *inode = (struct inode*)page->mapping->host;
+ loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+
+ kunmap(page);
+ if (pos > inode->i_size)
+ inode->i_size = pos;
+ return 0;
+}
+
+struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev)
+{
+ struct inode * inode = get_empty_inode();
+
+ if (inode) {
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_size = 0;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_rdev = dev;
+ inode->i_nlink = 1;
+ inode->i_op = NULL;
+ inode->i_fop = NULL;
+ inode->i_mapping->a_ops = &ramfs_aops;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+ default:
+ init_special_inode(inode, mode, dev);
+ break;
+ case S_IFREG:
+ inode->i_fop = &ramfs_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &ramfs_dir_inode_operations;
+ inode->i_fop = &ramfs_dir_operations;
+ break;
+ case S_IFLNK:
+ inode->i_op = &page_symlink_inode_operations;
+ break;
+ }
+ }
+ return inode;
+}
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
+{
+ struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev);
+ int error = -ENOSPC;
+
+ if (inode) {
+ d_instantiate(dentry, inode);
+ dget(dentry); /* Extra count - pin the dentry in core */
+ error = 0;
+ }
+ return error;
+}
+
+static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+ return ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+}
+
+static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+ return ramfs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+/*
+ * Link a file..
+ */
+static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
+{
+ struct inode *inode = old_dentry->d_inode;
+
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
+
+ inode->i_nlink++;
+ inode->i_count++; /* New dentry reference */
+ dget(dentry); /* Extra pinning count for the created dentry */
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+static inline int ramfs_positive(struct dentry *dentry)
+{
+ return dentry->d_inode && !d_unhashed(dentry);
+}
+
+/*
+ * Check that a directory is empty (this works
+ * for regular files too, they'll just always be
+ * considered empty..).
+ *
+ * Note that an empty directory can still have
+ * children, they just all have to be negative..
+ */
+static int ramfs_empty(struct dentry *dentry)
+{
+ struct list_head *list = dentry->d_subdirs.next;
+
+ while (list != &dentry->d_subdirs) {
+ struct dentry *de = list_entry(list, struct dentry, d_child);
+
+ if (ramfs_positive(de))
+ return 0;
+ list = list->next;
+ }
+ return 1;
+}
+
+/*
+ * This works for both directories and regular files.
+ * (non-directories will always have empty subdirs)
+ */
+static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
+{
+ int retval = -ENOTEMPTY;
+
+ if (ramfs_empty(dentry)) {
+ struct inode *inode = dentry->d_inode;
+
+ inode->i_nlink--;
+ dput(dentry); /* Undo the count from "create" - this does all the work */
+ d_delete(dentry);
+ retval = 0;
+ }
+ return retval;
+}
+
+#define ramfs_rmdir ramfs_unlink
+
+/*
+ * The VFS layer already does all the dentry stuff for rename,
+ * we just have to decrement the usage count for the target if
+ * it exists so that the VFS layer correctly free's it when it
+ * gets overwritten.
+ */
+static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
+{
+ int error = -ENOTEMPTY;
+
+ if (ramfs_empty(new_dentry)) {
+ struct inode *inode = new_dentry->d_inode;
+ if (inode) {
+ inode->i_nlink--;
+ dput(new_dentry);
+ }
+ error = 0;
+ }
+ return error;
+}
+
+static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
+{
+ int error;
+
+ error = ramfs_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);
+ if (!error) {
+ int l = strlen(symname)+1;
+ struct inode *inode = dentry->d_inode;
+ error = block_symlink(inode, symname, l);
+ }
+ return error;
+}
+
+/*
+ * This really should be the same as the proc filldir,
+ * once proc does the "one dentry tree" thing..
+ */
+static int ramfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+ int i;
+ struct dentry *dentry = filp->f_dentry;
+
+ i = filp->f_pos;
+ switch (i) {
+ case 0:
+ if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino) < 0)
+ break;
+ i++;
+ filp->f_pos++;
+ /* fallthrough */
+ case 1:
+ if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino) < 0)
+ break;
+ i++;
+ filp->f_pos++;
+ /* fallthrough */
+ default: {
+ struct list_head *list = dentry->d_subdirs.next;
+
+ int j = i-2;
+ for (;;) {
+ if (list == &dentry->d_subdirs)
+ return 0;
+ if (!j)
+ break;
+ j--;
+ list = list->next;
+ }
+
+ do {
+ struct dentry *de = list_entry(list, struct dentry, d_child);
+
+ if (ramfs_positive(de)) {
+ if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0)
+ break;
+ }
+ filp->f_pos++;
+ list = list->next;
+ } while (list != &dentry->d_subdirs);
+ }
+ }
+ return 0;
+}
+
+static struct address_space_operations ramfs_aops = {
+ readpage: ramfs_readpage,
+ writepage: ramfs_writepage,
+ prepare_write: ramfs_prepare_write,
+ commit_write: ramfs_commit_write
+};
+
+static struct file_operations ramfs_file_operations = {
+ read: generic_file_read,
+ write: generic_file_write,
+ mmap: generic_file_mmap
+};
+
+static struct file_operations ramfs_dir_operations = {
+ read: generic_read_dir,
+ readdir: ramfs_readdir,
+};
+
+static struct inode_operations ramfs_dir_inode_operations = {
+ create: ramfs_create,
+ lookup: ramfs_lookup,
+ link: ramfs_link,
+ unlink: ramfs_unlink,
+ symlink: ramfs_symlink,
+ mkdir: ramfs_mkdir,
+ rmdir: ramfs_rmdir,
+ mknod: ramfs_mknod,
+ rename: ramfs_rename,
+};
+
+
+static struct super_operations ramfs_ops = {
+ statfs: ramfs_statfs,
+};
+
+static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent)
+{
+ struct inode * inode;
+ struct dentry * root;
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = RAMFS_MAGIC;
+ sb->s_op = &ramfs_ops;
+ inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
+ if (!inode)
+ return NULL;
+
+ root = d_alloc_root(inode);
+ if (!root) {
+ iput(inode);
+ return NULL;
+ }
+ sb->s_root = root;
+ return sb;
+}
+
+static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, 0);
+
+static int __init init_ramfs_fs(void)
+{
+ return register_filesystem(&ramfs_fs_type);
+}
+
+static void __exit exit_ramfs_fs(void)
+{
+ unregister_filesystem(&ramfs_fs_type);
+}
+
+module_init(init_ramfs_fs)
+module_exit(exit_ramfs_fs)
diff --git a/fs/read_write.c b/fs/read_write.c
index e82aaea96..4569ee18a 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -64,17 +64,11 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
off_t retval;
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
retval = -EBADF;
file = fget(fd);
if (!file)
goto bad;
- /* N.B. Shouldn't this be ENOENT?? */
- if (!(dentry = file->f_dentry) ||
- !(inode = dentry->d_inode))
- goto out_putf;
retval = -EINVAL;
if (origin <= 2) {
loff_t res = llseek(file, offset, origin);
@@ -82,7 +76,6 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
if (res != (loff_t)retval)
retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
}
-out_putf:
fput(file);
bad:
return retval;
@@ -95,18 +88,12 @@ asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
{
int retval;
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
loff_t offset;
retval = -EBADF;
file = fget(fd);
if (!file)
goto bad;
- /* N.B. Shouldn't this be ENOENT?? */
- if (!(dentry = file->f_dentry) ||
- !(inode = dentry->d_inode))
- goto out_putf;
retval = -EINVAL;
if (origin > 2)
goto out_putf;
diff --git a/fs/super.c b/fs/super.c
index 302487807..c7848eb90 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -91,6 +91,19 @@ static struct file_system_type **find_filesystem(const char *name)
return p;
}
+/**
+ * register_filesystem - register a new filesystem
+ * @fs: the file system structure
+ *
+ * Adds the file system passed to the list of file systems the kernel
+ * is aware of for by mount and other syscalls. Returns 0 on success,
+ * or a negative errno code on an error.
+ *
+ * The file_system_type that is passed is linked into the kernel
+ * structures and must not be freed until the file system has been
+ * unregistered.
+ */
+
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
@@ -110,6 +123,18 @@ int register_filesystem(struct file_system_type * fs)
return res;
}
+/**
+ * unregister_filesystem - unregister a file system
+ * @fs: filesystem to unregister
+ *
+ * Remove a file system that was previously successfully registered
+ * with the kernel. An error is returned if the file system is not found.
+ * Zero is returned on a success.
+ *
+ * Once this function has returned the file_system_type structure may be
+ * freed or reused.
+ */
+
int unregister_filesystem(struct file_system_type * fs)
{
struct file_system_type ** tmp;
@@ -192,7 +217,6 @@ asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
{
int retval = -EINVAL;
- lock_kernel();
switch (option) {
case 1:
retval = fs_index((const char *) arg1);
@@ -206,7 +230,6 @@ asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
retval = fs_maxindex();
break;
}
- unlock_kernel();
return retval;
}
@@ -253,7 +276,7 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb,
const char *dev_name, const char *dir_name)
{
struct vfsmount *lptr;
- char *tmp, *name;
+ char *name;
lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
if (!lptr)
@@ -264,21 +287,19 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb,
lptr->mnt_dev = sb->s_dev;
/* N.B. Is it really OK to have a vfsmount without names? */
- if (dev_name && !IS_ERR(tmp = getname(dev_name))) {
- name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+ if (dev_name) {
+ name = (char *) kmalloc(strlen(dev_name)+1, GFP_KERNEL);
if (name) {
- strcpy(name, tmp);
+ strcpy(name, dev_name);
lptr->mnt_devname = name;
}
- putname(tmp);
}
- if (dir_name && !IS_ERR(tmp = getname(dir_name))) {
- name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+ if (dir_name) {
+ name = (char *) kmalloc(strlen(dir_name)+1, GFP_KERNEL);
if (name) {
- strcpy(name, tmp);
+ strcpy(name, dir_name);
lptr->mnt_dirname = name;
}
- putname(tmp);
}
if (vfsmntlist == (struct vfsmount *)NULL) {
@@ -343,13 +364,16 @@ static struct proc_fs_info {
static struct proc_nfs_info {
int flag;
char *str;
+ char *nostr;
} nfs_info[] = {
- { NFS_MOUNT_SOFT, ",soft" },
- { NFS_MOUNT_INTR, ",intr" },
- { NFS_MOUNT_POSIX, ",posix" },
- { NFS_MOUNT_NOCTO, ",nocto" },
- { NFS_MOUNT_NOAC, ",noac" },
- { 0, NULL }
+ { NFS_MOUNT_SOFT, ",soft", ",hard" },
+ { NFS_MOUNT_INTR, ",intr", "" },
+ { NFS_MOUNT_POSIX, ",posix", "" },
+ { NFS_MOUNT_TCP, ",tcp", ",udp" },
+ { NFS_MOUNT_NOCTO, ",nocto", "" },
+ { NFS_MOUNT_NOAC, ",noac", "" },
+ { NFS_MOUNT_NONLM, ",nolock", ",lock" },
+ { 0, NULL, NULL }
};
int get_filesystem_info( char *buf )
@@ -362,9 +386,10 @@ int get_filesystem_info( char *buf )
char *path,*buffer = (char *) __get_free_page(GFP_KERNEL);
if (!buffer) return 0;
- for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160;
- tmp = tmp->mnt_next) {
- path = d_path(tmp->mnt_sb->s_root, buffer, PAGE_SIZE);
+ for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160; tmp = tmp->mnt_next) {
+ if (!tmp->mnt_sb || !tmp->mnt_sb->s_root)
+ continue;
+ path = d_path(tmp->mnt_sb->s_root, tmp, buffer, PAGE_SIZE);
if (!path)
continue;
len += sprintf( buf + len, "%s %s %s %s",
@@ -379,14 +404,11 @@ int get_filesystem_info( char *buf )
}
if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
- if (nfss->rsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
- len += sprintf(buf+len, ",rsize=%d",
- nfss->rsize);
- }
- if (nfss->wsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
- len += sprintf(buf+len, ",wsize=%d",
- nfss->wsize);
- }
+ len += sprintf(buf+len, ",v%d", nfss->rpc_ops->version);
+
+ len += sprintf(buf+len, ",rsize=%d", nfss->rsize);
+
+ len += sprintf(buf+len, ",wsize=%d", nfss->wsize);
#if 0
if (nfss->timeo != 7*HZ/10) {
len += sprintf(buf+len, ",timeo=%d",
@@ -414,10 +436,13 @@ int get_filesystem_info( char *buf )
nfss->acdirmax/HZ);
}
for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
- if (nfss->flags & nfs_infop->flag) {
- strcpy(buf + len, nfs_infop->str);
- len += strlen(nfs_infop->str);
- }
+ char *str;
+ if (nfss->flags & nfs_infop->flag)
+ str = nfs_infop->str;
+ else
+ str = nfs_infop->nostr;
+ strcpy(buf + len, str);
+ len += strlen(str);
}
len += sprintf(buf+len, ",addr=%s",
nfss->hostname);
@@ -429,6 +454,14 @@ int get_filesystem_info( char *buf )
return len;
}
+/**
+ * __wait_on_super - wait on a superblock
+ * @sb: superblock to wait on
+ *
+ * Waits for a superblock to become unlocked and then returns. It does
+ * not take the lock. This is an internal function. See wait_on_super.
+ */
+
void __wait_on_super(struct super_block * sb)
{
DECLARE_WAITQUEUE(wait, current);
@@ -473,6 +506,14 @@ void sync_supers(kdev_t dev)
}
}
+/**
+ * get_super - get the superblock of a device
+ * @dev: device to get the super block for
+ *
+ * Scans the superblock list and finds the superblock of the file system
+ * mounted on the device given. NULL is returned if no match is found.
+ */
+
struct super_block * get_super(kdev_t dev)
{
struct super_block * s;
@@ -517,9 +558,15 @@ out:
return err;
}
-/*
- * Find a super_block with no device assigned.
+/**
+ * get_empty_super - find empty superblocks
+ *
+ * Find a super_block with no device assigned. A free superblock is
+ * found and returned. If neccessary new superblocks are allocated.
+ * NULL is returned if there are insufficient resources to complete
+ * the request
*/
+
struct super_block *get_empty_super(void)
{
struct super_block *s;
@@ -850,7 +897,7 @@ int fs_may_mount(kdev_t dev)
* Anyone using this new feature must know what he/she is doing.
*/
-int do_mount(struct block_device *bdev, const char *dev_name,
+static int do_mount(struct block_device *bdev, const char *dev_name,
const char *dir_name, const char * type, int flags, void * data)
{
kdev_t dev;
@@ -881,7 +928,7 @@ int do_mount(struct block_device *bdev, const char *dev_name,
/*
* Do the lookup first to force automounting.
*/
- dir_d = namei(dir_name);
+ dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
error = PTR_ERR(dir_d);
if (IS_ERR(dir_d))
goto out;
@@ -981,11 +1028,10 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
/*
- * Invalidate the inodes, as some mount options may be changed.
- * N.B. If we are changing media, we should check the return
- * from invalidate_inodes ... can't allow _any_ open files.
+ * We can't invalidate inodes as we can loose data when remounting
+ * (someone might manage to alter data while we are waiting in lock_super()
+ * or in foo_remount_fs()))
*/
- invalidate_inodes(sb);
return 0;
}
@@ -995,11 +1041,10 @@ static int do_remount(const char *dir,int flags,char *data)
struct dentry *dentry;
int retval;
- dentry = namei(dir);
+ dentry = lookup_dentry(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
retval = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
struct super_block * sb = dentry->d_inode->i_sb;
-
retval = -ENODEV;
if (sb) {
retval = -EINVAL;
@@ -1062,8 +1107,8 @@ static int copy_mount_options (const void * data, unsigned long *where)
* aren't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
*/
-long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
- unsigned long new_flags, unsigned long data_page)
+long do_sys_mount(char * dev_name, char * dir_name, char *type_page,
+ unsigned long new_flags, void *data_page)
{
struct file_system_type * fstype;
struct dentry * dentry = NULL;
@@ -1071,6 +1116,15 @@ long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
struct block_device *bdev = NULL;
int retval;
unsigned long flags = 0;
+
+ /* Basic sanity checks */
+
+ if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
+ return -EINVAL;
+ if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
+ return -EINVAL;
+ if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
+ return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -1083,7 +1137,7 @@ long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
goto out;
}
- fstype = get_fs_type((char *) type_page);
+ fstype = get_fs_type(type_page);
retval = -ENODEV;
if (!fstype)
goto out;
@@ -1091,7 +1145,10 @@ long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
if (fstype->fs_flags & FS_REQUIRES_DEV) {
struct block_device_operations *bdops;
- dentry = namei(dev_name);
+ retval = -EINVAL;
+ if (!dev_name || !*dev_name)
+ goto fs_out;
+ dentry = lookup_dentry(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
retval = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto fs_out;
@@ -1114,7 +1171,7 @@ long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
flags = new_flags & ~MS_MGC_MSK;
retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags,
- (void *) data_page);
+ data_page);
dput_and_out:
dput(dentry);
@@ -1130,6 +1187,8 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
int retval;
unsigned long data_page = 0;
unsigned long type_page = 0;
+ unsigned long dev_page = 0;
+ char *dir_page;
lock_kernel();
retval = copy_mount_options (type, &type_page);
@@ -1146,12 +1205,24 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
goto out;
}
+ dir_page = getname(dir_name);
+ retval = PTR_ERR(dir_page);
+ if (IS_ERR(dir_page))
+ goto out1;
+
+ retval = copy_mount_options (dev_name, &dev_page);
+ if (retval < 0)
+ goto out2;
retval = copy_mount_options (data, &data_page);
if (retval >= 0) {
- retval = do_sys_mount(dev_name, dir_name, type_page,
- new_flags, data_page);
+ retval = do_sys_mount((char*)dev_page,dir_page,(char*)type_page,
+ new_flags, (void*)data_page);
free_page(data_page);
}
+ free_page(dev_page);
+out2:
+ putname(dir_page);
+out1:
free_page(type_page);
out:
unlock_kernel();
@@ -1162,7 +1233,7 @@ void __init mount_root(void)
{
struct file_system_type * fs_type;
struct super_block * sb;
- struct vfsmount *vfsmnt;
+ struct vfsmount *vfsmnt = NULL;
struct block_device *bdev = NULL;
mode_t mode;
int retval;
@@ -1186,7 +1257,9 @@ void __init mount_root(void)
sb->s_dirt = 0;
sb->s_type = fs_type;
current->fs->root = dget(sb->s_root);
+ current->fs->rootmnt = mntget(vfsmnt);
current->fs->pwd = dget(sb->s_root);
+ current->fs->pwdmnt = mntget(vfsmnt);
ROOT_DEV = sb->s_dev;
printk (KERN_NOTICE "VFS: Mounted root (NFS filesystem)%s.\n", (sb->s_flags & MS_RDONLY) ? " readonly" : "");
return;
@@ -1298,7 +1371,9 @@ void __init mount_root(void)
mount_it:
sb->s_flags = root_mountflags;
current->fs->root = dget(sb->s_root);
+ current->fs->rootmnt = mntget(vfsmnt);
current->fs->pwd = dget(sb->s_root);
+ current->fs->pwdmnt = mntget(vfsmnt);
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1321,22 +1396,28 @@ mount_it:
static void chroot_fs_refs(struct dentry *old_root,
- struct dentry *new_root)
+ struct vfsmount *old_rootmnt,
+ struct dentry *new_root,
+ struct vfsmount *new_rootmnt)
{
struct task_struct *p;
read_lock(&tasklist_lock);
for_each_task(p) {
if (!p->fs) continue;
- if (p->fs->root == old_root) {
- dput(old_root);
+ if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) {
p->fs->root = dget(new_root);
+ p->fs->rootmnt = mntget(new_rootmnt);
+ mntput(old_rootmnt);
+ dput(old_root);
printk(KERN_DEBUG "chroot_fs_refs: changed root of "
"process %d\n",p->pid);
}
- if (p->fs->pwd == old_root) {
- dput(old_root);
+ if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt) {
p->fs->pwd = dget(new_root);
+ p->fs->pwdmnt = mntget(new_rootmnt);
+ mntput(old_rootmnt);
+ dput(old_root);
printk(KERN_DEBUG "chroot_fs_refs: changed cwd of "
"process %d\n",p->pid);
}
@@ -1344,7 +1425,6 @@ static void chroot_fs_refs(struct dentry *old_root,
read_unlock(&tasklist_lock);
}
-
/*
* Moves the current root to put_root, and sets root/cwd of all processes
* which had them on the old root to new_root.
@@ -1360,9 +1440,11 @@ static void chroot_fs_refs(struct dentry *old_root,
asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
{
struct dentry *root = current->fs->root;
+ struct vfsmount *root_mnt = current->fs->rootmnt;
struct dentry *d_new_root, *d_put_old, *covered;
struct dentry *root_dev_root, *new_root_dev_root;
struct dentry *walk, *next;
+ struct vfsmount *new_root_mnt = NULL;
int error;
if (!capable(CAP_SYS_ADMIN))
@@ -1414,7 +1496,7 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
root_dev_root = root->d_sb->s_root;
root_dev_root->d_covers = dget(d_put_old);
d_put_old->d_mounts = root_dev_root;
- chroot_fs_refs(root,d_new_root);
+ chroot_fs_refs(root,root_mnt,d_new_root,new_root_mnt);
error = 0;
out2:
up(&mount_sem);
@@ -1444,7 +1526,7 @@ int __init change_root(kdev_t new_root_dev,const char *put_old)
return -EBUSY;
}
/* First unmount devfs if mounted */
- dir_d = lookup_dentry ("/dev", NULL, 1);
+ dir_d = lookup_dentry ("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE);
if (!IS_ERR(dir_d)) {
struct super_block *sb = dir_d->d_inode->i_sb;
@@ -1467,12 +1549,9 @@ int __init change_root(kdev_t new_root_dev,const char *put_old)
/*
* Get the new mount directory
*/
- dir_d = lookup_dentry(put_old, NULL, 1);
+ dir_d = lookup_dentry(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
if (IS_ERR(dir_d)) {
error = PTR_ERR(dir_d);
- } else if (!dir_d->d_inode) {
- dput(dir_d);
- error = -ENOENT;
} else {
error = 0;
}
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 96297521b..cbaf77929 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -315,7 +315,7 @@ static int udf_release_file(struct inode * inode, struct file * filp)
*/
static int udf_open_file(struct inode * inode, struct file * filp)
{
- if ((inode->i_size & 0xFFFFFFFF00000000UL) && !(filp->f_flags & O_LARGEFILE))
+ if ((inode->i_size & 0xFFFFFFFF00000000ULL) && !(filp->f_flags & O_LARGEFILE))
return -EFBIG;
return 0;
}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index ed1507fa7..b0a9c42c0 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -78,7 +78,9 @@ void udf_put_inode(struct inode * inode)
{
lock_kernel();
udf_discard_prealloc(inode);
- write_inode_now(inode);
+ /* write the root inode on put, if dirty */
+ if (!inode->i_sb->s_root && inode->i_state & I_DIRTY)
+ udf_update_inode(inode, IS_SYNC(inode));
unlock_kernel();
}
}
@@ -111,7 +113,7 @@ void udf_delete_inode(struct inode * inode)
inode->i_size = 0;
udf_truncate(inode);
- write_inode_now(inode);
+ udf_update_inode(inode, IS_SYNC(inode));
udf_free_inode(inode);
out:
unlock_kernel();
@@ -1005,10 +1007,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_nlink = 1;
inode->i_size = le64_to_cpu(fe->informationLength);
-#if BITS_PER_LONG < 64
- if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000ULL)
- inode->i_size = (Uint32)-1;
-#endif
inode->i_mode = udf_convert_permissions(fe);
inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
index 4550f44cf..59a44e22e 100644
--- a/fs/ufs/symlink.c
+++ b/fs/ufs/symlink.c
@@ -33,10 +33,10 @@ static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen)
return vfs_readlink(dentry, buffer, buflen, s);
}
-static struct dentry *ufs_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink;
- return vfs_follow_link(dentry, base, flags, s);
+ return vfs_follow_link(nd, s);
}
struct inode_operations ufs_fast_symlink_inode_operations = {
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 18dd76572..29eebb3f2 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -651,9 +651,7 @@ char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
struct dentry * old_root = current->fs->root;
char * path;
- /* N.B. not safe -- fix this soon! */
- current->fs->root = dentry->d_sb->s_root;
- path = d_path(dentry, buffer, len);
+ path = __d_path(dentry, NULL, dentry->d_sb->s_root, NULL, buffer, len);
if (*path == '/')
path++; /* skip leading '/' */
@@ -665,7 +663,6 @@ char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
}
- current->fs->root = old_root;
return path;
}
diff --git a/include/asm-alpha/namei.h b/include/asm-alpha/namei.h
index 644ec0990..5cc9bb394 100644
--- a/include/asm-alpha/namei.h
+++ b/include/asm-alpha/namei.h
@@ -12,7 +12,6 @@
* Look at asm-sparc/namei.h for details.
*/
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif /* __ALPHA_NAMEI_H */
diff --git a/include/asm-arm/arch-arc/system.h b/include/asm-arm/arch-arc/system.h
index 7f204b1f5..31db5f390 100644
--- a/include/asm-arm/arch-arc/system.h
+++ b/include/asm-arm/arch-arc/system.h
@@ -20,7 +20,11 @@
#endif
-#define arch_do_idle() do { } while (0)
+extern __inline__ void arch_idle(void)
+{
+ while (!current->need_resched && !hlt_counter);
+}
+
#define arch_power_off() do { } while (0)
extern __inline__ void arch_reset(char mode)
diff --git a/include/asm-arm/arch-cl7500/system.h b/include/asm-arm/arch-cl7500/system.h
index a8a0ee518..a44cc9373 100644
--- a/include/asm-arm/arch-cl7500/system.h
+++ b/include/asm-arm/arch-cl7500/system.h
@@ -8,8 +8,11 @@
#include <asm/iomd.h>
-#define arch_do_idle() \
- outb(0, IOMD_SUSMODE)
+extern __inline__ void arch_idle(void)
+{
+ while (!current->need_resched && !hlt_counter)
+ outb(0, IOMD_SUSMODE);
+}
#define arch_reset(mode) \
do { \
diff --git a/include/asm-arm/arch-cl7500/vmalloc.h b/include/asm-arm/arch-cl7500/vmalloc.h
new file mode 100644
index 000000000..98f3604dd
--- /dev/null
+++ b/include/asm-arm/arch-cl7500/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-cl7500/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-ebsa110/hardware.h b/include/asm-arm/arch-ebsa110/hardware.h
index 0de487421..c8ebe67c3 100644
--- a/include/asm-arm/arch-ebsa110/hardware.h
+++ b/include/asm-arm/arch-ebsa110/hardware.h
@@ -27,6 +27,7 @@
* RAM definitions
*/
#define FLUSH_BASE_PHYS 0x40000000
+#define UNCACHEABLE_ADDR 0xf3000000
#else /* __ASSEMBLY__ */
diff --git a/include/asm-arm/arch-ebsa110/system.h b/include/asm-arm/arch-ebsa110/system.h
index 2ec712d06..767623096 100644
--- a/include/asm-arm/arch-ebsa110/system.h
+++ b/include/asm-arm/arch-ebsa110/system.h
@@ -6,7 +6,31 @@
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
-#define arch_do_idle() cpu_do_idle()
+/*
+ * This machine must never stop it MCLK. However, if we are
+ * idle for a long time, slow the processor clock to MCLK.
+ */
+extern __inline__ void arch_idle(void)
+{
+ unsigned long start_idle;
+
+ start_idle = jiffies;
+
+ do {
+ if (current->need_resched || hlt_counter)
+ goto slow_out;
+ } while (time_before(start_idle, jiffies + HZ/3));
+
+ cpu_do_idle(IDLE_CLOCK_SLOW);
+
+ while (!current->need_resched && !hlt_counter) {
+ /* do nothing slowly */
+ }
+
+ cpu_do_idle(IDLE_CLOCK_FAST);
+slow_out:
+}
+
#define arch_power_off() do { } while (0)
#define arch_reset(mode) cpu_reset(0x80000000)
diff --git a/include/asm-arm/arch-ebsa110/vmalloc.h b/include/asm-arm/arch-ebsa110/vmalloc.h
new file mode 100644
index 000000000..d9d09f03c
--- /dev/null
+++ b/include/asm-arm/arch-ebsa110/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-ebsa285/hardware.h b/include/asm-arm/arch-ebsa285/hardware.h
index 9aeaf6712..b3c1f2931 100644
--- a/include/asm-arm/arch-ebsa285/hardware.h
+++ b/include/asm-arm/arch-ebsa285/hardware.h
@@ -58,7 +58,7 @@
#define FLASH_BASE 0xf8000000
#define PCIMEM_SIZE 0x01000000
-#define PCIMEM_BASE 0xe0000000
+#define PCIMEM_BASE 0xf0000000
#elif defined(CONFIG_ARCH_CO285)
@@ -105,6 +105,7 @@
#define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET)
#define FLUSH_BASE_PHYS 0x50000000
+#define UNCACHEABLE_ADDR (ARMCSR_BASE + 0x108)
/* PIC irq control */
diff --git a/include/asm-arm/arch-ebsa285/system.h b/include/asm-arm/arch-ebsa285/system.h
index 46e60a084..0e37477b2 100644
--- a/include/asm-arm/arch-ebsa285/system.h
+++ b/include/asm-arm/arch-ebsa285/system.h
@@ -8,7 +8,28 @@
#include <asm/hardware.h>
#include <asm/leds.h>
-#define arch_do_idle() cpu_do_idle()
+extern __inline__ void arch_idle(void)
+{
+ unsigned long start_idle;
+
+ start_idle = jiffies;
+
+ do {
+ if (current->need_resched || hlt_counter)
+ goto slow_out;
+ cpu_do_idle(IDLE_WAIT_FAST);
+ } while (time_before(start_idle, jiffies + HZ/3));
+
+ cpu_do_idle(IDLE_CLOCK_SLOW);
+
+ while (!current->need_resched && !hlt_counter) {
+ cpu_do_idle(IDLE_WAIT_SLOW);
+ }
+
+ cpu_do_idle(IDLE_CLOCK_FAST);
+slow_out:
+}
+
#define arch_power_off() do { } while (0)
extern __inline__ void arch_reset(char mode)
diff --git a/include/asm-arm/arch-ebsa285/vmalloc.h b/include/asm-arm/arch-ebsa285/vmalloc.h
new file mode 100644
index 000000000..63dbeb9af
--- /dev/null
+++ b/include/asm-arm/arch-ebsa285/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END (PAGE_OFFSET + 0x20000000)
diff --git a/include/asm-arm/arch-nexuspci/system.h b/include/asm-arm/arch-nexuspci/system.h
index 3ef541df3..0726698e7 100644
--- a/include/asm-arm/arch-nexuspci/system.h
+++ b/include/asm-arm/arch-nexuspci/system.h
@@ -6,7 +6,12 @@
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
-#define arch_do_idle() cpu_do_idle()
+extern __inline__ void arch_idle(void)
+{
+ while (!current->need_resched && !hlt_counter)
+ cpu_do_idle(IDLE_WAIT_SLOW);
+}
+
#define arch_reset(mode) do { } while (0)
#define arch_power_off() do { } while (0)
diff --git a/include/asm-arm/arch-nexuspci/vmalloc.h b/include/asm-arm/arch-nexuspci/vmalloc.h
new file mode 100644
index 000000000..5c8d17dd7
--- /dev/null
+++ b/include/asm-arm/arch-nexuspci/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-nexuspci/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END (PAGE_OFFSET + 0x20000000)
diff --git a/include/asm-arm/arch-rpc/hardware.h b/include/asm-arm/arch-rpc/hardware.h
index 0ae320b86..80cca92e7 100644
--- a/include/asm-arm/arch-rpc/hardware.h
+++ b/include/asm-arm/arch-rpc/hardware.h
@@ -39,6 +39,7 @@
#define SCREEN1_BASE 0xd0000000
#define FLUSH_BASE 0xdf000000
+#define UNCACHEABLE_ADDR 0xdf010000
#ifndef __ASSEMBLY__
diff --git a/include/asm-arm/arch-rpc/system.h b/include/asm-arm/arch-rpc/system.h
index 1282c9505..135f3892d 100644
--- a/include/asm-arm/arch-rpc/system.h
+++ b/include/asm-arm/arch-rpc/system.h
@@ -7,7 +7,28 @@
#include <asm/iomd.h>
#include <asm/io.h>
-#define arch_do_idle() cpu_do_idle()
+extern __inline__ void arch_idle(void)
+{
+ unsigned long start_idle;
+
+ start_idle = jiffies;
+
+ do {
+ if (current->need_resched || hlt_counter)
+ goto slow_out;
+ cpu_do_idle(IDLE_WAIT_FAST);
+ } while (time_before(start_idle, jiffies + HZ/3));
+
+ cpu_do_idle(IDLE_CLOCK_SLOW);
+
+ while (!current->need_resched && !hlt_counter) {
+ cpu_do_idle(IDLE_WAIT_SLOW);
+ }
+
+ cpu_do_idle(IDLE_CLOCK_FAST);
+slow_out:
+}
+
#define arch_power_off() do { } while (0)
extern __inline__ void arch_reset(char mode)
diff --git a/include/asm-arm/arch-rpc/vmalloc.h b/include/asm-arm/arch-rpc/vmalloc.h
new file mode 100644
index 000000000..828869fc7
--- /dev/null
+++ b/include/asm-arm/arch-rpc/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-rpc/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-sa1100/hardware.h b/include/asm-arm/arch-sa1100/hardware.h
index 86358d96b..e93cbe7d9 100644
--- a/include/asm-arm/arch-sa1100/hardware.h
+++ b/include/asm-arm/arch-sa1100/hardware.h
@@ -13,6 +13,7 @@
#define FLUSH_BASE_PHYS 0xe0000000 /* SA1100 zero bank */
#define FLUSH_BASE 0xdf000000
#define FLUSH_BASE_MINICACHE 0xdf800000
+#define UNCACHEABLE_ADDR 0xfa050000
/*
* PCMCIA IO is mapped to 0xe0000000. We are likely to use in*()/out*()
diff --git a/include/asm-arm/arch-sa1100/keyboard.h b/include/asm-arm/arch-sa1100/keyboard.h
index c03526bf5..da214d3ed 100644
--- a/include/asm-arm/arch-sa1100/keyboard.h
+++ b/include/asm-arm/arch-sa1100/keyboard.h
@@ -1,27 +1,51 @@
/*
- * linux/include/asm-arm/arch-sa1100/keyboard.h
- *
- * Keyboard driver definitions for SA1100 architecture
- *
- * This really has to be cleaned up somehow...
- *
+ * linux/include/asm-arm/arch-sa1100/keyboard.h
+ * Created 16 Dec 1999 by Nicolas Pitre <nico@cam.org>
+ * This file contains the SA1100 architecture specific keyboard definitions
*/
-#define KEYBOARD_IRQ
+#ifndef _SA1100_KEYBOARD_H
+#define _SA1100_KEYBOARD_H
-#define NR_SCANCODES 128
+#include <linux/config.h>
-#define kbd_setkeycode(sc,kc) (-EINVAL)
-#define kbd_getkeycode(sc) (-EINVAL)
-#define kbd_pretranslate(sc,kc) 1
-#define kbd_translate(sc, kcp, raw) kbd_drv_translate(sc, kcp, raw)
-#define kbd_init_hw() kbd_drv_init()
-#define kbd_unexpected_up
-#define kbd_leds(leds)
+#ifdef CONFIG_SA1100_BRUTUS
-#define kbd_sysrq_xlate
-#define kbd_disable_irq()
-#define kbd_enable_irq()
+extern int Brutus_kbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern void Brutus_kbd_leds(unsigned char leds);
+extern void Brutus_kbd_init_hw(void);
+extern void Brutus_kbd_enable_irq(void);
+extern void Brutus_kbd_disable_irq(void);
+extern unsigned char Brutus_kbd_sysrq_xlate[128];
+
+#define kbd_setkeycode(x...) (-ENOSYS)
+#define kbd_getkeycode(x...) (-ENOSYS)
+#define kbd_translate Brutus_kbd_translate
+#define kbd_unexpected_up(x...) (1)
+#define kbd_leds Brutus_kbd_leds
+#define kbd_init_hw Brutus_kbd_init_hw
+#define kbd_enable_irq Brutus_kbd_enable_irq
+#define kbd_disable_irq Brutus_kbd_disable_irq
+#define kbd_sysrq_xlate Brutus_kbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
+
+#else
+
+/* dummy i.e. no real keyboard */
+#define kbd_setkeycode(x...) (-ENOSYS)
+#define kbd_getkeycode(x...) (-ENOSYS)
+#define kbd_translate(x...) (0)
+#define kbd_unexpected_up(x...) (1)
+#define kbd_leds(x...) (0)
+#define kbd_init_hw(x...) (0)
+#define kbd_enable_irq(x...) (0)
+#define kbd_disable_irq(x...) (0)
+
+#endif
+
+
+#endif /* _SA1100_KEYBOARD_H */
-#define SYSRQ_KEY 0x54
diff --git a/include/asm-arm/arch-sa1100/system.h b/include/asm-arm/arch-sa1100/system.h
index 4e883ee6a..3b56a4220 100644
--- a/include/asm-arm/arch-sa1100/system.h
+++ b/include/asm-arm/arch-sa1100/system.h
@@ -5,43 +5,43 @@
*/
#include <linux/config.h>
-#ifdef CONFIG_SA1100_VICTOR
-
-#define arch_reset( x ) { \
- /* switch off power supply */ \
- mdelay(2000); \
- GPCR = GPIO_GPIO23; \
- while(1); \
+extern __inline__ void arch_idle(void)
+{
+ while (!current->need_resched && !hlt_counter) {
+ cpu_do_idle(IDLE_CLOCK_SLOW);
+ cpu_do_idle(IDLE_WAIT_FAST);
+ cpu_do_idle(IDLE_CLOCK_FAST);
}
+}
-#else
-
-#define arch_reset(x) cpu_reset(0)
+#ifdef CONFIG_SA1100_VICTOR
-#endif
+extern inline void arch_power_off(void)
+{
+ /* switch off power supply */
+ mdelay(2000);
+ GPCR = GPIO_GPIO23;
+ while(1);
+}
+/* power off unconditionally */
+#define arch_reset(x) arch_power_off()
-#if 0
-#define arch_do_idle() cpu_do_idle()
#else
-/* Enter SA1100 idle mode (see data sheet sec 9.5).
- * It seems that the wait-on-interrupt just hang the CPU forever if it's
- * on the end of a cache line. Workaround: we force an explicit alignment
- * before it.
- */
-#define arch_do_idle() \
- do { \
- __asm__ __volatile__( \
-" mcr p15, 0, %0, c15, c2, 2 @ Disable clock switching \n" \
-" ldr %0, [%0] @ Must perform a non-cached access \n" \
-" b 1f @ Seems we must align the next \n" \
-" .align 5 @ instruction on a cache line \n" \
-"1: mcr p15, 0, %0, c15, c8, 2 @ Wait for interrupts \n" \
-" mov r0, r0 @ insert NOP to ensure SA1100 re-awakes\n" \
-" mcr p15, 0, %0, c15, c1, 2 @ Reenable clock switching \n" \
- : : "r" (&ICIP) : "cc" ); \
- } while (0)
-#endif
+
+extern inline void arch_reset(char mode)
+{
+ if (mode == 's') {
+ /* Jump into ROM at address 0 */
+ cpu_reset(0);
+ } else {
+ /* Activate SA1100 watchdog and wait for the trigger... */
+ OSMR3 = OSCR + 3686400/2; /* in 1/2 sec */
+ OWER |= OWER_WME;
+ OIER |= OIER_E3;
+ }
+}
#define arch_power_off() do { } while (0)
+#endif
diff --git a/include/asm-arm/arch-sa1100/vmalloc.h b/include/asm-arm/arch-sa1100/vmalloc.h
new file mode 100644
index 000000000..42affe414
--- /dev/null
+++ b/include/asm-arm/arch-sa1100/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-shark/dma.h b/include/asm-arm/arch-shark/dma.h
new file mode 100644
index 000000000..bf62c8ff8
--- /dev/null
+++ b/include/asm-arm/arch-shark/dma.h
@@ -0,0 +1,18 @@
+/*
+ * linux/include/asm-arm/arch-shark/dma.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+/* Use only the lowest 4MB, nothing else works.
+ * The rest is not DMAable. See dev / .properties
+ * in OpenFirmware.
+ */
+#define MAX_DMA_ADDRESS 0xC0400000
+#define MAX_DMA_CHANNELS 8
+#define DMA_ISA_CASCADE 4
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff --git a/include/asm-arm/arch-shark/hardware.h b/include/asm-arm/arch-shark/hardware.h
new file mode 100644
index 000000000..1fb25abd1
--- /dev/null
+++ b/include/asm-arm/arch-shark/hardware.h
@@ -0,0 +1,49 @@
+/*
+ * linux/include/asm-arm/arch-shark/hardware.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa110/hardware.h
+ * Copyright (C) 1996-1999 Russell King.
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Mapping areas
+ */
+#define IO_BASE 0xe0000000
+
+/*
+ * RAM definitions
+ */
+#define FLUSH_BASE_PHYS 0x60000000
+
+#else
+
+#define IO_BASE 0
+
+#endif
+
+#define IO_SIZE 0x10000000
+#define IO_START 0x40000000
+
+#define FLUSH_BASE 0xdf000000
+#define PCIO_BASE 0xe0000000
+
+
+/* defines for the Framebuffer */
+#define FB_BASE 0xd0000000
+#define FB_START 0x06000000
+#define FB_SIZE 0x00200000
+
+/* Registers for Framebuffer */
+#define FBREG_BASE (FB_BASE + FB_SIZE)
+#define FBREG_START 0x06800000
+#define FBREG_SIZE 0x000c0000
+
+#endif
+
diff --git a/include/asm-arm/arch-shark/ide.h b/include/asm-arm/arch-shark/ide.h
new file mode 100644
index 000000000..a9e373e98
--- /dev/null
+++ b/include/asm-arm/arch-shark/ide.h
@@ -0,0 +1,45 @@
+/*
+ * linux/include/asm-arm/arch-shark/ide.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa285/ide.h
+ * Copyright (c) 1998 Russell King
+ */
+
+#include <asm/irq.h>
+
+/*
+ * Set up a hw structure for a specified data port, control port and IRQ.
+ * This should follow whatever the default interface uses.
+ */
+static __inline__ void
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+{
+ ide_ioreg_t reg = (ide_ioreg_t) data_port;
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hw->io_ports[i] = reg;
+ reg += 1;
+ }
+ hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
+ hw->irq = irq;
+}
+
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+static __inline__ void
+ide_init_default_hwifs(void)
+{
+ hw_regs_t hw;
+
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, 14);
+ ide_register_hw(&hw, NULL);
+}
+
diff --git a/include/asm-arm/arch-shark/io.h b/include/asm-arm/arch-shark/io.h
new file mode 100644
index 000000000..ff0def03a
--- /dev/null
+++ b/include/asm-arm/arch-shark/io.h
@@ -0,0 +1,207 @@
+/*
+ * linux/include/asm-arm/arch-shark/io.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa110/io.h
+ * Copyright (C) 1997,1998 Russell King
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We use two different types of addressing - PC style addresses, and ARM
+ * addresses. PC style accesses the PC hardware with the normal PC IO
+ * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+
+ * and are translated to the start of IO.
+ */
+#define __PORT_PCIO(x) (!((x) & 0x80000000))
+
+/*
+ * Dynamic IO functions - let the compiler
+ * optimize the expressions
+ */
+#define DECLARE_DYN_OUT(fnsuffix,instr) \
+extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port) \
+{ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "tst %2, #0x80000000\n\t" \
+ "mov %0, %4\n\t" \
+ "addeq %0, %0, %3\n\t" \
+ "str" ##instr## " %1, [%0, %2] @ out"###fnsuffix \
+ : "=&r" (temp) \
+ : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \
+ : "cc"); \
+}
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr) \
+extern __inline__ unsigned sz __in##fnsuffix (unsigned int port) \
+{ \
+ unsigned long temp, value; \
+ __asm__ __volatile__( \
+ "tst %2, #0x80000000\n\t" \
+ "mov %0, %4\n\t" \
+ "addeq %0, %0, %3\n\t" \
+ "ldr" ##instr## " %1, [%0, %2] @ in"###fnsuffix \
+ : "=&r" (temp), "=r" (value) \
+ : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \
+ : "cc"); \
+ return (unsigned sz)value; \
+}
+
+extern __inline__ unsigned int __ioaddr (unsigned int port) \
+{ \
+ if (__PORT_PCIO(port)) \
+ return (unsigned int)(PCIO_BASE + (port)); \
+ else \
+ return (unsigned int)(IO_BASE + (port)); \
+}
+
+#define DECLARE_IO(sz,fnsuffix,instr) \
+ DECLARE_DYN_OUT(fnsuffix,instr) \
+ DECLARE_DYN_IN(sz,fnsuffix,instr)
+
+DECLARE_IO(char,b,"b")
+DECLARE_IO(short,w,"h")
+DECLARE_IO(long,l,"")
+
+#undef DECLARE_IO
+#undef DECLARE_DYN_OUT
+#undef DECLARE_DYN_IN
+
+/*
+ * Constant address IO functions
+ *
+ * These have to be macros for the 'J' constraint to work -
+ * +/-4096 immediate operand.
+ */
+#define __outbc(value,port) \
+({ \
+ if (__PORT_PCIO((port))) \
+ __asm__ __volatile__( \
+ "strb %0, [%1, %2] @ outbc" \
+ : : "r" (value), "r" (PCIO_BASE), "Jr" (port)); \
+ else \
+ __asm__ __volatile__( \
+ "strb %0, [%1, %2] @ outbc" \
+ : : "r" (value), "r" (IO_BASE), "r" (port)); \
+})
+
+#define __inbc(port) \
+({ \
+ unsigned char result; \
+ if (__PORT_PCIO((port))) \
+ __asm__ __volatile__( \
+ "ldrb %0, [%1, %2] @ inbc" \
+ : "=r" (result) : "r" (PCIO_BASE), "Jr" (port)); \
+ else \
+ __asm__ __volatile__( \
+ "ldrb %0, [%1, %2] @ inbc" \
+ : "=r" (result) : "r" (IO_BASE), "r" (port)); \
+ result; \
+})
+
+#define __outwc(value,port) \
+({ \
+ unsigned long v = value; \
+ if (__PORT_PCIO((port))) \
+ __asm__ __volatile__( \
+ "strh %0, [%1, %2] @ outwc" \
+ : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" (port)); \
+ else \
+ __asm__ __volatile__( \
+ "strh %0, [%1, %2] @ outwc" \
+ : : "r" (v|v<<16), "r" (IO_BASE), "r" (port)); \
+})
+
+#define __inwc(port) \
+({ \
+ unsigned short result; \
+ if (__PORT_PCIO((port))) \
+ __asm__ __volatile__( \
+ "ldrh %0, [%1, %2] @ inwc" \
+ : "=r" (result) : "r" (PCIO_BASE), "Jr" (port)); \
+ else \
+ __asm__ __volatile__( \
+ "ldrh %0, [%1, %2] @ inwc" \
+ : "=r" (result) : "r" (IO_BASE), "r" (port)); \
+ result & 0xffff; \
+})
+
+#define __outlc(value,port) \
+({ \
+ unsigned long v = value; \
+ if (__PORT_PCIO((port))) \
+ __asm__ __volatile__( \
+ "str %0, [%1, %2] @ outlc" \
+ : : "r" (v), "r" (PCIO_BASE), "Jr" (port)); \
+ else \
+ __asm__ __volatile__( \
+ "str %0, [%1, %2] @ outlc" \
+ : : "r" (v), "r" (IO_BASE), "r" (port)); \
+})
+
+#define __inlc(port) \
+({ \
+ unsigned long result; \
+ if (__PORT_PCIO((port))) \
+ __asm__ __volatile__( \
+ "ldr %0, [%1, %2] @ inlc" \
+ : "=r" (result) : "r" (PCIO_BASE), "Jr" (port)); \
+ else \
+ __asm__ __volatile__( \
+ "ldr %0, [%1, %2] @ inlc" \
+ : "=r" (result) : "r" (IO_BASE), "r" (port)); \
+ result; \
+})
+
+#define __ioaddrc(port) \
+({ \
+ unsigned long addr; \
+ if (__PORT_PCIO((port))) \
+ addr = PCIO_BASE + (port); \
+ else \
+ addr = IO_BASE + (port); \
+ addr; \
+})
+
+#define __mem_pci(addr) addr
+
+#define inb(p) (__builtin_constant_p((p)) ? __inbc(p) : __inb(p))
+#define inw(p) (__builtin_constant_p((p)) ? __inwc(p) : __inw(p))
+#define inl(p) (__builtin_constant_p((p)) ? __inlc(p) : __inl(p))
+#define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
+#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
+#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
+
+#define __arch_getb(addr) (*(volatile unsigned char *)(addr))
+#define __arch_getw(addr) (*(volatile unsigned short *)(addr))
+#define __arch_getl(addr) (*(volatile unsigned long *)(addr))
+
+#define __arch_putb(b,addr) (*(volatile unsigned char *)(addr) = (b))
+#define __arch_putw(b,addr) (*(volatile unsigned short *)(addr) = (b))
+#define __arch_putl(b,addr) (*(volatile unsigned long *)(addr) = (b))
+
+/*
+ * Translated address IO functions
+ *
+ * IO address has already been translated to a virtual address
+ */
+#define outb_t(v,p) \
+ (*(volatile unsigned char *)(p) = (v))
+
+#define inb_t(p) \
+ (*(volatile unsigned char *)(p))
+
+#define outl_t(v,p) \
+ (*(volatile unsigned long *)(p) = (v))
+
+#define inl_t(p) \
+ (*(volatile unsigned long *)(p))
+
+#endif
diff --git a/include/asm-arm/arch-shark/irq.h b/include/asm-arm/arch-shark/irq.h
new file mode 100644
index 000000000..7dae77e02
--- /dev/null
+++ b/include/asm-arm/arch-shark/irq.h
@@ -0,0 +1,123 @@
+/*
+ * linux/include/asm-arm/arch-shark/irq.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from linux/arch/ppc/kernel/i8259.c and:
+ * include/asm-arm/arch-ebsa110/irq.h
+ * Copyright (C) 1996-1998 Russell King
+ */
+
+#define fixup_irq(x) (x)
+
+/*
+ * 8259A PIC functions to handle ISA devices:
+ */
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ * Let through the cascade-interrupt no. 2 (ff-(1<<2)==fb)
+ */
+static unsigned char cached_irq_mask[2] = { 0xfb, 0xff };
+
+/*
+ * These have to be protected by the irq controller spinlock
+ * before being called.
+ */
+static void shark_disable_8259A_irq(unsigned int irq)
+{
+ unsigned int mask;
+ if (irq<8) {
+ mask = 1 << irq;
+ cached_irq_mask[0] |= mask;
+ } else {
+ mask = 1 << (irq-8);
+ cached_irq_mask[1] |= mask;
+ }
+ outb(cached_irq_mask[1],0xA1);
+ outb(cached_irq_mask[0],0x21);
+}
+
+static void shark_enable_8259A_irq(unsigned int irq)
+{
+ unsigned int mask;
+ if (irq<8) {
+ mask = ~(1 << irq);
+ cached_irq_mask[0] &= mask;
+ } else {
+ mask = ~(1 << (irq-8));
+ cached_irq_mask[1] &= mask;
+ }
+ outb(cached_irq_mask[1],0xA1);
+ outb(cached_irq_mask[0],0x21);
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+static void shark_mask_and_ack_8259A_irq(unsigned int irq)
+{
+ if (irq & 8) {
+ cached_irq_mask[1] |= 1 << (irq-8);
+ inb(0xA1); /* DUMMY */
+ outb(cached_irq_mask[1],0xA1);
+ } else {
+ cached_irq_mask[0] |= 1 << irq;
+ outb(cached_irq_mask[0],0x21);
+ }
+}
+
+static void bogus_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ printk("Got interrupt %i!\n",irq);
+}
+
+static struct irqaction cascade;
+
+static __inline__ void irq_init_irq(void)
+{
+ int irq;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ irq_desc[irq].valid = 1;
+ irq_desc[irq].probe_ok = 1;
+ irq_desc[irq].mask_ack = shark_mask_and_ack_8259A_irq;
+ irq_desc[irq].mask = shark_disable_8259A_irq;
+ irq_desc[irq].unmask = shark_enable_8259A_irq;
+ }
+
+ /* The PICs are initialized to level triggered and auto eoi!
+ * If they are set to edge triggered they lose some IRQs,
+ * if they are set to manual eoi they get locked up after
+ * a short time
+ */
+
+ /* init master interrupt controller */
+ outb(0x19, 0x20); /* Start init sequence, level triggered */
+ outb(0x00, 0x21); /* Vector base */
+ outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
+ outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/
+ outb(0x0A, 0x20);
+ /* init slave interrupt controller */
+ outb(0x19, 0xA0); /* Start init sequence, level triggered */
+ outb(0x08, 0xA1); /* Vector base */
+ outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
+ outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */
+ outb(0x0A, 0xA0);
+ outb(cached_irq_mask[1],0xA1);
+ outb(cached_irq_mask[0],0x21);
+ //request_region(0x20,0x2,"pic1");
+ //request_region(0xA0,0x2,"pic2");
+
+ cascade.handler = bogus_int;
+ cascade.flags = 0;
+ cascade.mask = 0;
+ cascade.name = "cascade";
+ cascade.next = NULL;
+ cascade.dev_id = NULL;
+ setup_arm_irq(2,&cascade);
+
+}
diff --git a/include/asm-arm/arch-shark/irqs.h b/include/asm-arm/arch-shark/irqs.h
new file mode 100644
index 000000000..eabfb4b70
--- /dev/null
+++ b/include/asm-arm/arch-shark/irqs.h
@@ -0,0 +1,11 @@
+/*
+ * linux/include/asm-arm/arch-shark/irqs.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+
+#define NR_IRQS 16
+
+#define IRQ_ISA_KEYBOARD 1
+#define AUX_IRQ 12
+#define IRQ_HARDDISK 14
diff --git a/include/asm-arm/arch-shark/keyboard.h b/include/asm-arm/arch-shark/keyboard.h
new file mode 100644
index 000000000..523bd065f
--- /dev/null
+++ b/include/asm-arm/arch-shark/keyboard.h
@@ -0,0 +1,95 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/keyboard.h
+ *
+ * Keyboard driver definitions for EBSA285 architecture
+ *
+ * (C) 1998 Russell King
+ * (C) 1998 Phil Blundell
+ */
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+extern int have_isa_bridge;
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
+#define KEYBOARD_IRQ IRQ_ISA_KEYBOARD
+
+#define NR_SCANCODES 128
+
+#define kbd_setkeycode(sc,kc) \
+ ({ \
+ int __ret; \
+ if (have_isa_bridge) \
+ __ret = pckbd_setkeycode(sc,kc);\
+ else \
+ __ret = -EINVAL; \
+ __ret; \
+ })
+
+#define kbd_getkeycode(sc) \
+ ({ \
+ int __ret; \
+ if (have_isa_bridge) \
+ __ret = pckbd_getkeycode(sc); \
+ else \
+ __ret = -EINVAL; \
+ __ret; \
+ })
+
+#define kbd_translate(sc, kcp, rm) \
+ ({ \
+ pckbd_translate(sc, kcp, rm); \
+ })
+
+#define kbd_unexpected_up pckbd_unexpected_up
+
+#define kbd_leds(leds) \
+ do { \
+ if (have_isa_bridge) \
+ pckbd_leds(leds); \
+ } while (0)
+
+#define kbd_init_hw() \
+ do { \
+ if (have_isa_bridge) \
+ pckbd_init_hw(); \
+ } while (0)
+
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
+
+#define kbd_disable_irq()
+#define kbd_enable_irq()
+
+#define SYSRQ_KEY 0x54
+
+/* resource allocation */
+#define kbd_request_region() request_region(0x60, 16, "keyboard")
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+ "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform. */
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations. */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+#define aux_request_irq(hand, dev_id) \
+ request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
diff --git a/include/asm-arm/arch-shark/memory.h b/include/asm-arm/arch-shark/memory.h
new file mode 100644
index 000000000..d3ede01ec
--- /dev/null
+++ b/include/asm-arm/arch-shark/memory.h
@@ -0,0 +1,35 @@
+/*
+ * linux/include/asm-arm/arch-shark/memory.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * derived from:
+ * linux/include/asm-arm/arch-ebsa110/memory.h
+ * Copyright (c) 1996-1999 Russell King.
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE_26 (0x04000000UL)
+
+/*
+ * Page offset: = 3GB
+ */
+#define PAGE_OFFSET (0xC0000000UL)
+#define PHYS_OFFSET (0x08000000UL)
+
+#define __virt_to_phys__is_a_macro
+#define __phys_to_virt__is_a_macro
+#define __virt_to_phys(vpage) (vpage - PAGE_OFFSET + PHYS_OFFSET)
+#define __phys_to_virt(ppage) (ppage - PHYS_OFFSET + PAGE_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff --git a/include/asm-arm/arch-shark/param.h b/include/asm-arm/arch-shark/param.h
new file mode 100644
index 000000000..f6b5f9e71
--- /dev/null
+++ b/include/asm-arm/arch-shark/param.h
@@ -0,0 +1,10 @@
+/*
+ * linux/include/asm-arm/arch-shark/param.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
+
+/* This must be a power of 2 because the RTC
+ * can't use anything else.
+ */
+#define HZ 64
diff --git a/include/asm-arm/arch-shark/processor.h b/include/asm-arm/arch-shark/processor.h
new file mode 100644
index 000000000..bd99869af
--- /dev/null
+++ b/include/asm-arm/arch-shark/processor.h
@@ -0,0 +1,28 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/processor.h
+ *
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ * 21-Mar-1999 RMK Added asm/arch/memory.h
+ */
+
+#ifndef __ASM_ARCH_PROCESSOR_H
+#define __ASM_ARCH_PROCESSOR_H
+
+#include <asm/arch/memory.h>
+
+/*
+ * Bus types
+ */
+#define EISA_bus 0
+#define EISA_bus__is_a_macro /* for versions in ksyms.c */
+#define MCA_bus 0
+#define MCA_bus__is_a_macro /* for versions in ksyms.c */
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+#endif
diff --git a/include/asm-arm/arch-shark/serial.h b/include/asm-arm/arch-shark/serial.h
new file mode 100644
index 000000000..7b23d4fb5
--- /dev/null
+++ b/include/asm-arm/arch-shark/serial.h
@@ -0,0 +1,33 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/serial.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ *
+ * Changelog:
+ * 15-10-1996 RMK Created
+ */
+#ifndef __ASM_ARCH_SERIAL_H
+#define __ASM_ARCH_SERIAL_H
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD (1843200 / 16)
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+#define RS_TABLE_SIZE 2
+
+ /* UART CLK PORT IRQ FLAGS */
+#define STD_SERIAL_PORT_DEFNS \
+ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
+ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */
+
+#define EXTRA_SERIAL_PORT_DEFNS
+
+#endif
+
diff --git a/include/asm-arm/arch-shark/system.h b/include/asm-arm/arch-shark/system.h
new file mode 100644
index 000000000..b0d34e811
--- /dev/null
+++ b/include/asm-arm/arch-shark/system.h
@@ -0,0 +1,21 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/system.h
+ *
+ * Copyright (c) 1996-1998 Russell King.
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+extern __inline__ void arch_reset(char mode)
+{
+ /*
+ * loop endlessly
+ */
+ cli();
+}
+
+#define arch_power_off() do { } while (0)
+#define arch_do_idle() do {} while (0)
+/*cpu_do_idle()*/
+
+#endif
diff --git a/include/asm-arm/arch-shark/time.h b/include/asm-arm/arch-shark/time.h
new file mode 100644
index 000000000..32f9d7593
--- /dev/null
+++ b/include/asm-arm/arch-shark/time.h
@@ -0,0 +1,101 @@
+/*
+ * linux/include/asm-arm/arch-shark/time.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * Uses the real time clock because you can't run
+ * the timer with level triggered interrupts and
+ * you can't run the shark with edge triggered
+ * inetrrupts (loses ints and hangs).
+ *
+ * derived from linux/drivers/char/rtc.c and:
+ * linux/include/asm-arm/arch-ebsa110/time.h
+ * Copyright (c) 1996,1997,1998 Russell King.
+ */
+
+#include <linux/config.h>
+#include <asm/leds.h>
+#include <linux/mc146818rtc.h>
+
+#define IRQ_TIMER 8
+
+extern void get_rtc_time(struct rtc_time *rtc_tm);
+extern void set_rtc_irq_bit(unsigned char bit);
+extern unsigned long epoch;
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+ CMOS_READ(RTC_INTR_FLAGS);
+
+#ifdef CONFIG_LEDS
+ {
+ static int count = 50;
+ if (--count == 0) {
+ count = 50;
+ leds_event(led_timer);
+ }
+ }
+#endif
+
+ {
+#ifdef DIVISOR
+ static unsigned int divisor;
+
+ if (divisor-- == 0) {
+ divisor = DIVISOR - 1;
+#else
+ {
+#endif
+ do_timer(regs);
+ }
+ }
+}
+
+static struct irqaction timerirq = {
+ timer_interrupt,
+ SA_INTERRUPT,
+ 0,
+ "timer",
+ NULL,
+ NULL
+};
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+extern __inline__ void setup_timer(void)
+{
+ struct rtc_time r_time;
+ unsigned long flags;
+ int tmp = 0;
+ unsigned char val;
+
+ /*
+ * Set the clock to 128 Hz, we already have a valid
+ * vector now:
+ */
+
+ while (HZ > (1<<tmp))
+ tmp++;
+
+ /*
+ * Check that the input was really a power of 2.
+ */
+ if (HZ != (1<<tmp))
+ panic("Please set HZ to a power of 2!");
+
+ save_flags(flags);
+ cli();
+ val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
+ val |= (16 - tmp);
+ CMOS_WRITE(val, RTC_FREQ_SELECT);
+ restore_flags(flags);
+ set_rtc_irq_bit(RTC_PIE);
+
+ get_rtc_time(&r_time);
+ xtime.tv_sec = mktime(r_time.tm_year+epoch, r_time.tm_mon+1, r_time.tm_mday,
+ r_time.tm_hour, r_time.tm_min, r_time.tm_sec);
+
+ setup_arm_irq(IRQ_TIMER, &timerirq);
+}
diff --git a/include/asm-arm/arch-shark/timex.h b/include/asm-arm/arch-shark/timex.h
new file mode 100644
index 000000000..9588719c2
--- /dev/null
+++ b/include/asm-arm/arch-shark/timex.h
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-shark/timex.h
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ */
diff --git a/include/asm-arm/arch-shark/uncompress.h b/include/asm-arm/arch-shark/uncompress.h
new file mode 100644
index 000000000..d6097d43f
--- /dev/null
+++ b/include/asm-arm/arch-shark/uncompress.h
@@ -0,0 +1,34 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+/*
+ * This does not append a newline
+ */
+static void puts(const char *s)
+{
+ __asm__ __volatile__("
+ ldrb %0, [%2], #1
+ teq %0, #0
+ beq 3f
+1: strb %0, [%3]
+2: ldrb %1, [%3, #0x14]
+ and %1, %1, #0x60
+ teq %1, #0x60
+ bne 2b
+ teq %0, #'\n'
+ moveq %0, #'\r'
+ beq 1b
+ ldrb %0, [%2], #1
+ teq %0, #0
+ bne 1b
+3: " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/include/asm-arm/checksum.h b/include/asm-arm/checksum.h
index 9d048a3ba..b91f5e7f4 100644
--- a/include/asm-arm/checksum.h
+++ b/include/asm-arm/checksum.h
@@ -123,12 +123,14 @@ csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
adcs %0, %0, %3
adcs %0, %0, %4
adcs %0, %0, %5
+ adc %0, %0, #0
adds %0, %0, %0, lsl #16
- addcs %0, %0, #0x10000"
+ addcs %0, %0, #0x10000
+ mvn %0, %0"
: "=&r"(sum)
- : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len) << 16), "Ir" (proto << 8)
+ : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len)), "Ir" (proto << 8)
: "cc");
- return (~sum) >> 16;
+ return sum >> 16;
}
diff --git a/include/asm-arm/cpu-multi32.h b/include/asm-arm/cpu-multi32.h
index b959f4994..b8a5b58f8 100644
--- a/include/asm-arm/cpu-multi32.h
+++ b/include/asm-arm/cpu-multi32.h
@@ -95,7 +95,7 @@ extern struct processor {
/*
* Idle the processor
*/
- int (*_do_idle)(void);
+ int (*_do_idle)(int mode);
/*
* flush I cache for a page
*/
@@ -110,7 +110,7 @@ extern const struct processor sa110_processor_functions;
#define cpu_check_bugs() processor._check_bugs()
#define cpu_proc_init() processor._proc_init()
#define cpu_proc_fin() processor._proc_fin()
-#define cpu_do_idle() processor._do_idle()
+#define cpu_do_idle(mode) processor._do_idle(mode)
#define cpu_flush_cache_all() processor._flush_cache_all()
#define cpu_flush_cache_area(start,end,flags) processor._flush_cache_area(start,end,flags)
diff --git a/include/asm-arm/cpu-single.h b/include/asm-arm/cpu-single.h
index 74cffcdb5..6a4c256f2 100644
--- a/include/asm-arm/cpu-single.h
+++ b/include/asm-arm/cpu-single.h
@@ -49,7 +49,7 @@ extern void cpu_data_abort(unsigned long pc);
extern void cpu_check_bugs(void);
extern void cpu_proc_init(void);
extern void cpu_proc_fin(void);
-extern int cpu_do_idle(void);
+extern int cpu_do_idle(int mode);
extern void cpu_flush_cache_all(void);
extern void cpu_flush_cache_area(unsigned long address, unsigned long end, int flags);
diff --git a/include/asm-arm/namei.h b/include/asm-arm/namei.h
index 082f2c910..a402d3b9d 100644
--- a/include/asm-arm/namei.h
+++ b/include/asm-arm/namei.h
@@ -12,51 +12,14 @@
#define ARM_BSD_EMUL "usr/gnemul/bsd/"
-static inline struct dentry *
-__arm_lookup_dentry(const char *name, int lookup_flags)
+static inline char *__emul_prefix(void)
{
- struct dentry *base;
- char *emul;
-
switch (current->personality) {
case PER_BSD:
- emul = ARM_BSD_EMUL; break;
+ return ARM_BSD_EMUL;
default:
return NULL;
}
-
- base = lookup_dentry (emul, dget (current->fs->root),
- (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
-
- if (IS_ERR (base)) return NULL;
-
- base = lookup_dentry (name, base, lookup_flags);
-
- if (IS_ERR (base)) return NULL;
-
- if (!base->d_inode) {
- struct dentry *fromroot;
-
- fromroot = lookup_dentry (name, dget (current->fs->root),
- lookup_flags);
-
- if (IS_ERR (fromroot)) return base;
-
- if (fromroot->d_inode) {
- dput(base);
- return fromroot;
- }
-
- dput(fromroot);
- }
-
- return base;
}
-#define __prefix_lookup_dentry(name, lookup_flags) \
- if (current->personality) { \
- dentry = __arm_lookup_dentry (name, lookup_flags); \
- if (dentry) return dentry; \
- }
-
#endif /* __ASMARM_NAMEI_H */
diff --git a/include/asm-arm/proc-armv/pgtable.h b/include/asm-arm/proc-armv/pgtable.h
index e9260057f..d4a57d8a2 100644
--- a/include/asm-arm/proc-armv/pgtable.h
+++ b/include/asm-arm/proc-armv/pgtable.h
@@ -12,6 +12,7 @@
#define __ASM_PROC_PGTABLE_H
#include <asm/proc/domain.h>
+#include <asm/arch/vmalloc.h>
/*
* entries per page directory level: they are two-level, so
@@ -21,19 +22,6 @@
#define PTRS_PER_PMD 1
#define PTRS_PER_PGD 4096
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts. That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
-
/****************
* PMD functions *
****************/
@@ -139,7 +127,7 @@ extern __inline__ unsigned long pmd_page(pmd_t pmd)
#define PAGE_NONE __pgprot(_L_PTE_DEFAULT)
#define PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_BUFFERABLE)
#define PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_BUFFERABLE | L_PTE_WRITE)
-#define PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_BUFFERABLE)
#define PAGE_KERNEL __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
#define _PAGE_CHG_MASK (PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
diff --git a/include/asm-i386/namei.h b/include/asm-i386/namei.h
index 5708ffd8d..814865088 100644
--- a/include/asm-i386/namei.h
+++ b/include/asm-i386/namei.h
@@ -12,7 +12,6 @@
* Look at asm-sparc/namei.h for details.
*/
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif /* __I386_NAMEI_H */
diff --git a/include/asm-ia64/namei.h b/include/asm-ia64/namei.h
index 74e195253..0507e03dc 100644
--- a/include/asm-ia64/namei.h
+++ b/include/asm-ia64/namei.h
@@ -11,7 +11,6 @@
* for /usr/gnemul/ emulation stuff.
* Look at asm-sparc/namei.h for details.
*/
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif /* _ASM_IA64_NAMEI_H */
diff --git a/include/asm-m68k/namei.h b/include/asm-m68k/namei.h
index 7b4f02680..f33f243b6 100644
--- a/include/asm-m68k/namei.h
+++ b/include/asm-m68k/namei.h
@@ -12,7 +12,6 @@
* Look at asm-sparc/namei.h for details.
*/
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif
diff --git a/include/asm-mips/namei.h b/include/asm-mips/namei.h
index 64acd52ff..5361d07fd 100644
--- a/include/asm-mips/namei.h
+++ b/include/asm-mips/namei.h
@@ -13,42 +13,18 @@
/* Only one at this time. */
#define IRIX32_EMUL "usr/gnemul/irix/"
-static inline struct dentry *
-__mips_lookup_dentry(const char *name, int lookup_flags)
-{
- struct dentry *base;
+#ifdef CONFIG_BINFMT_IRIX
+static inline char *__emul_prefix(void)
+{
if (current->personality != PER_IRIX32)
- return ERR_PTR(-ENOENT);
-
- base = lookup_dentry (IRIX32_EMUL,
- dget (current->fs->root),
- (LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
-
- if (IS_ERR (base)) return base;
-
- base = lookup_dentry (name, base, lookup_flags);
-
- if (IS_ERR (base)) return base;
-
- if (!base->d_inode) {
- dput(base);
- return ERR_PTR(-ENOENT);
- }
-
- return base;
+ return NULL;
+ return IRIX32_EMUL;
}
-#ifdef CONFIG_BINFMT_IRIX
-
-#define __prefix_lookup_dentry(name, lookup_flags) \
- dentry = __mips_lookup_dentry (name, lookup_flags); \
- if (!IS_ERR (dentry)) return dentry;
-
#else /* !defined(CONFIG_BINFMT_IRIX) */
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif /* !defined(CONFIG_BINFMT_IRIX) */
diff --git a/include/asm-mips64/namei.h b/include/asm-mips64/namei.h
index 3152a3836..aed1ebf52 100644
--- a/include/asm-mips64/namei.h
+++ b/include/asm-mips64/namei.h
@@ -13,7 +13,6 @@
* Look at asm-sparc/namei.h for details.
*/
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif /* _ASM_NAMEI_H */
diff --git a/include/asm-ppc/namei.h b/include/asm-ppc/namei.h
index 9e0268b03..cd871903d 100644
--- a/include/asm-ppc/namei.h
+++ b/include/asm-ppc/namei.h
@@ -13,7 +13,6 @@
* Look at asm-sparc/namei.h for details.
*/
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif /* __PPC_NAMEI_H */
diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
index bf0d00c0a..85462da1e 100644
--- a/include/asm-sh/bitops.h
+++ b/include/asm-sh/bitops.h
@@ -103,7 +103,7 @@ extern __inline__ unsigned long ffz(unsigned long word)
{
unsigned long result;
- __asm__("1:\n"
+ __asm__("1:\n\t"
"shlr %1\n\t"
"bt/s 1b\n\t"
" add #1, %0"
diff --git a/include/asm-sh/byteorder.h b/include/asm-sh/byteorder.h
index dcc9f8241..cddaeb58e 100644
--- a/include/asm-sh/byteorder.h
+++ b/include/asm-sh/byteorder.h
@@ -19,7 +19,7 @@ static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
{
- __asm__("swap.b %0,%0"
+ __asm__("swap.b %0, %0"
: "=r" (x)
: "0" (x));
return x;
diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h
index ae0272e9b..846e64509 100644
--- a/include/asm-sh/checksum.h
+++ b/include/asm-sh/checksum.h
@@ -55,24 +55,6 @@ unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
}
-#if 0
-
-/* Not used at the moment. It is difficult to imagine for what purpose
- it can be used :-) Please, do not forget to verify_area before it --ANK
- */
-
-/*
- * This combination is currently not used, but possible:
- */
-
-extern __inline__
-unsigned int csum_partial_copy_to_user ( const char *src, char *dst,
- int len, int sum, int *err_ptr)
-{
- return csum_partial_copy_generic ( src, dst, len, sum, NULL, err_ptr);
-}
-#endif
-
/*
* These are the old (and unsafe) way of doing checksums, a warning message will be
* printed if they are used and an exeption occurs.
@@ -91,12 +73,12 @@ static __inline__ unsigned int csum_fold(unsigned int sum)
{
unsigned int __dummy;
__asm__("clrt\n\t"
- "mov %0,%1\n\t"
+ "mov %0, %1\n\t"
"shll16 %0\n\t"
- "addc %0,%1\n\t"
+ "addc %0, %1\n\t"
"movt %0\n\t"
"shlr16 %1\n\t"
- "add %1,%0"
+ "add %1, %0"
: "=r" (sum), "=&r" (__dummy)
: "0" (sum));
return ~sum;
@@ -114,24 +96,24 @@ static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int
unsigned int sum, __dummy;
__asm__ __volatile__(
- "mov.l @%1+,%0\n\t"
- "add #-4,%2\n\t"
+ "mov.l @%1+, %0\n\t"
+ "add #-4, %2\n\t"
"clrt\n\t"
- "mov.l @%1+,%3\n\t"
- "addc %3,%0\n\t"
- "mov.l @%1+,%3\n\t"
- "addc %3,%0\n\t"
- "mov.l @%1+,%3\n\t"
- "addc %3,%0\n"
+ "mov.l @%1+, %3\n\t"
+ "addc %3, %0\n\t"
+ "mov.l @%1+, %3\n\t"
+ "addc %3, %0\n\t"
+ "mov.l @%1+, %3\n\t"
+ "addc %3, %0\n"
"1:\t"
- "mov.l @%1+,%3\n\t"
- "addc %3,%0\n\t"
+ "mov.l @%1+, %3\n\t"
+ "addc %3, %0\n\t"
"movt %3\n\t"
"dt %2\n\t"
"bf/s 1b\n\t"
- " cmp/eq #1,%3\n\t"
- "mov #0,%3\n\t"
- "addc %3,%0\n\t"
+ " cmp/eq #1, %3\n\t"
+ "mov #0, %3\n\t"
+ "addc %3, %0\n\t"
/* Since the input registers which are loaded with iph and ihl
are modified, we must also specify them as outputs, or gcc
will assume they contain their original values. */
@@ -153,11 +135,11 @@ static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
unsigned long len_proto = (proto<<16)+len;
#endif
__asm__("clrt\n\t"
- "addc %0,%1\n\t"
- "addc %2,%1\n\t"
- "addc %3,%1\n\t"
+ "addc %0, %1\n\t"
+ "addc %2, %1\n\t"
+ "addc %3, %1\n\t"
"movt %0\n\t"
- "add %1,%0"
+ "add %1, %0"
: "=r" (sum), "=r" (len_proto)
: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
return sum;
@@ -195,26 +177,26 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
{
unsigned int __dummy;
__asm__("clrt\n\t"
- "mov.l @(0,%2),%1\n\t"
- "addc %1,%0\n\t"
- "mov.l @(4,%2),%1\n\t"
- "addc %1,%0\n\t"
- "mov.l @(8,%2),%1\n\t"
- "addc %1,%0\n\t"
- "mov.l @(12,%2),%1\n\t"
- "addc %1,%0\n\t"
- "mov.l @(0,%3),%1\n\t"
- "addc %1,%0\n\t"
- "mov.l @(4,%3),%1\n\t"
- "addc %1,%0\n\t"
- "mov.l @(8,%3),%1\n\t"
- "addc %1,%0\n\t"
- "mov.l @(12,%3),%1\n\t"
- "addc %1,%0\n\t"
- "addc %4,%0\n\t"
- "addc %5,%0\n\t"
+ "mov.l @(0,%2), %1\n\t"
+ "addc %1, %0\n\t"
+ "mov.l @(4,%2), %1\n\t"
+ "addc %1, %0\n\t"
+ "mov.l @(8,%2), %1\n\t"
+ "addc %1, %0\n\t"
+ "mov.l @(12,%2), %1\n\t"
+ "addc %1, %0\n\t"
+ "mov.l @(0,%3), %1\n\t"
+ "addc %1, %0\n\t"
+ "mov.l @(4,%3), %1\n\t"
+ "addc %1, %0\n\t"
+ "mov.l @(8,%3), %1\n\t"
+ "addc %1, %0\n\t"
+ "mov.l @(12,%3), %1\n\t"
+ "addc %1, %0\n\t"
+ "addc %4, %0\n\t"
+ "addc %5, %0\n\t"
"movt %1\n\t"
- "add %1,%0\n"
+ "add %1, %0\n"
: "=r" (sum), "=&r" (__dummy)
: "r" (saddr), "r" (daddr),
"r" (htonl(len)), "r" (htonl(proto)), "0" (sum));
diff --git a/include/asm-sh/current.h b/include/asm-sh/current.h
index fe65bfcc9..3bd231173 100644
--- a/include/asm-sh/current.h
+++ b/include/asm-sh/current.h
@@ -12,8 +12,8 @@ static __inline__ struct task_struct * get_current(void)
{
struct task_struct *current;
- __asm__("stc r4_bank,%0\n\t"
- "add %1,%0"
+ __asm__("stc $r4_bank, %0\n\t"
+ "add %1, %0"
:"=&r" (current)
:"r" (-8192));
return current;
diff --git a/include/asm-sh/delay.h b/include/asm-sh/delay.h
index 222561a3e..3e25684fe 100644
--- a/include/asm-sh/delay.h
+++ b/include/asm-sh/delay.h
@@ -8,7 +8,7 @@
extern __inline__ void __delay(unsigned long loops)
{
__asm__ __volatile__(
- "tst %0,%0\n\t"
+ "tst %0, %0\n\t"
"1:\t"
"bf/s 1b\n\t"
" dt %0"
@@ -19,8 +19,8 @@ extern __inline__ void __delay(unsigned long loops)
extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
{
usecs *= 0x000010c6; /* 2**32 / 1000000 */
- __asm__("dmulu.l %0,%2\n\t"
- "sts mach,%0"
+ __asm__("dmulu.l %0, %2\n\t"
+ "sts $mach, %0"
: "=r" (usecs)
: "0" (usecs), "r" (lps)
: "macl", "mach");
diff --git a/include/asm-sh/mman.h b/include/asm-sh/mman.h
index 19b02f6da..49fecaed5 100644
--- a/include/asm-sh/mman.h
+++ b/include/asm-sh/mman.h
@@ -25,6 +25,12 @@
#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
#define MAP_FILE 0
diff --git a/include/asm-sh/namei.h b/include/asm-sh/namei.h
index 582fc77e3..a51522ac1 100644
--- a/include/asm-sh/namei.h
+++ b/include/asm-sh/namei.h
@@ -12,7 +12,6 @@
* Look at asm-sparc/namei.h for details.
*/
-#define __prefix_lookup_dentry(name, lookup_flags) \
- do {} while (0)
+#define __emul_prefix() NULL
#endif /* __ASM_SH_NAMEI_H */
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
index 962461a33..1fcfb1300 100644
--- a/include/asm-sh/processor.h
+++ b/include/asm-sh/processor.h
@@ -45,8 +45,10 @@ extern struct sh_cpuinfo boot_cpu_data;
/*
* User space process size: 2GB.
+ *
+ * Since SH7709 and SH7750 have "area 7", we can't use 0x7c000000--0x7fffffff
*/
-#define TASK_SIZE 0x80000000
+#define TASK_SIZE 0x7c000000UL
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
@@ -54,19 +56,25 @@ extern struct sh_cpuinfo boot_cpu_data;
#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
/*
- * FPU structure and data
- */
-/* FD-bit of SR register.
- * When it's set, it means the processor doesn't have right to use FPU,
- * and it results exception when the floating operation is executed.
+ * Bit of SR register
+ *
+ * FD-bit:
+ * When it's set, it means the processor doesn't have right to use FPU,
+ * and it results exception when the floating operation is executed.
+ *
+ * IMASK-bit:
+ * Interrupt level mask
*/
-#define SR_FD 0x00008000
+#define SR_FD 0x00008000
+#define SR_IMASK 0x000000f0
-#define NUM_FPU_REGS 16
+/*
+ * FPU structure and data
+ */
struct sh_fpu_hard_struct {
- unsigned long fp_regs[NUM_FPU_REGS];
- unsigned long xf_regs[NUM_FPU_REGS];
+ unsigned long fp_regs[16];
+ unsigned long long xd_regs[8];
unsigned long fpscr;
unsigned long fpul;
@@ -75,13 +83,13 @@ struct sh_fpu_hard_struct {
/* Dummy fpu emulator */
struct sh_fpu_soft_struct {
- unsigned long fp_regs[NUM_FPU_REGS];
+ unsigned long fp_regs[16];
+ unsigned long long xd_regs[8];
unsigned long fpscr;
unsigned long fpul;
- unsigned long xf_regs[NUM_FPU_REGS];
- unsigned char lookahead;
- unsigned long entry_pc;
+ unsigned char lookahead;
+ unsigned long entry_pc;
};
union sh_fpu_union {
@@ -120,7 +128,7 @@ struct thread_struct {
regs->pr = 0; \
regs->sr = 0; /* User mode. */ \
regs->pc = new_pc; \
- regs->sp = new_sp
+ regs->regs[15] = new_sp
/* Forward declaration, a strange C thing */
struct task_struct;
@@ -189,6 +197,9 @@ extern void save_fpu(struct task_struct *__tsk);
(tsk)->flags &= ~PF_USEDFPU; \
} while (0)
+/* Double presision, NANS as NANS, rounding to nearest, no exceptions */
+#define FPSCR_INIT 0x00080000
+
/*
* Return saved PC of a blocked thread.
*/
diff --git a/include/asm-sh/ptrace.h b/include/asm-sh/ptrace.h
index ad3ab8905..369fc23bb 100644
--- a/include/asm-sh/ptrace.h
+++ b/include/asm-sh/ptrace.h
@@ -2,19 +2,49 @@
#define __ASM_SH_PTRACE_H
/*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999, 2000 Niibe Yutaka
*
*/
/*
+ * As GCC does:
+ * 0 - 15 are integer registers
+ * 17 - 22 are control/special registers
+ * 24 - 39 fp registers
+ * 40 - 47 xd registers
+ * 48 - fpscr register
+ * -----------------------------
+ * Not as GCC:
+ * 16 --- program counter PC
+ * 23 --- syscall #
+ */
+#define REG_REG0 0
+#define REG_REG15 15
+#define REG_PC 16
+
+#define REG_PR 17
+#define REG_SR 18
+#define REG_GBR 19
+#define REG_MACH 20
+#define REG_MACL 21
+#define REG_FPUL 22
+
+#define REG_SYSCALL 23
+
+#define REG_FPREG0 24
+#define REG_FPREG15 39
+#define REG_XDREG0 40
+#define REG_XDREG14 47
+#define REG_FPSCR 48
+
+/*
* This struct defines the way the registers are stored on the
* kernel stack during a system call or other kernel entry.
*/
struct pt_regs {
long syscall_nr;
unsigned long sr;
- unsigned long sp;
- unsigned long regs[15];
+ unsigned long regs[16];
unsigned long gbr;
unsigned long mach;
unsigned long macl;
@@ -26,6 +56,60 @@ struct pt_regs {
#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
#define instruction_pointer(regs) ((regs)->pc)
extern void show_regs(struct pt_regs *);
+
+/* User Break Controller */
+
+#if defined(__sh3__)
+/* The value is for sh4, please fix... */
+#define UBC_BARA 0xff200000
+#define UBC_BAMRA 0xff200004
+#define UBC_BBRA 0xff200008
+#define UBC_BASRA 0xff000014
+#define UBC_BARB 0xff20000c
+#define UBC_BAMRB 0xff200010
+#define UBC_BBRB 0xff200014
+#define UBC_BASRB 0xff000018
+#define UBC_BDRB 0xff200018
+#define UBC_BDMRB 0xff20001c
+#define UBC_BRCR 0xff200020
+#elif defined(__SH4__)
+#define UBC_BARA 0xff200000
+#define UBC_BAMRA 0xff200004
+#define UBC_BBRA 0xff200008
+#define UBC_BASRA 0xff000014
+#define UBC_BARB 0xff20000c
+#define UBC_BAMRB 0xff200010
+#define UBC_BBRB 0xff200014
+#define UBC_BASRB 0xff000018
+#define UBC_BDRB 0xff200018
+#define UBC_BDMRB 0xff20001c
+#define UBC_BRCR 0xff200020
+#endif
+
+#define BAMR_ASID (1 << 2)
+#define BAMR_NONE 0
+#define BAMR_10 0x1
+#define BAMR_12 0x2
+#define BAMR_ALL 0x3
+#define BAMR_16 0x8
+#define BAMR_20 0x9
+
+#define BBR_INST (1 << 4)
+#define BBR_DATA (2 << 4)
+#define BBR_READ (1 << 2)
+#define BBR_WRITE (2 << 4)
+#define BBR_BYTE 0x1
+#define BBR_HALF 0x2
+#define BBR_LONG 0x3
+#define BBR_QUAD (1 << 6)
+
+#define BRCR_CMFA (1 << 15)
+#define BRCR_CMFB (1 << 14)
+#define BRCR_PCBA (1 << 10) /* 1: after execution */
+#define BRCR_DBEB (1 << 7)
+#define BRCR_PCBB (1 << 6)
+#define BRCR_SEQ (1 << 3)
+#define BRCR_UBDE (1 << 0)
#endif
#endif /* __ASM_SH_PTRACE_H */
diff --git a/include/asm-sh/sigcontext.h b/include/asm-sh/sigcontext.h
index c1a77873b..6f61ed38c 100644
--- a/include/asm-sh/sigcontext.h
+++ b/include/asm-sh/sigcontext.h
@@ -5,14 +5,22 @@ struct sigcontext {
unsigned long oldmask;
/* CPU registers */
- unsigned long sc_regs[15];
+ unsigned long sc_regs[16];
unsigned long sc_gbr;
unsigned long sc_mach;
unsigned long sc_macl;
unsigned long sc_pr;
- unsigned long sc_sp;
unsigned long sc_sr;
unsigned long sc_pc;
+
+#if defined(__SH4__)
+ /* FPU registers */
+ unsigned long sc_fpregs[16];
+ unsigned long long sc_xdregs[8];
+ unsigned int sc_fpscr;
+ unsigned int sc_fpul;
+ unsigned int sc_ownedfp;
+#endif
};
#endif /* __ASM_SH_SIGCONTEXT_H */
diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h
index bcff30489..3eab1c123 100644
--- a/include/asm-sh/string.h
+++ b/include/asm-sh/string.h
@@ -13,11 +13,11 @@ extern __inline__ char *strcpy(char *__dest, const char *__src)
unsigned long __dummy;
__asm__ __volatile__("1:\n\t"
- "mov.b @%1+,%2\n\t"
- "mov.b %2,@%0\n\t"
- "cmp/eq #0,%2\n\t"
+ "mov.b @%1+, %2\n\t"
+ "mov.b %2, @%0\n\t"
+ "cmp/eq #0, %2\n\t"
"bf/s 1b\n\t"
- " add #1,%0\n\t"
+ " add #1, %0\n\t"
: "=r" (__dest), "=r" (__src), "=&z" (__dummy)
: "0" (__dest), "1" (__src)
: "memory");
@@ -36,13 +36,13 @@ extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
__asm__ __volatile__(
"1:\n"
- "mov.b @%1+,%2\n\t"
- "mov.b %2,@%0\n\t"
- "cmp/eq #0,%2\n\t"
+ "mov.b @%1+, %2\n\t"
+ "mov.b %2, @%0\n\t"
+ "cmp/eq #0, %2\n\t"
"bt/s 2f\n\t"
" cmp/eq %5,%1\n\t"
"bf/s 1b\n\t"
- " add #1,%0\n"
+ " add #1, %0\n"
"2:"
: "=r" (__dest), "=r" (__src), "=&z" (__dummy)
: "0" (__dest), "1" (__src), "r" (__src+__n)
@@ -58,17 +58,17 @@ extern __inline__ int strcmp(const char *__cs, const char *__ct)
unsigned long __dummy;
__asm__ __volatile__(
- "mov.b @%1+,%3\n"
+ "mov.b @%1+, %3\n"
"1:\n\t"
- "mov.b @%0+,%2\n\t"
- "cmp/eq #0,%3\n\t"
+ "mov.b @%0+, %2\n\t"
+ "cmp/eq #0, %3\n\t"
"bt 2f\n\t"
- "cmp/eq %2,%3\n\t"
+ "cmp/eq %2, %3\n\t"
"bt/s 1b\n\t"
- " mov.b @%1+,%3\n\t"
- "add #-2,%1\n\t"
- "mov.b @%1,%3\n\t"
- "sub %3,%2\n"
+ " mov.b @%1+, %3\n\t"
+ "add #-2, %1\n\t"
+ "mov.b @%1, %3\n\t"
+ "sub %3, %2\n"
"2:"
: "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
: "0" (__cs), "1" (__ct));
@@ -83,20 +83,20 @@ extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
unsigned long __dummy;
__asm__ __volatile__(
- "mov.b @%1+,%3\n"
+ "mov.b @%1+, %3\n"
"1:\n\t"
- "mov.b @%0+,%2\n\t"
- "cmp/eq %6,%0\n\t"
+ "mov.b @%0+, %2\n\t"
+ "cmp/eq %6, %0\n\t"
"bt/s 2f\n\t"
- " cmp/eq #0,%3\n\t"
+ " cmp/eq #0, %3\n\t"
"bt/s 3f\n\t"
- " cmp/eq %3,%2\n\t"
+ " cmp/eq %3, %2\n\t"
"bt/s 1b\n\t"
- " mov.b @%1+,%3\n\t"
- "add #-2,%1\n\t"
- "mov.b @%1,%3\n"
+ " mov.b @%1+, %3\n\t"
+ "add #-2, %1\n\t"
+ "mov.b @%1, %3\n"
"2:\n\t"
- "sub %3,%2\n"
+ "sub %3, %2\n"
"3:"
:"=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy)
: "0" (__cs), "1" (__ct), "r" (__cs+__n));
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index e76071bf2..130800b47 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -2,7 +2,7 @@
#define __ASM_SH_SYSTEM_H
/*
- * Copyright (C) 1999, 2000 Niibe Yutaka
+ * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
*/
/*
@@ -93,13 +93,15 @@ extern void __xchg_called_with_bad_pointer(void);
/* Interrupt Control */
extern __inline__ void __sti(void)
{
- unsigned long __dummy;
+ unsigned long __dummy0, __dummy1;
__asm__ __volatile__("stc $sr, %0\n\t"
"and %1, %0\n\t"
+ "stc $r5_bank, %1\n\t"
+ "or %1, %0\n\t"
"ldc %0, $sr"
- : "=&r" (__dummy)
- : "r" (0xefffffff)
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~0xf0)
: "memory");
}
@@ -107,10 +109,10 @@ extern __inline__ void __cli(void)
{
unsigned long __dummy;
__asm__ __volatile__("stc $sr, %0\n\t"
- "or %1, %0\n\t"
+ "or #0xf0, %0\n\t"
"ldc %0, $sr"
- : "=&r" (__dummy)
- : "r" (0x10000000)
+ : "=&z" (__dummy)
+ : /* no inputs */
: "memory");
}
@@ -118,35 +120,72 @@ extern __inline__ void __cli(void)
x = (__extension__ ({ unsigned long __sr; \
__asm__ __volatile__( \
"stc $sr, %0" \
- : "=r" (__sr) \
+ : "=&r" (__sr) \
: /* no inputs */ \
: "memory"); \
- (__sr & 0xffff7f0f);}))
+ (__sr & 0x000000f0);}))
#define __save_and_cli(x) \
x = (__extension__ ({ unsigned long __dummy,__sr; \
__asm__ __volatile__( \
"stc $sr, %1\n\t" \
- "or %0, %1\n\t" \
- "stc $sr, %0\n\t" \
- "ldc %1, $sr" \
- : "=r" (__sr), "=&r" (__dummy) \
- : "0" (0x10000000) \
- : "memory"); (__sr & 0xffff7f0f); }))
+ "mov %1, %0\n\t" \
+ "or #0xf0, %0\n\t" \
+ "ldc %0, $sr" \
+ : "=&z" (__dummy), "=&r" (__sr) \
+ : /* no inputs */ \
+ : "memory"); (__sr & 0x000000f0); }))
#define __restore_flags(x) do { \
- unsigned long __dummy; \
- __asm__ __volatile__( \
+ unsigned long __dummy0, __dummy1; \
+ if (x != 0xf0) /* not CLI-ed? */ \
+ __asm__ __volatile__( \
"stc $sr, %0\n\t" \
"and %1, %0\n\t" \
- "or %2, %0\n\t" \
+ "stc $r5_bank, %1\n\t" \
+ "or %1, %0\n\t" \
"ldc %0, $sr" \
- : "=&r" (__dummy) \
- : "r" (0x000080f0), /* IMASK+FD */ \
- "r" (x) \
+ : "=&r" (__dummy0), "=r" (__dummy1) \
+ : "1" (0xffffff0f) \
: "memory"); \
} while (0)
+/*
+ * Jump to P2 area.
+ * When handling TLB or caches, we need to do it from P2 area.
+ */
+#define jump_to_P2() \
+do { \
+ unsigned long __dummy; \
+ __asm__ __volatile__( \
+ "mov.l 1f, %0\n\t" \
+ "or %1, %0\n\t" \
+ "jmp @%0\n\t" \
+ " nop\n\t" \
+ ".balign 4\n" \
+ "1: .long 2f\n" \
+ "2:" \
+ : "=&r" (__dummy) \
+ : "r" (0x20000000)); \
+} while (0)
+
+/*
+ * Back to P1 area.
+ */
+#define back_to_P1() \
+do { \
+ unsigned long __dummy; \
+ __asm__ __volatile__( \
+ "nop;nop;nop;nop;nop;nop\n\t" \
+ "mov.l 1f, %0\n\t" \
+ "jmp @%0\n\t" \
+ " nop\n\t" \
+ ".balign 4\n" \
+ "1: .long 2f\n" \
+ "2:" \
+ : "=&r" (__dummy)); \
+} while (0)
+
/* For spinlocks etc */
#define local_irq_save(x) __save_and_cli(x)
#define local_irq_restore(x) __restore_flags(x)
diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
index b64de2cd5..65ed58fd8 100644
--- a/include/asm-sh/uaccess.h
+++ b/include/asm-sh/uaccess.h
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.6 1999/10/29 13:10:44 gniibe Exp $
+/* $Id: uaccess.h,v 1.10 2000/03/24 13:53:45 gniibe Exp $
*
* User space memory access functions
*
@@ -47,7 +47,7 @@
*/
#define __range_ok(addr,size) ({ \
unsigned long flag,sum; \
- __asm__("clrt; addc %3,%1; movt %0; cmp/hi %4,%1; rotcl %0" \
+ __asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0" \
:"=&r" (flag), "=r" (sum) \
:"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg)); \
flag; })
@@ -137,17 +137,17 @@ default: __get_user_unknown(); break; \
({ \
__asm__ __volatile__( \
"1:\n\t" \
- "mov." insn " %2,%1\n\t" \
- "mov #0,%0\n" \
- "2:\n\t" \
+ "mov." insn " %2, %1\n\t" \
+ "mov #0, %0\n" \
+ "2:\n" \
".section .fixup,\"ax\"\n" \
"3:\n\t" \
- "mov #0,%1\n\t" \
- "mov.l 4f,%0\n\t" \
+ "mov #0, %1\n\t" \
+ "mov.l 4f, %0\n\t" \
"jmp @%0\n\t" \
- " mov %3,%0\n" \
+ " mov %3, %0\n" \
"4: .long 2b\n\t" \
- ".previous\n\t" \
+ ".previous\n" \
".section __ex_table,\"a\"\n\t" \
".long 1b, 3b\n\t" \
".previous" \
@@ -189,17 +189,17 @@ default: __put_user_unknown(); break; \
({ \
__asm__ __volatile__( \
"1:\n\t" \
- "mov." insn " %1,%2\n\t" \
- "mov #0,%0\n" \
- "2:\n\t" \
+ "mov." insn " %1, %2\n\t" \
+ "mov #0, %0\n" \
+ "2:\n" \
".section .fixup,\"ax\"\n" \
"3:\n\t" \
"nop\n\t" \
- "mov.l 4f,%0\n\t" \
+ "mov.l 4f, %0\n\t" \
"jmp @%0\n\t" \
- "mov %3,%0\n" \
+ "mov %3, %0\n" \
"4: .long 2b\n\t" \
- ".previous\n\t" \
+ ".previous\n" \
".section __ex_table,\"a\"\n\t" \
".long 1b, 3b\n\t" \
".previous" \
@@ -218,18 +218,18 @@ __copy_user(void *__to, const void *__from, __kernel_size_t __n)
__asm__ __volatile__(
"9:\n\t"
- "mov.b @%2+,%1\n\t"
+ "mov.b @%2+, %1\n\t"
"dt %0\n"
"1:\n\t"
- "mov.b %1,@%3\n\t"
+ "mov.b %1, @%3\n\t"
"bf/s 9b\n\t"
- " add #1,%3\n"
- "2:"
+ " add #1, %3\n"
+ "2:\n"
".section .fixup,\"ax\"\n"
"3:\n\t"
- "mov.l 5f,%1\n\t"
+ "mov.l 5f, %1\n\t"
"jmp @%1\n\t"
- " mov %7,%0\n\t"
+ " mov %7, %0\n\t"
".balign 4\n"
"5: .long 2b\n"
".previous\n"
@@ -238,7 +238,7 @@ __copy_user(void *__to, const void *__from, __kernel_size_t __n)
" .long 9b,3b\n"
" .long 1b,2b\n"
".previous"
- : "=&r" (res), "=&z" (__dummy), "=&r" (_f), "=&r" (_t)
+ : "=r" (res), "=&z" (__dummy), "=r" (_f), "=r" (_t)
: "2" (__from), "3" (__to), "0" (__n), "i" (-EFAULT)
: "memory");
@@ -297,23 +297,21 @@ if (__copy_from_user(to,from,n)) \
extern __inline__ __kernel_size_t
__clear_user(void *addr, __kernel_size_t size)
{
- __kernel_size_t res;
- unsigned long __a, __s;
+ unsigned long __a;
__asm__ __volatile__(
"9:\n\t"
- "dt %2\n"
+ "dt %0\n"
"1:\n\t"
- "mov.b %5,@%1\n\t"
+ "mov.b %4, @%1\n\t"
"bf/s 9b\n\t"
- " add #1,%1\n\t"
- "sub %2,%0\n"
+ " add #1, %1\n"
"2:\n"
".section .fixup,\"ax\"\n"
"3:\n\t"
- "mov.l 4f,%0\n\t"
- "jmp @%0\n\t"
- " mov %7,%0\n"
+ "mov.l 4f, %1\n\t"
+ "jmp @%1\n\t"
+ " nop\n"
".balign 4\n"
"4: .long 2b\n"
".previous\n"
@@ -321,10 +319,10 @@ __clear_user(void *addr, __kernel_size_t size)
" .balign 4\n"
" .long 1b,3b\n"
".previous"
- : "=&r" (res), "=&r" (__a), "=&r" (__s)
- : "1" (addr), "2" (size), "r" (0), "0" (size), "i" (-EFAULT));
+ : "=r" (size), "=r" (__a)
+ : "0" (size), "1" (addr), "r" (0));
- return res;
+ return size;
}
#define clear_user(addr,n) ({ \
@@ -342,31 +340,31 @@ __strncpy_from_user(unsigned long __dest, unsigned long __src, int __count)
__asm__ __volatile__(
"9:\n"
- "mov.b @%2+,%1\n\t"
- "cmp/eq #0,%1\n\t"
+ "mov.b @%2+, %1\n\t"
+ "cmp/eq #0, %1\n\t"
"bt/s 2f\n"
"1:\n"
- "mov.b %1,@%3\n\t"
- "dt %0\n\t"
+ "mov.b %1, @%3\n\t"
+ "dt %7\n\t"
"bf/s 9b\n\t"
- " add #1,%3\n\t"
- "sub %6,%0\n"
- "2:\n"
+ " add #1, %3\n\t"
+ "2:\n\t"
+ "sub %7, %0\n"
+ "3:\n"
".section .fixup,\"ax\"\n"
- "3:\n\t"
- "mov.l 4f,%1\n\t"
+ "4:\n\t"
+ "mov.l 5f, %1\n\t"
"jmp @%1\n\t"
- " mov %8,%0\n\t"
+ " mov %8, %0\n\t"
".balign 4\n"
- "4: .long 2b\n"
+ "5: .long 3b\n"
".previous\n"
".section __ex_table,\"a\"\n"
" .balign 4\n"
- " .long 9b,3b\n"
- " .long 1b,2b\n"
+ " .long 9b,4b\n"
".previous"
- : "=&r" (res), "=&z" (__dummy), "=&r" (_s), "=&r" (_d)
- : "2" (__src), "3" (__dest), "r" (__count), "0" (__count),
+ : "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d)
+ : "0" (__count), "2" (__src), "3" (__dest), "r" (__count),
"i" (-EFAULT)
: "memory");
@@ -393,19 +391,19 @@ extern __inline__ long __strnlen_user(const char *__s, long __n)
__asm__ __volatile__(
"9:\n"
- "cmp/eq %4,%0\n\t"
+ "cmp/eq %4, %0\n\t"
"bt 2f\n"
"1:\t"
- "mov.b @(%0,%3),%1\n\t"
- "tst %1,%1\n\t"
+ "mov.b @(%0,%3), %1\n\t"
+ "tst %1, %1\n\t"
"bf/s 9b\n\t"
- " add #1,%0\n"
+ " add #1, %0\n"
"2:\n"
".section .fixup,\"ax\"\n"
"3:\n\t"
- "mov.l 4f,%1\n\t"
+ "mov.l 4f, %1\n\t"
"jmp @%1\n\t"
- " mov %5,%0\n"
+ " mov %5, %0\n"
".balign 4\n"
"4: .long 2b\n"
".previous\n"
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 20f5f659b..baaff1798 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -227,6 +227,8 @@
#define __NR_setfsuid32 215
#define __NR_setfsgid32 216
#define __NR_pivot_root 217
+#define __NR_mincore 218
+#define __NR_madvise 219
/* user-visible error numbers are in the range -1 - -125: see <asm-sh/errno.h> */
diff --git a/include/asm-sh/user.h b/include/asm-sh/user.h
index 243cc04fd..6888368aa 100644
--- a/include/asm-sh/user.h
+++ b/include/asm-sh/user.h
@@ -30,16 +30,16 @@
*/
struct user_fpu_struct {
- unsigned long fp_regs[NUM_FPU_REGS];
- unsigned long xf_regs[NUM_FPU_REGS];
+ unsigned long fp_regs[16];
+ unsigned long long xd_regs[8];
unsigned long fpscr;
unsigned long fpul;
};
struct user {
struct pt_regs regs; /* entire machine state */
- struct user_fpu_struct fpu; /* Math Co-processor registers. */
- int u_fpvalid; /* True if math co-processor being used. */
+ struct user_fpu_struct fpu; /* Math Co-processor registers */
+ int u_fpvalid; /* True if math co-processor being used */
size_t u_tsize; /* text size (pages) */
size_t u_dsize; /* data size (pages) */
size_t u_ssize; /* stack size (pages) */
@@ -48,7 +48,7 @@ struct user {
unsigned long start_stack; /* stack starting address */
long int signal; /* signal causing core dump */
struct regs * u_ar0; /* help gdb find registers */
- struct user_fpu_struct* u_fpstate; /* Math Co-processor pointer. */
+ struct user_fpu_struct* u_fpstate; /* Math Co-processor pointer */
unsigned long magic; /* identifies a core file */
char u_comm[32]; /* user command name */
};
diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h
index 71610a59f..cafd68674 100644
--- a/include/asm-sparc/io.h
+++ b/include/asm-sparc/io.h
@@ -1,5 +1,5 @@
/*
- * $Id: io.h,v 1.25 2000/01/22 07:35:46 zaitcev Exp $
+ * $Id: io.h,v 1.26 2000/03/30 01:43:26 davem Exp $
*/
#ifndef __SPARC_IO_H
#define __SPARC_IO_H
@@ -49,6 +49,31 @@ extern __inline__ void writel(unsigned int b, unsigned long addr) {
*(volatile unsigned long*)addr = flip_dword(b);
}
+/* Now the 'raw' versions. */
+extern __inline__ unsigned long __raw_readb(unsigned long addr) {
+ return *(volatile unsigned char*)addr;
+}
+
+extern __inline__ unsigned long __raw_readw(unsigned long addr) {
+ return *(volatile unsigned short*)addr;
+}
+
+extern __inline__ unsigned long __raw_readl(unsigned long addr) {
+ return *(volatile unsigned long*)addr;
+}
+
+extern __inline__ void __raw_writeb(unsigned char b, unsigned long addr) {
+ *(volatile unsigned char*)addr = b;
+}
+
+extern __inline__ void __raw_writew(unsigned short b, unsigned long addr) {
+ *(volatile unsigned short*)addr = b;
+}
+
+extern __inline__ void __raw_writel(unsigned int b, unsigned long addr) {
+ *(volatile unsigned long*)addr = b;
+}
+
/*
* I/O space operations
*
diff --git a/include/asm-sparc/namei.h b/include/asm-sparc/namei.h
index 89cd1c3a9..18430c8d1 100644
--- a/include/asm-sparc/namei.h
+++ b/include/asm-sparc/namei.h
@@ -11,53 +11,16 @@
#define SPARC_BSD_EMUL "usr/gnemul/sunos/"
#define SPARC_SOL_EMUL "usr/gnemul/solaris/"
-static inline struct dentry *
-__sparc_lookup_dentry(const char *name, int lookup_flags)
+static inline char * __emul_prefix(void)
{
- struct dentry *base;
- char *emul;
-
switch (current->personality) {
case PER_BSD:
- emul = SPARC_BSD_EMUL; break;
+ return SPARC_BSD_EMUL;
case PER_SVR4:
- emul = SPARC_SOL_EMUL; break;
+ return SPARC_SOL_EMUL;
default:
return NULL;
}
-
- base = lookup_dentry (emul,
- dget (current->fs->root),
- (LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
-
- if (IS_ERR (base)) return NULL;
-
- base = lookup_dentry (name, base, lookup_flags);
-
- if (IS_ERR (base)) return NULL;
-
- if (!base->d_inode) {
- struct dentry *fromroot;
-
- fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
-
- if (IS_ERR (fromroot)) return base;
-
- if (fromroot->d_inode) {
- dput(base);
- return fromroot;
- }
-
- dput(fromroot);
- }
-
- return base;
}
-#define __prefix_lookup_dentry(name, lookup_flags) \
- if (current->personality) { \
- dentry = __sparc_lookup_dentry (name, lookup_flags); \
- if (dentry) return dentry; \
- }
-
#endif /* __SPARC_NAMEI_H */
diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h
index 0fc2aa247..379c8cc97 100644
--- a/include/asm-sparc/page.h
+++ b/include/asm-sparc/page.h
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.51 2000/03/15 07:19:25 davem Exp $
+/* $Id: page.h,v 1.52 2000/03/28 06:07:25 anton Exp $
* page.h: Various defines and such for MMU operations on the Sparc for
* the Linux kernel.
*
@@ -32,11 +32,20 @@
#ifndef __ASSEMBLY__
-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
-
-#define PAGE_BUG(page) do { \
- BUG(); \
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+/* We need the mb()'s so we don't trigger a compiler bug - Anton */
+#define BUG() do { \
+ mb(); \
+ __builtin_trap(); \
+ mb(); \
+} while(0)
+#else
+#define BUG() do { \
+ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; \
} while (0)
+#endif
+
+#define PAGE_BUG(page) BUG()
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index 8925923b0..04b34e5e9 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.93 2000/03/21 01:04:53 anton Exp $ */
+/* $Id: pgtable.h,v 1.94 2000/03/28 06:07:25 anton Exp $ */
#ifndef _SPARC_PGTABLE_H
#define _SPARC_PGTABLE_H
@@ -96,12 +96,18 @@ BTFIXUPDEF_SIMM13(user_ptrs_per_pgd)
#define VMALLOC_START (0xfe300000)
#define VMALLOC_END ~0x0UL
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+#define pte_ERROR(e) __builtin_trap()
+#define pmd_ERROR(e) __builtin_trap()
+#define pgd_ERROR(e) __builtin_trap()
+#else
#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))
+#endif
BTFIXUPDEF_INT(page_none)
BTFIXUPDEF_INT(page_shared)
diff --git a/include/asm-sparc64/asm_offsets.h b/include/asm-sparc64/asm_offsets.h
index 3ed7dd760..8a5eb1246 100644
--- a/include/asm-sparc64/asm_offsets.h
+++ b/include/asm-sparc64/asm_offsets.h
@@ -266,33 +266,39 @@
#define ASIZ_thread_w_saved 0x00000001
#define AOFF_thread_fpdepth 0x0000000d
#define ASIZ_thread_fpdepth 0x00000001
-#define AOFF_thread_fpsaved 0x0000000e
+#define AOFF_thread_fault_code 0x0000000e
+#define ASIZ_thread_fault_code 0x00000001
+#define AOFF_thread_use_blkcommit 0x0000000f
+#define ASIZ_thread_use_blkcommit 0x00000001
+#define AOFF_thread_fault_address 0x00000010
+#define ASIZ_thread_fault_address 0x00000008
+#define AOFF_thread_fpsaved 0x00000018
#define ASIZ_thread_fpsaved 0x00000007
-#define AOFF_thread___pad1 0x00000015
-#define ASIZ_thread___pad1 0x00000003
-#define AOFF_thread_kregs 0x00000018
+#define AOFF_thread___pad2 0x0000001f
+#define ASIZ_thread___pad2 0x00000001
+#define AOFF_thread_kregs 0x00000020
#define ASIZ_thread_kregs 0x00000008
-#define AOFF_thread_utraps 0x00000020
+#define AOFF_thread_utraps 0x00000028
#define ASIZ_thread_utraps 0x00000008
-#define AOFF_thread_gsr 0x00000028
+#define AOFF_thread_gsr 0x00000030
#define ASIZ_thread_gsr 0x00000007
-#define AOFF_thread___pad2 0x0000002f
-#define ASIZ_thread___pad2 0x00000001
-#define AOFF_thread_xfsr 0x00000030
+#define AOFF_thread___pad3 0x00000037
+#define ASIZ_thread___pad3 0x00000001
+#define AOFF_thread_xfsr 0x00000038
#define ASIZ_thread_xfsr 0x00000038
-#define AOFF_thread_reg_window 0x00000068
+#define AOFF_thread_reg_window 0x00000070
#define ASIZ_thread_reg_window 0x00000380
-#define AOFF_thread_rwbuf_stkptrs 0x000003e8
+#define AOFF_thread_rwbuf_stkptrs 0x000003f0
#define ASIZ_thread_rwbuf_stkptrs 0x00000038
-#define AOFF_thread_user_cntd0 0x00000420
+#define AOFF_thread_user_cntd0 0x00000428
#define ASIZ_thread_user_cntd0 0x00000008
-#define AOFF_thread_user_cntd1 0x00000428
+#define AOFF_thread_user_cntd1 0x00000430
#define ASIZ_thread_user_cntd1 0x00000008
-#define AOFF_thread_kernel_cntd0 0x00000430
+#define AOFF_thread_kernel_cntd0 0x00000438
#define ASIZ_thread_kernel_cntd0 0x00000008
-#define AOFF_thread_kernel_cntd1 0x00000438
+#define AOFF_thread_kernel_cntd1 0x00000440
#define ASIZ_thread_kernel_cntd1 0x00000008
-#define AOFF_thread_pcr_reg 0x00000440
+#define AOFF_thread_pcr_reg 0x00000448
#define ASIZ_thread_pcr_reg 0x00000008
#define ASIZ_thread 0x00000450
@@ -554,33 +560,39 @@
#define ASIZ_thread_w_saved 0x00000001
#define AOFF_thread_fpdepth 0x0000000d
#define ASIZ_thread_fpdepth 0x00000001
-#define AOFF_thread_fpsaved 0x0000000e
+#define AOFF_thread_fault_code 0x0000000e
+#define ASIZ_thread_fault_code 0x00000001
+#define AOFF_thread_use_blkcommit 0x0000000f
+#define ASIZ_thread_use_blkcommit 0x00000001
+#define AOFF_thread_fault_address 0x00000010
+#define ASIZ_thread_fault_address 0x00000008
+#define AOFF_thread_fpsaved 0x00000018
#define ASIZ_thread_fpsaved 0x00000007
-#define AOFF_thread___pad1 0x00000015
-#define ASIZ_thread___pad1 0x00000003
-#define AOFF_thread_kregs 0x00000018
+#define AOFF_thread___pad2 0x0000001f
+#define ASIZ_thread___pad2 0x00000001
+#define AOFF_thread_kregs 0x00000020
#define ASIZ_thread_kregs 0x00000008
-#define AOFF_thread_utraps 0x00000020
+#define AOFF_thread_utraps 0x00000028
#define ASIZ_thread_utraps 0x00000008
-#define AOFF_thread_gsr 0x00000028
+#define AOFF_thread_gsr 0x00000030
#define ASIZ_thread_gsr 0x00000007
-#define AOFF_thread___pad2 0x0000002f
-#define ASIZ_thread___pad2 0x00000001
-#define AOFF_thread_xfsr 0x00000030
+#define AOFF_thread___pad3 0x00000037
+#define ASIZ_thread___pad3 0x00000001
+#define AOFF_thread_xfsr 0x00000038
#define ASIZ_thread_xfsr 0x00000038
-#define AOFF_thread_reg_window 0x00000068
+#define AOFF_thread_reg_window 0x00000070
#define ASIZ_thread_reg_window 0x00000380
-#define AOFF_thread_rwbuf_stkptrs 0x000003e8
+#define AOFF_thread_rwbuf_stkptrs 0x000003f0
#define ASIZ_thread_rwbuf_stkptrs 0x00000038
-#define AOFF_thread_user_cntd0 0x00000420
+#define AOFF_thread_user_cntd0 0x00000428
#define ASIZ_thread_user_cntd0 0x00000008
-#define AOFF_thread_user_cntd1 0x00000428
+#define AOFF_thread_user_cntd1 0x00000430
#define ASIZ_thread_user_cntd1 0x00000008
-#define AOFF_thread_kernel_cntd0 0x00000430
+#define AOFF_thread_kernel_cntd0 0x00000438
#define ASIZ_thread_kernel_cntd0 0x00000008
-#define AOFF_thread_kernel_cntd1 0x00000438
+#define AOFF_thread_kernel_cntd1 0x00000440
#define ASIZ_thread_kernel_cntd1 0x00000008
-#define AOFF_thread_pcr_reg 0x00000440
+#define AOFF_thread_pcr_reg 0x00000448
#define ASIZ_thread_pcr_reg 0x00000008
#define ASIZ_thread 0x00000450
@@ -840,33 +852,39 @@
#define ASIZ_thread_w_saved 0x00000001
#define AOFF_thread_fpdepth 0x0000000d
#define ASIZ_thread_fpdepth 0x00000001
-#define AOFF_thread_fpsaved 0x0000000e
+#define AOFF_thread_fault_code 0x0000000e
+#define ASIZ_thread_fault_code 0x00000001
+#define AOFF_thread_use_blkcommit 0x0000000f
+#define ASIZ_thread_use_blkcommit 0x00000001
+#define AOFF_thread_fault_address 0x00000010
+#define ASIZ_thread_fault_address 0x00000008
+#define AOFF_thread_fpsaved 0x00000018
#define ASIZ_thread_fpsaved 0x00000007
-#define AOFF_thread___pad1 0x00000015
-#define ASIZ_thread___pad1 0x00000003
-#define AOFF_thread_kregs 0x00000018
+#define AOFF_thread___pad2 0x0000001f
+#define ASIZ_thread___pad2 0x00000001
+#define AOFF_thread_kregs 0x00000020
#define ASIZ_thread_kregs 0x00000008
-#define AOFF_thread_utraps 0x00000020
+#define AOFF_thread_utraps 0x00000028
#define ASIZ_thread_utraps 0x00000008
-#define AOFF_thread_gsr 0x00000028
+#define AOFF_thread_gsr 0x00000030
#define ASIZ_thread_gsr 0x00000007
-#define AOFF_thread___pad2 0x0000002f
-#define ASIZ_thread___pad2 0x00000001
-#define AOFF_thread_xfsr 0x00000030
+#define AOFF_thread___pad3 0x00000037
+#define ASIZ_thread___pad3 0x00000001
+#define AOFF_thread_xfsr 0x00000038
#define ASIZ_thread_xfsr 0x00000038
-#define AOFF_thread_reg_window 0x00000068
+#define AOFF_thread_reg_window 0x00000070
#define ASIZ_thread_reg_window 0x00000380
-#define AOFF_thread_rwbuf_stkptrs 0x000003e8
+#define AOFF_thread_rwbuf_stkptrs 0x000003f0
#define ASIZ_thread_rwbuf_stkptrs 0x00000038
-#define AOFF_thread_user_cntd0 0x00000420
+#define AOFF_thread_user_cntd0 0x00000428
#define ASIZ_thread_user_cntd0 0x00000008
-#define AOFF_thread_user_cntd1 0x00000428
+#define AOFF_thread_user_cntd1 0x00000430
#define ASIZ_thread_user_cntd1 0x00000008
-#define AOFF_thread_kernel_cntd0 0x00000430
+#define AOFF_thread_kernel_cntd0 0x00000438
#define ASIZ_thread_kernel_cntd0 0x00000008
-#define AOFF_thread_kernel_cntd1 0x00000438
+#define AOFF_thread_kernel_cntd1 0x00000440
#define ASIZ_thread_kernel_cntd1 0x00000008
-#define AOFF_thread_pcr_reg 0x00000440
+#define AOFF_thread_pcr_reg 0x00000448
#define ASIZ_thread_pcr_reg 0x00000008
#define ASIZ_thread 0x00000450
#endif /* SPIN_LOCK_DEBUG */
diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
index 6a6ec52b1..512d16410 100644
--- a/include/asm-sparc64/bitops.h
+++ b/include/asm-sparc64/bitops.h
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.27 2000/02/09 03:28:33 davem Exp $
+/* $Id: bitops.h,v 1.28 2000/03/27 10:38:56 davem Exp $
* bitops.h: Bit string operations on the V9.
*
* Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,132 +8,17 @@
#define _SPARC64_BITOPS_H
#include <asm/byteorder.h>
-#include <asm/asi.h> /* For the little endian spaces. */
-/* These can all be exported to userland, because the atomic
- * primitives used are not privileged.
- */
-
-/* Set bit 'nr' in 64-bit quantity at address 'addr' where bit '0'
- * is in the highest of the eight bytes and bit '63' is the high bit
- * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
- */
+extern long __test_and_set_bit(unsigned long nr, void *addr);
+extern long __test_and_clear_bit(unsigned long nr, void *addr);
+extern long __test_and_change_bit(unsigned long nr, void *addr);
-extern __inline__ int test_and_set_bit(unsigned long nr, void *addr)
-{
- unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
- unsigned long oldbit;
-
- __asm__ __volatile__("
-1: ldx [%2], %%g7
- andcc %%g7, %1, %0
- bne,pn %%xcc, 2f
- xor %%g7, %1, %%g5
- casx [%2], %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%xcc, 1b
- nop
-2:
-" : "=&r" (oldbit)
- : "HIr" (1UL << (nr & 63)), "r" (m)
- : "g5", "g7", "cc", "memory");
- return oldbit != 0;
-}
-
-extern __inline__ void set_bit(unsigned long nr, void *addr)
-{
- unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-
- __asm__ __volatile__("
-1: ldx [%1], %%g7
- andcc %%g7, %0, %%g0
- bne,pn %%xcc, 2f
- xor %%g7, %0, %%g5
- casx [%1], %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%xcc, 1b
- nop
-2:
-" : /* no outputs */
- : "HIr" (1UL << (nr & 63)), "r" (m)
- : "g5", "g7", "cc", "memory");
-}
-
-extern __inline__ int test_and_clear_bit(unsigned long nr, void *addr)
-{
- unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
- unsigned long oldbit;
-
- __asm__ __volatile__("
-1: ldx [%2], %%g7
- andcc %%g7, %1, %0
- be,pn %%xcc, 2f
- xor %%g7, %1, %%g5
- casx [%2], %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%xcc, 1b
- nop
-2:
-" : "=&r" (oldbit)
- : "HIr" (1UL << (nr & 63)), "r" (m)
- : "g5", "g7", "cc", "memory");
- return oldbit != 0;
-}
-
-extern __inline__ void clear_bit(unsigned long nr, void *addr)
-{
- unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-
- __asm__ __volatile__("
-1: ldx [%1], %%g7
- andcc %%g7, %0, %%g0
- be,pn %%xcc, 2f
- xor %%g7, %0, %%g5
- casx [%1], %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%xcc, 1b
- nop
-2:
-" : /* no outputs */
- : "HIr" (1UL << (nr & 63)), "r" (m)
- : "g5", "g7", "cc", "memory");
-}
-
-extern __inline__ int test_and_change_bit(unsigned long nr, void *addr)
-{
- unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
- unsigned long oldbit;
-
- __asm__ __volatile__("
-1: ldx [%2], %%g7
- and %%g7, %1, %0
- xor %%g7, %1, %%g5
- casx [%2], %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%xcc, 1b
- nop
-" : "=&r" (oldbit)
- : "HIr" (1UL << (nr & 63)), "r" (m)
- : "g5", "g7", "cc", "memory");
- return oldbit != 0;
-}
-
-extern __inline__ void change_bit(unsigned long nr, void *addr)
-{
- unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
-
- __asm__ __volatile__("
-1: ldx [%1], %%g7
- xor %%g7, %0, %%g5
- casx [%1], %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%xcc, 1b
- nop
-" : /* no outputs */
- : "HIr" (1UL << (nr & 63)), "r" (m)
- : "g5", "g7", "cc", "memory");
-}
+#define test_and_set_bit(nr,addr) (__test_and_set_bit(nr,addr)!=0)
+#define test_and_clear_bit(nr,addr) (__test_and_clear_bit(nr,addr)!=0)
+#define test_and_change_bit(nr,addr) (__test_and_change_bit(nr,addr)!=0)
+#define set_bit(nr,addr) ((void)__test_and_set_bit(nr,addr))
+#define clear_bit(nr,addr) ((void)__test_and_clear_bit(nr,addr))
+#define change_bit(nr,addr) ((void)__test_and_change_bit(nr,addr))
extern __inline__ int test_bit(int nr, __const__ void *addr)
{
@@ -280,50 +165,13 @@ found_middle:
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
-/* Now for the ext2 filesystem bit operations and helper routines.
- * Note the usage of the little endian ASI's, werd, V9 is supreme.
- */
-extern __inline__ int set_le_bit(int nr,void * addr)
-{
- unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
- unsigned long oldbit;
-
- __asm__ __volatile__("
-1: lduwa [%2] %3, %%g7
- andcc %%g7, %1, %0
- bne,pn %%icc, 2f
- xor %%g7, %1, %%g5
- casa [%2] %3, %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%icc, 1b
- nop
-2:
-" : "=&r" (oldbit)
- : "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
- : "g5", "g7", "cc", "memory");
- return oldbit != 0;
-}
-
-extern __inline__ int clear_le_bit(int nr, void * addr)
-{
- unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
- unsigned long oldbit;
+extern long __test_and_set_le_bit(int nr, void *addr);
+extern long __test_and_clear_le_bit(int nr, void *addr);
- __asm__ __volatile__("
-1: lduwa [%2] %3, %%g7
- andcc %%g7, %1, %0
- be,pn %%icc, 2f
- xor %%g7, %1, %%g5
- casa [%2] %3, %%g7, %%g5
- cmp %%g7, %%g5
- bne,pn %%icc, 1b
- nop
-2:
-" : "=&r" (oldbit)
- : "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
- : "g5", "g7", "cc", "memory");
- return oldbit != 0;
-}
+#define test_and_set_le_bit(nr,addr) (__test_and_set_le_bit(nr,addr)!=0)
+#define test_and_clear_le_bit(nr,addr) (__test_and_clear_le_bit(nr,addr)!=0)
+#define set_le_bit(nr,addr) ((void)__test_and_set_le_bit(nr,addr))
+#define clear_le_bit(nr,addr) ((void)__test_and_clear_le_bit(nr,addr))
extern __inline__ int test_le_bit(int nr, __const__ void * addr)
{
@@ -375,8 +223,8 @@ found_middle:
#ifdef __KERNEL__
-#define ext2_set_bit set_le_bit
-#define ext2_clear_bit clear_le_bit
+#define ext2_set_bit test_and_set_le_bit
+#define ext2_clear_bit test_and_clear_le_bit
#define ext2_test_bit test_le_bit
#define ext2_find_first_zero_bit find_first_zero_le_bit
#define ext2_find_next_zero_bit find_next_zero_le_bit
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index f8bdaa826..2ca3b4693 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.33 2000/02/25 05:47:38 davem Exp $ */
+/* $Id: io.h,v 1.34 2000/03/30 01:40:54 davem Exp $ */
#ifndef __SPARC64_IO_H
#define __SPARC64_IO_H
@@ -156,6 +156,68 @@ extern __inline__ void _writel(unsigned int l, unsigned long addr)
#define writew(__w, __addr) (_writew((__w), (unsigned long)(__addr)))
#define writel(__l, __addr) (_writel((__l), (unsigned long)(__addr)))
+/* Now versions without byte-swapping. */
+extern __inline__ unsigned int _raw_readb(unsigned long addr)
+{
+ unsigned int ret;
+
+ __asm__ __volatile__("lduba\t[%1] %2, %0\t/* pci_raw_readb */"
+ : "=r" (ret)
+ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+
+ return ret;
+}
+
+extern __inline__ unsigned int _raw_readw(unsigned long addr)
+{
+ unsigned int ret;
+
+ __asm__ __volatile__("lduha\t[%1] %2, %0\t/* pci_raw_readw */"
+ : "=r" (ret)
+ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+
+ return ret;
+}
+
+extern __inline__ unsigned int _raw_readl(unsigned long addr)
+{
+ unsigned int ret;
+
+ __asm__ __volatile__("lduwa\t[%1] %2, %0\t/* pci_raw_readl */"
+ : "=r" (ret)
+ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+
+ return ret;
+}
+
+extern __inline__ void _raw_writeb(unsigned char b, unsigned long addr)
+{
+ __asm__ __volatile__("stba\t%r0, [%1] %2\t/* pci_raw_writeb */"
+ : /* no outputs */
+ : "Jr" (b), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+extern __inline__ void _raw_writew(unsigned short w, unsigned long addr)
+{
+ __asm__ __volatile__("stha\t%r0, [%1] %2\t/* pci_raw_writew */"
+ : /* no outputs */
+ : "Jr" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+extern __inline__ void _raw_writel(unsigned int l, unsigned long addr)
+{
+ __asm__ __volatile__("stwa\t%r0, [%1] %2\t/* pci_raw_writel */"
+ : /* no outputs */
+ : "Jr" (l), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+#define __raw_readb(__addr) (_raw_readb((unsigned long)(__addr)))
+#define __raw_readw(__addr) (_raw_readw((unsigned long)(__addr)))
+#define __raw_readl(__addr) (_raw_readl((unsigned long)(__addr)))
+#define __raw_writeb(__b, __addr) (_raw_writeb((__b), (unsigned long)(__addr)))
+#define __raw_writew(__w, __addr) (_raw_writew((__w), (unsigned long)(__addr)))
+#define __raw_writel(__l, __addr) (_raw_writel((__l), (unsigned long)(__addr)))
+
/* Valid I/O Space regions are anywhere, because each PCI bus supported
* can live in an arbitrary area of the physical address range.
*/
diff --git a/include/asm-sparc64/namei.h b/include/asm-sparc64/namei.h
index d3d57545c..7f6dd9495 100644
--- a/include/asm-sparc64/namei.h
+++ b/include/asm-sparc64/namei.h
@@ -11,53 +11,16 @@
#define SPARC_BSD_EMUL "usr/gnemul/sunos/"
#define SPARC_SOL_EMUL "usr/gnemul/solaris/"
-static inline struct dentry *
-__sparc64_lookup_dentry(const char *name, int lookup_flags)
+static inline char * __emul_prefix(void)
{
- struct dentry *base;
- char *emul;
-
switch (current->personality) {
case PER_BSD:
- emul = SPARC_BSD_EMUL; break;
+ return SPARC_BSD_EMUL;
case PER_SVR4:
- emul = SPARC_SOL_EMUL; break;
+ return SPARC_SOL_EMUL;
default:
return NULL;
}
-
- base = lookup_dentry (emul,
- dget (current->fs->root),
- (LOOKUP_FOLLOW | LOOKUP_DIRECTORY));
-
- if (IS_ERR (base)) return NULL;
-
- base = lookup_dentry (name, base, lookup_flags);
-
- if (IS_ERR (base)) return NULL;
-
- if (!base->d_inode) {
- struct dentry *fromroot;
-
- fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
-
- if (IS_ERR (fromroot)) return base;
-
- if (fromroot->d_inode) {
- dput(base);
- return fromroot;
- }
-
- dput(fromroot);
- }
-
- return base;
}
-#define __prefix_lookup_dentry(name, lookup_flags) \
- if (current->personality) { \
- dentry = __sparc64_lookup_dentry (name, lookup_flags); \
- if (dentry) return dentry; \
- }
-
#endif /* __SPARC64_NAMEI_H */
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
index d1141d105..c17e9bf23 100644
--- a/include/asm-sparc64/pbm.h
+++ b/include/asm-sparc64/pbm.h
@@ -1,4 +1,4 @@
-/* $Id: pbm.h,v 1.21 2000/03/10 02:42:17 davem Exp $
+/* $Id: pbm.h,v 1.22 2000/03/25 05:18:30 davem Exp $
* pbm.h: UltraSparc PCI controller software state.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -143,6 +143,10 @@ struct pci_pbm_info {
struct resource io_space;
struct resource mem_space;
+ /* State of 66MHz capabilities on this PBM. */
+ int is_66mhz_capable;
+ int all_devs_66mhz;
+
/* This PBM's streaming buffer. */
struct pci_strbuf stc;
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
index fe4d9e1fa..697dc6fbc 100644
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -70,27 +70,11 @@ extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
#define flush_cache_all() smp_flush_cache_all()
#define flush_tlb_all() smp_flush_tlb_all()
-
-extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
-{
- if (CTX_VALID(mm->context))
- smp_flush_tlb_mm(mm);
-}
-
-extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
- unsigned long end)
-{
- if (CTX_VALID(mm->context))
- smp_flush_tlb_range(mm, start, end);
-}
-
-extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
- struct mm_struct *mm = vma->vm_mm;
-
- if (CTX_VALID(mm->context))
- smp_flush_tlb_page(mm, page);
-}
+#define flush_tlb_mm(mm) smp_flush_tlb_mm(mm)
+#define flush_tlb_range(mm, start, end) \
+ smp_flush_tlb_range(mm, start, end)
+#define flush_tlb_page(vma, page) \
+ smp_flush_tlb_page((vma)->vm_mm, page)
#endif /* ! __SMP__ */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 056b60f6a..0d49e700e 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.121 2000/03/02 20:37:41 davem Exp $
+/* $Id: pgtable.h,v 1.124 2000/03/27 10:38:56 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -214,26 +214,9 @@ extern inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
#define pte_page(x) (mem_map+pte_pagenr(x))
/* Be very careful when you change these three, they are delicate. */
-static __inline__ pte_t pte_mkyoung(pte_t _pte)
-{ if(pte_val(_pte) & _PAGE_READ)
- return __pte(pte_val(_pte)|(_PAGE_ACCESSED|_PAGE_R));
- else
- return __pte(pte_val(_pte)|(_PAGE_ACCESSED));
-}
-
-static __inline__ pte_t pte_mkwrite(pte_t _pte)
-{ if(pte_val(_pte) & _PAGE_MODIFIED)
- return __pte(pte_val(_pte)|(_PAGE_WRITE|_PAGE_W));
- else
- return __pte(pte_val(_pte)|(_PAGE_WRITE));
-}
-
-static __inline__ pte_t pte_mkdirty(pte_t _pte)
-{ if(pte_val(_pte) & _PAGE_WRITE)
- return __pte(pte_val(_pte)|(_PAGE_MODIFIED|_PAGE_W));
- else
- return __pte(pte_val(_pte)|(_PAGE_MODIFIED));
-}
+#define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R))
+#define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_WRITE))
+#define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W))
/* to find an entry in a page-table-directory. */
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD))
@@ -256,41 +239,7 @@ extern pgd_t swapper_pg_dir[1];
#define mmu_lockarea(vaddr, len) (vaddr)
#define mmu_unlockarea(vaddr, len) do { } while(0)
-/* There used to be some funny code here which tried to guess which
- * TLB wanted the mapping, that wasn't accurate enough to justify it's
- * existance. The real way to do that is to have each TLB miss handler
- * pass in a distinct code to do_sparc64_fault() and do it more accurately
- * there.
- *
- * What we do need to handle here is prevent I-cache corruption. The
- * deal is that the I-cache snoops stores from other CPUs and all DMA
- * activity, however stores from the local processor are not snooped.
- * The dynamic linker and our signal handler mechanism take care of
- * the cases where they write into instruction space, but when a page
- * is copied in the kernel and then executed in user-space is not handled
- * right. This leads to corruptions if things are "just right", consider
- * the following scenerio:
- * 1) Process 1 frees up a page that was used for the PLT of libc in
- * it's address space.
- * 2) Process 2 writes into a page in the PLT of libc for the first
- * time. do_wp_page() copies the page locally, the local I-cache of
- * the processor does not notice the writes during the page copy.
- * The new page used just so happens to be the one just freed in #1.
- * 3) After the PLT write, later the cpu calls into an unresolved PLT
- * entry, the CPU executes old instructions from process 1's PLT
- * table.
- * 4) Splat.
- */
-extern void __flush_icache_page(unsigned long phys_page);
-#define update_mmu_cache(__vma, __address, _pte) \
-do { \
- unsigned short __flags = ((__vma)->vm_flags); \
- if ((__flags & VM_EXEC) != 0 && \
- ((pte_val(_pte) & (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED)) == \
- (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED))) { \
- __flush_icache_page(pte_pagenr(_pte) << PAGE_SHIFT); \
- } \
-} while(0)
+extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte);
#define flush_icache_page(vma, pg) do { } while(0)
diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h
index 158fbbf39..7237736fe 100644
--- a/include/asm-sparc64/processor.h
+++ b/include/asm-sparc64/processor.h
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.61 2000/01/21 11:39:22 jj Exp $
+/* $Id: processor.h,v 1.63 2000/03/27 10:38:57 davem Exp $
* include/asm-sparc64/processor.h
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -51,15 +51,16 @@ struct thread_struct {
unsigned long ksp __attribute__ ((aligned(16)));
unsigned char wstate, cwp, flags;
mm_segment_t current_ds;
- unsigned char w_saved, fpdepth;
+ unsigned char w_saved, fpdepth, fault_code, use_blkcommit;
+ unsigned long fault_address;
unsigned char fpsaved[7];
- unsigned char __pad1[3];
- struct pt_regs *kregs;
+ unsigned char __pad2;
/* D$ line 2, 3, 4 */
+ struct pt_regs *kregs;
unsigned long *utraps;
unsigned char gsr[7];
- unsigned char __pad2;
+ unsigned char __pad3;
unsigned long xfsr[7];
struct reg_window reg_window[NSWINS];
@@ -73,11 +74,16 @@ struct thread_struct {
#endif /* !(__ASSEMBLY__) */
-#define SPARC_FLAG_UNALIGNED 0x01 /* is allowed to do unaligned accesses */
-#define SPARC_FLAG_NEWSIGNALS 0x02 /* task wants new-style signals */
-#define SPARC_FLAG_32BIT 0x04 /* task is older 32-bit binary */
-#define SPARC_FLAG_NEWCHILD 0x08 /* task is just-spawned child process */
-#define SPARC_FLAG_PERFCTR 0x10 /* task has performance counters active */
+#define SPARC_FLAG_UNALIGNED 0x01 /* is allowed to do unaligned accesses */
+#define SPARC_FLAG_NEWSIGNALS 0x02 /* task wants new-style signals */
+#define SPARC_FLAG_32BIT 0x04 /* task is older 32-bit binary */
+#define SPARC_FLAG_NEWCHILD 0x08 /* task is just-spawned child process */
+#define SPARC_FLAG_PERFCTR 0x10 /* task has performance counters active */
+
+#define FAULT_CODE_WRITE 0x01 /* Write access, implies D-TLB */
+#define FAULT_CODE_DTLB 0x02 /* Miss happened in D-TLB */
+#define FAULT_CODE_ITLB 0x04 /* Miss happened in I-TLB */
+#define FAULT_CODE_WINFIXUP 0x08 /* Miss happened during spill/fill */
#define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
NULL, PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
@@ -85,10 +91,12 @@ struct thread_struct {
#define INIT_THREAD { \
/* ksp, wstate, cwp, flags, current_ds, */ \
0, 0, 0, 0, KERNEL_DS, \
-/* w_saved, fpdepth, fpsaved, pad1, kregs, */ \
- 0, 0, { 0 }, { 0 }, 0, \
-/* utraps, gsr, pad2, xfsr, */ \
- 0, { 0 }, 0, { 0 }, \
+/* w_saved, fpdepth, fault_code, use_blkcommit, */ \
+ 0, 0, 0, 0, \
+/* fault_address, fpsaved, __pad2, kregs, */ \
+ 0, { 0 }, 0, 0, \
+/* utraps, gsr, __pad3, xfsr, */ \
+ 0, { 0 }, 0, { 0 }, \
/* reg_window */ \
{ { { 0, }, { 0, } }, }, \
/* rwbuf_stkptrs */ \
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 87379139b..1429e7772 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.56 2000/03/06 22:33:45 davem Exp $ */
+/* $Id: system.h,v 1.57 2000/03/27 10:38:57 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
@@ -131,16 +131,8 @@ extern void __global_restore_flags(unsigned long flags);
extern void synchronize_user_stack(void);
-extern __inline__ void flushw_user(void)
-{
- __asm__ __volatile__("
- rdpr %%otherwin, %%g1
- brz,pt %%g1, 1f
- mov %%o7, %%g3
- call __flushw_user
- clr %%g2
-1:" : : : "g1", "g2", "g3");
-}
+extern void __flushw_user(void);
+#define flushw_user() __flushw_user()
#define flush_user_windows flushw_user
#define flush_register_windows flushw_all
diff --git a/include/linux/blk.h b/include/linux/blk.h
index f06443c04..fd9e46712 100644
--- a/include/linux/blk.h
+++ b/include/linux/blk.h
@@ -54,6 +54,11 @@ extern int ez_init(void);
extern int bpcd_init(void);
extern int ps2esdi_init(void);
+#if defined(CONFIG_ARCH_S390)
+extern int mdisk_init(void);
+extern int dasd_init(void);
+#endif /* CONFIG_ARCH_S390 */
+
extern void set_device_ro(kdev_t dev,int flag);
void add_blkdev_randomness(int major);
@@ -352,6 +357,23 @@ static void floppy_off(unsigned int nr);
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MDISK_MAJOR)
+
+#define DEVICE_NAME "mdisk"
+#define DEVICE_REQUEST mdisk_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == DASD_MAJOR)
+
+#define DEVICE_NAME "dasd"
+#define DEVICE_REQUEST do_dasd_request
+#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
#elif (MAJOR_NR == I2O_MAJOR)
#define DEVICE_NAME "I2O block"
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 8a05bdca2..fb673b0af 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -32,6 +32,7 @@ struct request {
int errors;
unsigned long sector;
unsigned long nr_sectors;
+ unsigned long hard_sector, hard_nr_sectors;
unsigned int nr_segments;
unsigned int nr_hw_segments;
unsigned long current_nr_sectors;
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 75d9fb540..359905839 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -14,6 +14,7 @@
*/
extern unsigned long max_low_pfn;
+extern unsigned long min_low_pfn;
/*
* node_bootmem_map is a map pointer - the bits represent all physical
diff --git a/include/linux/cycx_x25.h b/include/linux/cycx_x25.h
index 4fa2e967e..97e7b59e2 100644
--- a/include/linux/cycx_x25.h
+++ b/include/linux/cycx_x25.h
@@ -12,6 +12,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* 2000/04/02 acme dprintk and cycx_debug
* 1999/01/03 acme judicious use of data types
* 1999/01/02 acme #define X25_ACK_N3 0x4411
* 1998/12/28 acme cleanup: lot'o'things removed
@@ -30,6 +31,11 @@
#define X25_MBOX_OFFS 0x300 /* general mailbox block */
#define X25_RXMBOX_OFFS 0x340 /* receive mailbox */
+/* Debug */
+#define dprintk(level, format, a...) if (cycx_debug >= level) printk(format, ##a)
+
+extern unsigned int cycx_debug;
+
/* Data Structures */
/* X.25 Command Block. */
typedef struct X25Cmd
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 4cc4c56ce..f28b3bd9e 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -1,6 +1,9 @@
#ifndef __LINUX_DCACHE_H
#define __LINUX_DCACHE_H
+#include <asm/atomic.h>
+#include <linux/mount.h>
+
#ifdef __KERNEL__
/*
@@ -105,7 +108,10 @@ struct dentry_operations {
* s_nfsd_free_path semaphore will be down
*/
-/*
+/**
+ * d_drop - drop a dentry
+ * @dentry: dentry to drop
+ *
* d_drop() unhashes the entry from the parent
* dentry hashes, so that it won't be found through
* a VFS lookup any more. Note that this is different
@@ -118,6 +124,7 @@ struct dentry_operations {
* to invalidate a dentry for some reason (NFS
* timeouts or autofs deletes).
*/
+
static __inline__ void d_drop(struct dentry * dentry)
{
list_del(&dentry->d_hash);
@@ -164,10 +171,16 @@ extern int have_submounts(struct dentry *);
* This adds the entry to the hash queues.
*/
extern void d_rehash(struct dentry *);
-/*
+
+/**
+ * d_add - add dentry to hash queues
+ * @entry: dentry to add
+ * @inode: The inode to attach to this dentry
+ *
* This adds the entry to the hash queues and initializes "d_inode".
* The entry was actually filled in earlier during "d_alloc()"
*/
+
static __inline__ void d_add(struct dentry * entry, struct inode * inode)
{
d_rehash(entry);
@@ -183,10 +196,24 @@ extern struct dentry * d_lookup(struct dentry *, struct qstr *);
/* validate "insecure" dentry pointer */
extern int d_validate(struct dentry *, struct dentry *, unsigned int, unsigned int);
+extern char * __d_path(struct dentry *, struct vfsmount *, struct dentry *,
+ struct vfsmount *, char *, int);
/* write full pathname into buffer and return start of pathname */
-extern char * d_path(struct dentry *, char *, int);
-
+#define d_path(dentry, vfsmnt, buffer, buflen) \
+ __d_path(dentry, vfsmnt, current->fs->root, current->fs->rootmnt, \
+ buffer, buflen)
+
/* Allocation counts.. */
+
+/**
+ * dget - get a reference to a dentry
+ * @dentry: dentry to get a reference too
+ *
+ * Given a dentry or NULL pointer increment the reference count
+ * if appropriate and return the dentry. A dentry will not be
+ * destroyed when it has references.
+ */
+
static __inline__ struct dentry * dget(struct dentry *dentry)
{
if (dentry)
@@ -194,6 +221,13 @@ static __inline__ struct dentry * dget(struct dentry *dentry)
return dentry;
}
+/**
+ * d_unhashed - is dentry hashed
+ * @dentry: entry to check
+ *
+ * Returns true if the dentry passed is not currently hashed
+ */
+
static __inline__ int d_unhashed(struct dentry *dentry)
{
return list_empty(&dentry->d_hash);
@@ -201,6 +235,13 @@ static __inline__ int d_unhashed(struct dentry *dentry)
extern void dput(struct dentry *);
+/* MOUNT_REWRITE: replace with the check for d_vfsmnt */
+static __inline__ int d_mountpoint(struct dentry *dentry)
+{
+ return dentry != dentry->d_mounts;
+}
+
+
#endif /* __KERNEL__ */
#endif /* __LINUX_DCACHE_H */
diff --git a/include/linux/errno.h b/include/linux/errno.h
index ac2128445..653227803 100644
--- a/include/linux/errno.h
+++ b/include/linux/errno.h
@@ -11,6 +11,16 @@
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#define ENOIOCTLCMD 515 /* No ioctl command */
+/* Defined for the NFSv3 protocol */
+#define EBADHANDLE 521 /* Illegal NFS file handle */
+#define ENOTSYNC 522 /* Update synchronization mismatch */
+#define EBADCOOKIE 523 /* Cookie is stale */
+#define ENOTSUPP 524 /* Operation is not supported */
+#define ETOOSMALL 525 /* Buffer or request is too small */
+#define ESERVERFAULT 526 /* An untranslatable error occurred */
+#define EBADTYPE 527 /* Type not supported by server */
+#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */
+
#endif
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c1d3ffe75..57bade5c6 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -79,7 +79,6 @@ extern int max_super_blocks, nr_super_blocks;
#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
* FS_NO_DCACHE is not set.
*/
-#define FS_IBASKET 8 /* FS does callback to free_ibasket() if space gets low. */
/*
* These are the fs-independent mount-flags: up to 16 flags are supported
@@ -456,6 +455,7 @@ struct fown_struct {
struct file {
struct list_head f_list;
struct dentry *f_dentry;
+ struct vfsmount *f_vfsmnt;
struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
@@ -507,16 +507,24 @@ struct file_lock {
struct file *fl_file;
unsigned char fl_flags;
unsigned char fl_type;
- off_t fl_start;
- off_t fl_end;
+ loff_t fl_start;
+ loff_t fl_end;
void (*fl_notify)(struct file_lock *); /* unblock callback */
+ void (*fl_insert)(struct file_lock *); /* lock insertion callback */
+ void (*fl_remove)(struct file_lock *); /* lock removal callback */
union {
struct nfs_lock_info nfs_fl;
} fl_u;
};
+/* The following constant reflects the upper bound of the file/locking space */
+#ifndef OFFSET_MAX
+#define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1)))
+#define OFFSET_MAX INT_LIMIT(loff_t)
+#endif
+
extern struct file_lock *file_lock_table;
#include <linux/fcntl.h>
@@ -539,10 +547,36 @@ struct fasync_struct {
struct file *fa_file;
};
+struct nameidata {
+ struct dentry *dentry;
+ struct vfsmount *mnt;
+ struct qstr last;
+};
+
#define FASYNC_MAGIC 0x4601
extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
+#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
+#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
+
+struct quota_mount_options
+{
+ unsigned int flags; /* Flags for diskquotas on this device */
+ struct semaphore dqio_sem; /* lock device while I/O in progress */
+ struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */
+ struct file *files[MAXQUOTAS]; /* fp's to quotafiles */
+ time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */
+ time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */
+ char rsquash[MAXQUOTAS]; /* for quotas threat root as any other user */
+};
+
+/*
+ * Umount options
+ */
+
+#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
+
#include <linux/minix_fs_sb.h>
#include <linux/ext2_fs_sb.h>
#include <linux/hpfs_fs_sb.h>
@@ -582,9 +616,6 @@ struct super_block {
struct dentry *s_root;
wait_queue_head_t s_wait;
- struct inode *s_ibasket;
- short int s_ibasket_count;
- short int s_ibasket_max;
struct list_head s_dirty; /* dirty inodes */
struct list_head s_files;
@@ -688,7 +719,7 @@ struct inode_operations {
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
int (*readlink) (struct dentry *, char *,int);
- struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
+ int (*follow_link) (struct dentry *, struct nameidata *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int);
int (*revalidate) (struct dentry *);
@@ -812,10 +843,9 @@ extern int do_truncate(struct dentry *, loff_t start);
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 struct file *filp_open(const char *, int, int);
+extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
extern int filp_close(struct file *, fl_owner_t id);
-
extern char * getname(const char *);
#define __getname() ((char *) __get_free_page(GFP_KERNEL))
#define putname(name) free_page((unsigned long)(name))
@@ -930,13 +960,8 @@ extern int get_write_access(struct inode *);
extern void put_write_access(struct inode *);
extern struct dentry * do_mknod(const char *, int, dev_t);
extern int do_pipe(int *);
-extern int do_unlink(const char * name, struct dentry *);
-extern struct dentry * __open_namei(const char *, int, int, struct dentry *);
-static inline struct dentry * open_namei(const char *pathname)
-{
- return __open_namei(pathname, 0, 0, NULL);
-}
+extern int open_namei(const char *, int, int, struct nameidata *);
extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
extern struct file * open_exec(const char *);
@@ -968,6 +993,8 @@ extern ino_t find_inode_number(struct dentry *, struct qstr *);
#define LOOKUP_DIRECTORY (2)
#define LOOKUP_SLASHOK (4)
#define LOOKUP_CONTINUE (8)
+#define LOOKUP_POSITIVE (16)
+#define LOOKUP_PARENT (32)
/*
* "descriptor" for what we're up to with a read for sendfile().
@@ -987,12 +1014,13 @@ typedef struct {
typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
-
-extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int);
+extern struct dentry * lookup_dentry(const char *, unsigned int);
+extern int walk_init(const char *, unsigned, struct nameidata *);
+extern int walk_name(const char *, unsigned, struct nameidata *);
extern struct dentry * lookup_one(const char *, struct dentry *);
extern struct dentry * __namei(const char *, unsigned int);
-#define namei(pathname) __namei(pathname, 1)
+#define namei(pathname) __namei(pathname, LOOKUP_FOLLOW)
#define lnamei(pathname) __namei(pathname, 0)
extern void iput(struct inode *);
@@ -1062,9 +1090,9 @@ extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
extern struct file_operations generic_ro_fops;
extern int vfs_readlink(struct dentry *, char *, int, const char *);
-extern struct dentry *vfs_follow_link(struct dentry *, struct dentry *, unsigned, const char *);
+extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char *, int);
-extern struct dentry *page_follow_link(struct dentry *, struct dentry *, unsigned);
+extern int page_follow_link(struct dentry *, struct nameidata *);
extern struct inode_operations page_symlink_inode_operations;
extern int vfs_readdir(struct file *, filldir_t, void *);
diff --git a/include/linux/ibmtr.h b/include/linux/ibmtr.h
new file mode 100644
index 000000000..3e341078b
--- /dev/null
+++ b/include/linux/ibmtr.h
@@ -0,0 +1,454 @@
+/* Definitions for an IBM Token Ring card. */
+/* This file is distributed under the GNU GPL */
+
+/* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */
+
+#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */
+#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
+#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
+#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
+#define TR_RETRIES 6 /* number of open retries */
+
+#define TR_ISA 1
+#define TR_MCA 2
+#define TR_ISAPNP 3
+#define NOTOK 0
+#define TOKDEBUG 1
+
+#define IBMTR_SHARED_RAM_SIZE 0x10000
+#define IBMTR_IO_EXTENT 4
+#define IBMTR_MAX_ADAPTERS 2
+
+#define CHANNEL_ID 0X1F30
+#define AIP 0X1F00
+#define AIPCHKSUM1 0X1F60
+#define AIPCHKSUM2 0X1FF0
+#define AIPADAPTYPE 0X1FA0
+#define AIPDATARATE 0X1FA2
+#define AIPEARLYTOKEN 0X1FA4
+#define AIPAVAILSHRAM 0X1FA6
+#define AIPSHRAMPAGE 0X1FA8
+#define AIP4MBDHB 0X1FAA
+#define AIP16MBDHB 0X1FAC
+#define AIPFID 0X1FBA
+
+/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits. I left everything
+ the way my documentation had it, ie: 0x0A20. */
+#define ADAPTINTCNTRL 0x02f0 /* Adapter interrupt control */
+#define ADAPTRESET 0x1 /* Control Adapter reset (add to base) */
+#define ADAPTRESETREL 0x2 /* Release Adapter from reset ( """) */
+#define ADAPTINTREL 0x3 /* Adapter interrupt release */
+
+#define MMIOStartLocP 0x0a20 /* Primary adapter's starting MMIO area */
+#define MMIOStartLocA 0x0a24 /* Alternate adapter's starting MMIO area */
+
+#define GLOBAL_INT_ENABLE 0x02f0
+
+/* MMIO bits 0-4 select register */
+#define RRR_EVEN 0x00 /* Shared RAM relocation registers - even and odd */
+/* Used to set the starting address of shared RAM */
+/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/
+/* ie: 0x02 sets RAM address to ...ato! issy su wazzoo !! GODZILLA!!! */
+#define RRR_ODD 0x01
+/* Bits 2 and 3 of this register can be read to determine shared RAM size */
+/* 00 for 8k, 01 for 16k, 10 for 32k, 11 for 64k */
+#define WRBR_EVEN 0x02 /* Write region base registers - even and odd */
+#define WRBR_ODD 0x03
+#define WWOR_EVEN 0x04 /* Write window open registers - even and odd */
+#define WWOR_ODD 0x05
+#define WWCR_EVEN 0x06 /* Write window close registers - even and odd */
+#define WWCR_ODD 0x07
+
+/* Interrupt status registers - PC system - even and odd */
+#define ISRP_EVEN 0x08
+
+#define TCR_INT 0x10 /* Bit 4 - Timer interrupt. The TVR_EVEN timer has
+ expired. */
+#define ERR_INT 0x08 /* Bit 3 - Error interrupt. The adapter has had an
+ internal error. */
+#define ACCESS_INT 0x04 /* Bit 2 - Access interrupt. You have attempted to
+ write to an invalid area of shared RAM or an invalid
+ register within the MMIO. */
+/* In addition, the following bits within ISRP_EVEN can be turned on or off by you */
+/* to control the interrupt processing: */
+#define INT_IRQ 0x80 /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and
+ IRQ. This should normally be set (by you) to 1. */
+#define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable. If 0, no interrupts will
+ occur. If 1, interrupts will occur normally.
+ Normally set to 1. */
+/* Bit 0 - Primary or alternate adapter. Set to zero if this adapter is the primary adapter,*/
+/* 1 if this adapter is the alternate adapter. */
+
+
+#define ISRP_ODD 0x09
+
+#define ADAP_CHK_INT 0x40 /* Bit 6 - Adapter check. the adapter has
+ encountered a serious problem and has closed
+ itself. Whoa. */
+#define SRB_RESP_INT 0x20 /* Bit 5 - SRB response. The adapter has accepted
+ an SRB request and set the return code within
+ the SRB. */
+#define ASB_FREE_INT 0x10 /* Bit 4 - ASB free. The adapter has read the ASB
+ and this area can be safely reused. This interrupt
+ is only used if your application has set the ASB
+ free request bit in ISRA_ODD or if an error was
+ detected in your response. */
+#define ARB_CMD_INT 0x08 /* Bit 3 - ARB command. The adapter has given you a
+ command for action. The command is located in the
+ ARB area of shared memory. */
+#define SSB_RESP_INT 0x04 /* Bit 2 - SSB response. The adapter has posted a
+ response to your SRB (the response is located in
+ the SSB area of shared memory). */
+/* Bit 1 - Bridge frame forward complete. */
+
+
+
+#define ISRA_EVEN 0x0A /* Interrupt status registers - adapter - even and odd */
+/* Bit 7 - Internal parity error (on adapter's internal bus) */
+/* Bit 6 - Timer interrupt pending */
+/* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */
+/* Bit 4 - Adapter microcode problem (microcode dead-man timer expired) */
+/* Bit 3 - Adapter processor check status */
+/* Bit 2 - Reserved */
+/* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */
+/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */
+
+#define ISRA_ODD 0x0B
+#define CMD_IN_SRB 0x20 /* Bit 5 - Indicates that you have placed a new
+ command in the SRB and are ready for the adapter to
+ process the command. */
+#define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response
+ (an ASB) in the shared RAM which is available for
+ the adapter's use. */
+/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */
+/* command is still pending. The adapter will then interrupt you when the previous */
+/* command is completed */
+/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */
+/* ASB is still pending. The adapter will then interrupt you when the previous ASB */
+/* is copied. */
+#define ARB_FREE 0x2
+#define SSB_FREE 0x1
+
+#define TCR_EVEN 0x0C /* Timer control registers - even and odd */
+#define TCR_ODD 0x0D
+#define TVR_EVEN 0x0E /* Timer value registers - even and odd */
+#define TVR_ODD 0x0F
+#define SRPR_EVEN 0x18 /* Shared RAM paging registers - even and odd */
+#define SRPR_ENABLE_PAGING 0xc0
+#define SRPR_ODD 0x19 /* Not used. */
+#define TOKREAD 0x60
+#define TOKOR 0x40
+#define TOKAND 0x20
+#define TOKWRITE 0x00
+
+/* MMIO bits 5-6 select operation */
+/* 00 is used to write to a register */
+/* 01 is used to bitwise AND a byte with a register */
+/* 10 is used to bitwise OR a byte with a register */
+/* 11 is used to read from a register */
+
+/* MMIO bits 7-8 select area of interest.. see below */
+/* 00 selects attachment control area. */
+/* 01 is reserved. */
+/* 10 selects adapter identification area A containing the adapter encoded address. */
+/* 11 selects the adapter identification area B containing test patterns. */
+
+#define PCCHANNELID 5049434F3631313039393020
+#define MCCHANNELID 4D4152533633583435313820
+
+#define ACA_OFFSET 0x1e00
+#define ACA_SET 0x40
+#define ACA_RESET 0x20
+#define ACA_RW 0x00
+
+#ifdef ENABLE_PAGING
+#define SET_PAGE(x) (isa_writeb((x), \
+ ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN))
+#else
+#define SET_PAGE(x)
+#endif
+
+typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state;
+
+/* do_tok_int possible values */
+#define FIRST_INT 1
+#define NOT_FIRST 2
+
+struct tok_info {
+ unsigned char irq;
+ __u32 mmio;
+ unsigned char hw_address[32];
+ unsigned char adapter_type;
+ unsigned char data_rate;
+ unsigned char token_release;
+ unsigned char avail_shared_ram;
+ unsigned char shared_ram_paging;
+ unsigned short dhb_size4mb;
+ unsigned short rbuf_len4;
+ unsigned short rbuf_cnt4;
+ unsigned short maxmtu4;
+ unsigned short dhb_size16mb;
+ unsigned short rbuf_len16;
+ unsigned short rbuf_cnt16;
+ unsigned short maxmtu16;
+ /* Additions by David Morris */
+ unsigned char do_tok_int;
+ wait_queue_head_t wait_for_tok_int;
+ wait_queue_head_t wait_for_reset;
+ unsigned char sram_base;
+ /* Additions by Peter De Schrijver */
+ unsigned char page_mask; /* mask to select RAM page to Map*/
+ unsigned char mapped_ram_size; /* size of RAM page */
+ __u32 sram; /* Shared memory base address */
+ __u32 init_srb; /* Initial System Request Block address */
+ __u32 srb; /* System Request Block address */
+ __u32 ssb; /* System Status Block address */
+ __u32 arb; /* Adapter Request Block address */
+ __u32 asb; /* Adapter Status Block address */
+ __u8 init_srb_page;
+ __u8 srb_page;
+ __u8 ssb_page;
+ __u8 arb_page;
+ __u8 asb_page;
+ unsigned short exsap_station_id;
+ unsigned short global_int_enable;
+ struct sk_buff *current_skb;
+ struct net_device_stats tr_stats;
+ unsigned char auto_ringspeedsave;
+ open_state open_status;
+ unsigned char readlog_pending;
+ unsigned short adapter_int_enable; /* Adapter-specific int enable */
+ struct timer_list tr_timer;
+ unsigned char ring_speed;
+ __u32 func_addr;
+ unsigned int retry_count;
+ spinlock_t lock; /* SMP protection */
+};
+
+/* token ring adapter commands */
+#define DIR_INTERRUPT 0x00 /* struct srb_interrupt */
+#define DIR_MOD_OPEN_PARAMS 0x01
+#define DIR_OPEN_ADAPTER 0x03 /* struct dir_open_adapter */
+#define DIR_CLOSE_ADAPTER 0x04
+#define DIR_SET_GRP_ADDR 0x06
+#define DIR_SET_FUNC_ADDR 0x07 /* struct srb_set_funct_addr */
+#define DIR_READ_LOG 0x08 /* struct srb_read_log */
+#define DLC_OPEN_SAP 0x15 /* struct dlc_open_sap */
+#define DLC_CLOSE_SAP 0x16
+#define DATA_LOST 0x20 /* struct asb_rec */
+#define REC_DATA 0x81 /* struct arb_rec_req */
+#define XMIT_DATA_REQ 0x82 /* struct arb_xmit_req */
+#define DLC_STATUS 0x83 /* struct arb_dlc_status */
+#define RING_STAT_CHANGE 0x84 /* struct dlc_open_sap ??? */
+
+/* DIR_OPEN_ADAPTER options */
+#define OPEN_PASS_BCON_MAC 0x0100
+#define NUM_RCV_BUF 2
+#define RCV_BUF_LEN 1024
+#define DHB_LENGTH 2048
+#define NUM_DHB 2
+#define DLC_MAX_SAP 2
+#define DLC_MAX_STA 1
+
+/* DLC_OPEN_SAP options */
+#define MAX_I_FIELD 0x0088
+#define SAP_OPEN_IND_SAP 0x04
+#define SAP_OPEN_PRIORITY 0x20
+#define SAP_OPEN_STATION_CNT 0x1
+#define XMIT_DIR_FRAME 0x0A
+#define XMIT_UI_FRAME 0x0d
+#define XMIT_XID_CMD 0x0e
+#define XMIT_TEST_CMD 0x11
+
+/* srb close return code */
+#define SIGNAL_LOSS 0x8000
+#define HARD_ERROR 0x4000
+#define XMIT_BEACON 0x1000
+#define LOBE_FAULT 0x0800
+#define AUTO_REMOVAL 0x0400
+#define REMOVE_RECV 0x0100
+#define LOG_OVERFLOW 0x0080
+#define RING_RECOVER 0x0020
+
+struct srb_init_response {
+ unsigned char command;
+ unsigned char init_status;
+ unsigned char init_status_2;
+ unsigned char reserved[3];
+ __u16 bring_up_code;
+ __u16 encoded_address;
+ __u16 level_address;
+ __u16 adapter_address;
+ __u16 parms_address;
+ __u16 mac_address;
+};
+
+struct dir_open_adapter {
+ unsigned char command;
+ char reserved[7];
+ __u16 open_options;
+ unsigned char node_address[6];
+ unsigned char group_address[4];
+ unsigned char funct_address[4];
+ __u16 num_rcv_buf;
+ __u16 rcv_buf_len;
+ __u16 dhb_length;
+ unsigned char num_dhb;
+ char reserved2;
+ unsigned char dlc_max_sap;
+ unsigned char dlc_max_sta;
+ unsigned char dlc_max_gsap;
+ unsigned char dlc_max_gmem;
+ unsigned char dlc_t1_tick_1;
+ unsigned char dlc_t2_tick_1;
+ unsigned char dlc_ti_tick_1;
+ unsigned char dlc_t1_tick_2;
+ unsigned char dlc_t2_tick_2;
+ unsigned char dlc_ti_tick_2;
+ unsigned char product_id[18];
+};
+
+struct srb_open_response {
+ unsigned char command;
+ unsigned char reserved1;
+ unsigned char ret_code;
+ unsigned char reserved2[3];
+ __u16 error_code;
+ __u16 asb_addr;
+ __u16 srb_addr;
+ __u16 arb_addr;
+ __u16 ssb_addr;
+};
+
+struct dlc_open_sap {
+ unsigned char command;
+ unsigned char reserved1;
+ unsigned char ret_code;
+ unsigned char reserved2;
+ __u16 station_id;
+ unsigned char timer_t1;
+ unsigned char timer_t2;
+ unsigned char timer_ti;
+ unsigned char maxout;
+ unsigned char maxin;
+ unsigned char maxout_incr;
+ unsigned char max_retry_count;
+ unsigned char gsap_max_mem;
+ __u16 max_i_field;
+ unsigned char sap_value;
+ unsigned char sap_options;
+ unsigned char station_count;
+ unsigned char sap_gsap_mem;
+ unsigned char gsap[0];
+};
+
+struct srb_xmit {
+ unsigned char command;
+ unsigned char cmd_corr;
+ unsigned char ret_code;
+ unsigned char reserved1;
+ __u16 station_id;
+};
+
+struct srb_interrupt {
+ unsigned char command;
+ unsigned char cmd_corr;
+ unsigned char ret_code;
+};
+
+struct srb_read_log {
+ unsigned char command;
+ unsigned char reserved1;
+ unsigned char ret_code;
+ unsigned char reserved2;
+ unsigned char line_errors;
+ unsigned char internal_errors;
+ unsigned char burst_errors;
+ unsigned char A_C_errors;
+ unsigned char abort_delimiters;
+ unsigned char reserved3;
+ unsigned char lost_frames;
+ unsigned char recv_congest_count;
+ unsigned char frame_copied_errors;
+ unsigned char frequency_errors;
+ unsigned char token_errors;
+};
+
+struct asb_xmit_resp {
+ unsigned char command;
+ unsigned char cmd_corr;
+ unsigned char ret_code;
+ unsigned char reserved;
+ __u16 station_id;
+ __u16 frame_length;
+ unsigned char hdr_length;
+ unsigned char rsap_value;
+};
+
+struct arb_xmit_req {
+ unsigned char command;
+ unsigned char cmd_corr;
+ unsigned char reserved1[2];
+ __u16 station_id;
+ __u16 dhb_address;
+};
+
+struct arb_rec_req {
+ unsigned char command;
+ unsigned char reserved1[3];
+ __u16 station_id;
+ __u16 rec_buf_addr;
+ unsigned char lan_hdr_len;
+ unsigned char dlc_hdr_len;
+ __u16 frame_len;
+ unsigned char msg_type;
+};
+
+struct asb_rec {
+ unsigned char command;
+ unsigned char reserved1;
+ unsigned char ret_code;
+ unsigned char reserved2;
+ __u16 station_id;
+ __u16 rec_buf_addr;
+};
+
+struct rec_buf {
+ /* unsigned char reserved1[2]; */
+ __u16 buf_ptr;
+ unsigned char reserved2;
+ __u16 buf_len;
+ unsigned char data[0];
+};
+
+struct arb_dlc_status {
+ unsigned char command;
+ unsigned char reserved1[3];
+ __u16 station_id;
+ __u16 status;
+ unsigned char frmr_data[5];
+ unsigned char access_prio;
+ unsigned char rem_addr[TR_ALEN];
+ unsigned char rsap_value;
+};
+
+struct arb_ring_stat_change {
+ unsigned char command;
+ unsigned char reserved1[5];
+ __u16 ring_status;
+};
+
+struct srb_close_adapter {
+ unsigned char command;
+ unsigned char reserved1;
+ unsigned char ret_code;
+};
+
+struct srb_set_funct_addr {
+ unsigned char command;
+ unsigned char reserved1;
+ unsigned char ret_code;
+ unsigned char reserved2[3];
+ unsigned char funct_address[4];
+};
+
diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h
index f5d80a778..38adbdcc0 100644
--- a/include/linux/if_ppp.h
+++ b/include/linux/if_ppp.h
@@ -21,7 +21,7 @@
*/
/*
- * ==FILEVERSION 20000115==
+ * ==FILEVERSION 20000324==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the above date.
@@ -140,6 +140,7 @@ struct ifpppcstatsreq {
#define PPPIOCCONNECT _IOW('t', 58, int) /* connect channel to unit */
#define PPPIOCDISCONN _IO('t', 57) /* disconnect channel */
#define PPPIOCATTCHAN _IOW('t', 56, int) /* attach to ppp channel */
+#define PPPIOCGCHAN _IOR('t', 55, int) /* get ppp channel number */
#define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0)
#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */
diff --git a/include/linux/input.h b/include/linux/input.h
index 4cc82fbf4..17f6c046f 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -47,6 +47,35 @@ struct input_event {
};
/*
+ * The device ID structure;
+ */
+
+struct input_id {
+ __u16 bus;
+ __u16 vendor;
+ __u16 product;
+};
+
+/*
+ * Protocol version.
+ */
+
+#define EV_VERSION 0x010000
+
+/*
+ * IOCTLs (0x00 - 0x7f)
+ */
+
+#define EVIOCGVERSION _IOR('E', 0x01, __u32) /* get driver version */
+#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
+#define EVIOCGREP _IOR('E', 0x03, int[2]) /* get repeat settings */
+#define EVIOCSREP _IOW('E', 0x03, int[2]) /* get repeat settings */
+#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x03, len) /* get device name */
+#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
+#define EVIOCGABSLIM(num) _IOR('E', 0x40 + num, int[4]) /* get abs event limits */
+#define EVIOCGABS(num) _IOR('E', 0x80 + num, int) /* get abs value */
+
+/*
* Event types
*/
@@ -273,11 +302,12 @@ struct input_event {
#define BTN_THUMB2 0x122
#define BTN_TOP 0x123
#define BTN_TOP2 0x124
-#define BTN_BASE 0x125
-#define BTN_BASE2 0x126
-#define BTN_BASE3 0x127
-#define BTN_BASE4 0x128
-#define BTN_BASE5 0x129
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
#define BTN_GAMEPAD 0x130
#define BTN_A 0x130
@@ -383,6 +413,7 @@ struct input_event {
*/
#include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define BIT(x) (1<<((x)%BITS_PER_LONG))
@@ -393,6 +424,8 @@ struct input_dev {
void *private;
int number;
+ char *name;
+ struct input_id id;
unsigned long evbit[NBITS(EV_MAX)];
unsigned long keybit[NBITS(KEY_MAX)];
@@ -430,17 +463,21 @@ struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
- int (*connect)(struct input_handler *handler, struct input_dev *dev);
+ struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev);
void (*disconnect)(struct input_handle *handle);
- struct input_handle *handle;
+ struct file_operations *fops;
+ int minor;
+ struct input_handle *handle;
struct input_handler *next;
};
struct input_handle {
void *private;
+
+ int open;
struct input_dev *dev;
struct input_handler *handler;
@@ -455,9 +492,12 @@ void input_unregister_device(struct input_dev *);
void input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
-void input_open_device(struct input_handle *);
+int input_open_device(struct input_handle *);
void input_close_device(struct input_handle *);
+devfs_handle_t input_register_minor(char *name, int minor, int minor_base);
+void input_unregister_minor(devfs_handle_t handle);
+
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
#define input_report_key(a,b,c) input_event(a, EV_KEY, b, c)
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index d949bd649..694046eaa 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -146,12 +146,14 @@ struct nlm_host * nlm_lookup_host(struct svc_client *,
struct sockaddr_in *, int, int);
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
void nlm_rebind_host(struct nlm_host *);
+struct nlm_host * nlm_get_host(struct nlm_host *);
void nlm_release_host(struct nlm_host *);
void nlm_shutdown_hosts(void);
/*
* Server-side lock handling
*/
+int nlmsvc_async_call(struct nlm_rqst *, u32, rpc_action);
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
struct nlm_lock *, int, struct nlm_cookie *);
u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
diff --git a/include/linux/lockd/nlm.h b/include/linux/lockd/nlm.h
index 4bc44e7d9..e22388d50 100644
--- a/include/linux/lockd/nlm.h
+++ b/include/linux/lockd/nlm.h
@@ -12,11 +12,8 @@
#include <linux/config.h>
/* Maximum file offset in file_lock.fl_end */
-#ifdef OFFSET_MAX
-# define NLM_OFFSET_MAX OFFSET_MAX
-#else
-# define NLM_OFFSET_MAX ((off_t) 0x7fffffff)
-#endif
+# define NLM_OFFSET_MAX ((s32) 0x7fffffff)
+# define NLM4_OFFSET_MAX ((s64) ((~(u64)0) >> 1))
/* Return states for NLM */
enum {
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0e35a9c79..453b31d7c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -163,7 +163,7 @@ typedef struct page {
#define PG_error 1
#define PG_referenced 2
#define PG_uptodate 3
-#define PG__unused_00 4
+#define PG_dirty 4
#define PG_decr_after 5
#define PG_unused_01 6
#define PG__unused_02 7
@@ -180,6 +180,8 @@ typedef struct page {
#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
#define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags)
#define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags)
+#define PageDirty(page) test_bit(PG_dirty, &(page)->flags)
+#define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags)
#define PageLocked(page) test_bit(PG_locked, &(page)->flags)
#define LockPage(page) set_bit(PG_locked, &(page)->flags)
#define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags)
@@ -188,7 +190,7 @@ typedef struct page {
wake_up(&page->wait); \
} while (0)
#define PageError(page) test_bit(PG_error, &(page)->flags)
-#define SetPageError(page) test_and_set_bit(PG_error, &(page)->flags)
+#define SetPageError(page) set_bit(PG_error, &(page)->flags)
#define ClearPageError(page) clear_bit(PG_error, &(page)->flags)
#define PageReferenced(page) test_bit(PG_referenced, &(page)->flags)
#define PageDecrAfter(page) test_bit(PG_decr_after, &(page)->flags)
@@ -205,6 +207,9 @@ typedef struct page {
#define PageClearSwapCache(page) clear_bit(PG_swap_cache, &(page)->flags)
#define PageTestandClearSwapCache(page) test_and_clear_bit(PG_swap_cache, &(page)->flags)
+#define PageSwapEntry(page) test_bit(PG_swap_entry, &(page)->flags)
+#define SetPageSwapEntry(page) set_bit(PG_swap_entry, &(page)->flags)
+#define ClearPageSwapEntry(page) clear_bit(PG_swap_entry, &(page)->flags)
#ifdef CONFIG_HIGHMEM
#define PageHighMem(page) test_bit(PG_highmem, &(page)->flags)
@@ -406,7 +411,8 @@ extern int check_pgt_cache(void);
extern void free_area_init(unsigned long * zones_size);
extern void free_area_init_node(int nid, pg_data_t *pgdat,
- unsigned long * zones_size, unsigned long zone_start_paddr);
+ unsigned long * zones_size, unsigned long zone_start_paddr,
+ unsigned long *zholes_size);
extern void mem_init(void);
extern void show_mem(void);
extern void si_meminfo(struct sysinfo * val);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 82d3e62f4..05a846297 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -102,7 +102,7 @@ extern pg_data_t *pgdat_list;
*/
extern void show_free_areas_core(int);
extern void free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
- unsigned long *zones_size, unsigned long paddr);
+ unsigned long *zones_size, unsigned long paddr, unsigned long *zholes_size);
#ifndef CONFIG_DISCONTIGMEM
diff --git a/include/linux/mount.h b/include/linux/mount.h
index c2dcfe93f..547163d2e 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -11,20 +11,6 @@
#ifndef _LINUX_MOUNT_H
#define _LINUX_MOUNT_H
-#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
-#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
-
-struct quota_mount_options
-{
- unsigned int flags; /* Flags for diskquotas on this device */
- struct semaphore dqio_sem; /* lock device while I/O in progress */
- struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */
- struct file *files[MAXQUOTAS]; /* fp's to quotafiles */
- time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */
- time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */
- char rsquash[MAXQUOTAS]; /* for quotas threat root as any other user */
-};
-
struct vfsmount
{
kdev_t mnt_dev; /* Device this applies to */
@@ -34,10 +20,14 @@ struct vfsmount
struct vfsmount *mnt_next; /* pointer to next in linkedlist */
};
-/*
- * Umount options
- */
-
-#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
+/* MOUNT_REWRITE: fill these */
+static inline struct vfsmount *mntget(struct vfsmount *mnt)
+{
+ return mnt;
+}
+
+static inline void mntput(struct vfsmount *mnt)
+{
+}
#endif /* _LINUX_MOUNT_H */
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index cdd77e932..c981a6911 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -15,6 +15,7 @@
#define NBD_CLEAR_QUE _IO( 0xab, 5 )
#define NBD_PRINT_DEBUG _IO( 0xab, 6 )
#define NBD_SET_SIZE_BLOCKS _IO( 0xab, 7 )
+#define NBD_DISCONNECT _IO( 0xab, 8 )
#ifdef MAJOR_NR
diff --git a/include/linux/net.h b/include/linux/net.h
index d91b6bcf6..0269a037e 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -53,12 +53,14 @@ typedef enum {
SS_DISCONNECTING /* in process of disconnecting */
} socket_state;
-#define SO_ACCEPTCON (1<<16) /* performed a listen */
-#define SO_WAITDATA (1<<17) /* wait data to read */
-#define SO_NOSPACE (1<<18) /* no space to write */
+#define __SO_ACCEPTCON (1<<16) /* performed a listen */
#ifdef __KERNEL__
+#define SOCK_ASYNC_NOSPACE 0
+#define SOCK_ASYNC_WAITDATA 1
+#define SOCK_NOSPACE 2
+
struct socket
{
socket_state state;
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index 12cf75136..178eb4c06 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -67,13 +67,13 @@ struct ip_conntrack_expect
struct ip_conntrack *expectant;
};
-#if defined(CONFIG_IP_NF_NAT) || defined(CONFIG_IP_NF_NAT_MODULE)
+#ifdef CONFIG_IP_NF_NAT_NEEDED
#include <linux/netfilter_ipv4/ip_nat.h>
#endif
#if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE)
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#if defined(CONFIG_IP_NF_NAT) || defined(CONFIG_IP_NF_NAT_MODULE)
+#ifdef CONFIG_IP_NF_NAT_NEEDED
#include <linux/netfilter_ipv4/ip_nat_ftp.h>
#endif
#endif
@@ -119,7 +119,7 @@ struct ip_conntrack
#endif
} help;
-#if defined(CONFIG_IP_NF_NAT) || defined(CONFIG_IP_NF_NAT_MODULE)
+#ifdef CONFIG_IP_NF_NAT_NEEDED
struct {
struct ip_nat_info info;
union {
@@ -132,7 +132,7 @@ struct ip_conntrack
int masq_index;
#endif
} nat;
-#endif /* CONFIG_IP_NF_NAT || CONFIG_IP_NF_NAT_MODULE */
+#endif /* CONFIG_IP_NF_NAT_NEEDED */
};
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
index a164aed4f..c5fabbbd9 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
@@ -19,7 +19,6 @@ enum ip_ct_ftp_type
IP_CT_FTP_PASV = IP_CT_DIR_REPLY
};
-/* Protected by ip_conntrack_lock */
/* We record seq number and length of ftp ip/port text here: all in
host order. */
struct ip_ct_ftp
diff --git a/include/linux/netfilter_ipv4/ip_queue.h b/include/linux/netfilter_ipv4/ip_queue.h
index 8bbd6230f..a78776235 100644
--- a/include/linux/netfilter_ipv4/ip_queue.h
+++ b/include/linux/netfilter_ipv4/ip_queue.h
@@ -2,7 +2,7 @@
* This is a module which is used for queueing IPv4 packets and
* communicating with userspace via netlink.
*
- * (C) 2000 James Morris
+ * (C) 2000 James Morris, this code is GPL.
*/
#ifndef _IP_QUEUE_H
#define _IP_QUEUE_H
@@ -27,7 +27,7 @@ typedef struct ipq_packet_msg {
char indev_name[IFNAMSIZ]; /* Name of incoming interface */
char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */
size_t data_len; /* Length of packet data */
- /* Optional packet data follows */
+ unsigned char payload[0]; /* Optional packet data */
} ipq_packet_msg_t;
/* Messages sent from userspace */
@@ -40,7 +40,7 @@ typedef struct ipq_verdict_msg {
unsigned int value; /* Verdict to hand to netfilter */
unsigned long id; /* Packet ID for this verdict */
size_t data_len; /* Length of replacement data */
- /* Optional replacement data follows */
+ unsigned char payload[0]; /* Optional replacement packet */
} ipq_verdict_msg_t;
typedef struct ipq_peer_msg {
@@ -50,37 +50,19 @@ typedef struct ipq_peer_msg {
} msg;
} ipq_peer_msg_t;
-/* Each queued packet has one of these states */
+/* Packet delivery modes */
enum {
- IPQ_PS_NEW, /* Newly arrived packet */
- IPQ_PS_WAITING, /* User has been notified of packet,
- we're waiting for a verdict */
- IPQ_PS_VERDICT /* Packet has been assigned verdict,
- waiting to be reinjected */
-};
-#define IPQ_PS_MAX IPQ_PS_VERDICT
-
-/* The queue operates in one of these states */
-enum {
- IPQ_QS_HOLD, /* Hold all packets in queue */
- IPQ_QS_COPY, /* Copy metadata and/or packets to user */
- IPQ_QS_FLUSH /* Flush and drop all queue entries */
-};
-#define IPQ_QS_MAX IPQ_QS_FLUSH
-
-/* Modes requested by peer */
-enum {
- IPQ_COPY_NONE, /* Copy nothing */
+ IPQ_COPY_NONE, /* Initial mode, packets are dropped */
IPQ_COPY_META, /* Copy metadata */
IPQ_COPY_PACKET /* Copy metadata + packet (range) */
-};
+};
#define IPQ_COPY_MAX IPQ_COPY_PACKET
/* Types of messages */
#define IPQM_BASE 0x10 /* standard netlink messages below this */
-#define IPQM_MODE (IPQM_BASE + 1) /* Mode request from peer */
-#define IPQM_VERDICT (IPQM_BASE + 2) /* Verdict from peer */
-#define IPQM_PACKET (IPQM_BASE + 3) /* Packet from kernel */
+#define IPQM_MODE (IPQM_BASE + 1) /* Mode request from peer */
+#define IPQM_VERDICT (IPQM_BASE + 2) /* Verdict from peer */
+#define IPQM_PACKET (IPQM_BASE + 3) /* Packet from kernel */
#define IPQM_MAX (IPQM_BASE + 4)
#endif /*_IP_QUEUE_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_REJECT.h b/include/linux/netfilter_ipv4/ipt_REJECT.h
index 1ceebe211..eeafdf468 100644
--- a/include/linux/netfilter_ipv4/ipt_REJECT.h
+++ b/include/linux/netfilter_ipv4/ipt_REJECT.h
@@ -6,8 +6,7 @@ enum ipt_reject_with {
IPT_ICMP_HOST_UNREACHABLE,
IPT_ICMP_PROT_UNREACHABLE,
IPT_ICMP_PORT_UNREACHABLE,
- IPT_ICMP_ECHOREPLY,
- IPT_TCP_RESET,
+ IPT_ICMP_ECHOREPLY
};
struct ipt_reject_info {
diff --git a/include/linux/nfs.h b/include/linux/nfs.h
index 3dca58cbc..aa36f7bd3 100644
--- a/include/linux/nfs.h
+++ b/include/linux/nfs.h
@@ -9,6 +9,7 @@
#include <linux/sunrpc/msg_prot.h>
+#define NFS_PROGRAM 100003
#define NFS_PORT 2049
#define NFS_MAXDATA 8192
#define NFS_MAXPATHLEN 1024
@@ -26,7 +27,9 @@
#define NFSMODE_SOCK 0140000
#define NFSMODE_FIFO 0010000
-
+#define NFS_MNT_PROGRAM 100005
+#define NFS_MNT_PORT 627
+
/*
* NFS stats. The good thing with these values is that NFSv3 errors are
* a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
@@ -84,187 +87,27 @@ enum nfs_ftype {
NFFIFO = 8
};
+#if defined(__KERNEL__)
+/*
+ * This is the kernel NFS client file handle representation
+ */
+#define NFS_MAXFHSIZE 64
struct nfs_fh {
- char data[NFS_FHSIZE];
+ unsigned short size;
+ unsigned char data[NFS_MAXFHSIZE];
};
-#define NFS_PROGRAM 100003
-#define NFS_VERSION 2
-#define NFSPROC_NULL 0
-#define NFSPROC_GETATTR 1
-#define NFSPROC_SETATTR 2
-#define NFSPROC_ROOT 3
-#define NFSPROC_LOOKUP 4
-#define NFSPROC_READLINK 5
-#define NFSPROC_READ 6
-#define NFSPROC_WRITECACHE 7
-#define NFSPROC_WRITE 8
-#define NFSPROC_CREATE 9
-#define NFSPROC_REMOVE 10
-#define NFSPROC_RENAME 11
-#define NFSPROC_LINK 12
-#define NFSPROC_SYMLINK 13
-#define NFSPROC_MKDIR 14
-#define NFSPROC_RMDIR 15
-#define NFSPROC_READDIR 16
-#define NFSPROC_STATFS 17
-
-/* Mount support for NFSroot */
-#ifdef __KERNEL__
-#define NFS_MNT_PROGRAM 100005
-#define NFS_MNT_VERSION 1
-#define NFS_MNT_PORT 627
-#define NFS_MNTPROC_MNT 1
-#define NFS_MNTPROC_UMNT 3
-
/*
* This is really a general kernel constant, but since nothing like
* this is defined in the kernel headers, I have to do it here.
*/
#define NFS_OFFSET_MAX ((__s64)((~(__u64)0) >> 1))
-#endif /* __KERNEL__ */
-
-#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
-
-extern struct rpc_program nfs_program;
-extern struct rpc_stat nfs_rpcstat;
-
-struct nfs_time {
- __u32 seconds;
- __u32 useconds;
-};
-
-struct nfs_fattr {
- enum nfs_ftype type;
- __u32 mode;
- __u32 nlink;
- __u32 uid;
- __u32 gid;
- __u32 size;
- __u32 blocksize;
- __u32 rdev;
- __u32 blocks;
- __u32 fsid;
- __u32 fileid;
- struct nfs_time atime;
- struct nfs_time mtime;
- struct nfs_time ctime;
-};
-
-struct nfs_fsinfo {
- __u32 tsize;
- __u32 bsize;
- __u32 blocks;
- __u32 bfree;
- __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;
- 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
-
-struct nfs_sattrargs {
- struct nfs_fh * fh;
- struct iattr * sattr;
-};
-
-struct nfs_diropargs {
- struct nfs_fh * fh;
- const char * name;
-};
-
-struct nfs_readlinkargs {
- struct nfs_fh * fh;
- const void * buffer;
-};
-
-struct nfs_readargs {
- struct nfs_fh * fh;
- __u32 offset;
- __u32 count;
- void * buffer;
-};
-
-struct nfs_createargs {
- struct nfs_fh * fh;
- const char * name;
- struct iattr * sattr;
-};
-
-struct nfs_renameargs {
- struct nfs_fh * fromfh;
- const char * fromname;
- struct nfs_fh * tofh;
- const char * toname;
-};
-
-struct nfs_linkargs {
- struct nfs_fh * fromfh;
- struct nfs_fh * tofh;
- const char * toname;
-};
-
-struct nfs_symlinkargs {
- struct nfs_fh * fromfh;
- const char * fromname;
- const char * topath;
- struct iattr * sattr;
-};
-
-struct nfs_readdirargs {
- struct nfs_fh * fh;
- __u32 cookie;
- void * buffer;
- int bufsiz;
-};
-
-struct nfs_diropok {
- struct nfs_fh * fh;
- struct nfs_fattr * fattr;
-};
-
-struct nfs_readres {
- struct nfs_fattr * fattr;
- unsigned int count;
-};
-
-struct nfs_readdirres {
- void * buffer;
- int bufsiz;
- u32 cookie;
-};
-
-#endif /* NFS_NEED_XDR_TYPES */
#endif /* __KERNEL__ */
-
-#endif
+#endif /* _LINUX_NFS_H */
diff --git a/include/linux/nfs2.h b/include/linux/nfs2.h
new file mode 100644
index 000000000..0ed951713
--- /dev/null
+++ b/include/linux/nfs2.h
@@ -0,0 +1,74 @@
+/*
+ * NFS protocol definitions
+ *
+ * This file contains constants for Version 2 of the protocol.
+ */
+#ifndef _LINUX_NFS2_H
+#define _LINUX_NFS2_H
+
+#define NFS2_PORT 2049
+#define NFS2_MAXDATA 8192
+#define NFS2_MAXPATHLEN 1024
+#define NFS2_MAXNAMLEN 255
+#define NFS2_MAXGROUPS 16
+#define NFS2_FHSIZE 32
+#define NFS2_COOKIESIZE 4
+#define NFS2_FIFO_DEV (-1)
+#define NFS2MODE_FMT 0170000
+#define NFS2MODE_DIR 0040000
+#define NFS2MODE_CHR 0020000
+#define NFS2MODE_BLK 0060000
+#define NFS2MODE_REG 0100000
+#define NFS2MODE_LNK 0120000
+#define NFS2MODE_SOCK 0140000
+#define NFS2MODE_FIFO 0010000
+
+
+/* NFSv2 file types - beware, these are not the same in NFSv3 */
+enum nfs2_ftype {
+ NF2NON = 0,
+ NF2REG = 1,
+ NF2DIR = 2,
+ NF2BLK = 3,
+ NF2CHR = 4,
+ NF2LNK = 5,
+ NF2SOCK = 6,
+ NF2BAD = 7,
+ NF2FIFO = 8
+};
+
+struct nfs2_fh {
+ char data[NFS2_FHSIZE];
+};
+
+/*
+ * Procedure numbers for NFSv2
+ */
+#define NFS2_VERSION 2
+#define NFSPROC_NULL 0
+#define NFSPROC_GETATTR 1
+#define NFSPROC_SETATTR 2
+#define NFSPROC_ROOT 3
+#define NFSPROC_LOOKUP 4
+#define NFSPROC_READLINK 5
+#define NFSPROC_READ 6
+#define NFSPROC_WRITECACHE 7
+#define NFSPROC_WRITE 8
+#define NFSPROC_CREATE 9
+#define NFSPROC_REMOVE 10
+#define NFSPROC_RENAME 11
+#define NFSPROC_LINK 12
+#define NFSPROC_SYMLINK 13
+#define NFSPROC_MKDIR 14
+#define NFSPROC_RMDIR 15
+#define NFSPROC_READDIR 16
+#define NFSPROC_STATFS 17
+
+#define NFS_MNT_PROGRAM 100005
+#define NFS_MNT_VERSION 1
+#define MNTPROC_NULL 0
+#define MNTPROC_MNT 1
+#define MNTPROC_UMNT 3
+#define MNTPROC_UMNTALL 4
+
+#endif /* _LINUX_NFS2_H */
diff --git a/include/linux/nfs3.h b/include/linux/nfs3.h
index cf5405b35..1f45a9296 100644
--- a/include/linux/nfs3.h
+++ b/include/linux/nfs3.h
@@ -4,14 +4,12 @@
#ifndef _LINUX_NFS3_H
#define _LINUX_NFS3_H
-#include <linux/sunrpc/msg_prot.h>
-#include <linux/nfs.h>
-
#define NFS3_PORT 2049
-#define NFS3_MAXDATA 8192
+#define NFS3_MAXDATA 32768
#define NFS3_MAXPATHLEN PATH_MAX
#define NFS3_MAXNAMLEN NAME_MAX
#define NFS3_MAXGROUPS 16
+#define NFS3_FHSIZE 64
#define NFS3_COOKIESIZE 4
#define NFS3_FIFO_DEV (-1)
#define NFS3MODE_FMT 0170000
@@ -23,7 +21,6 @@
#define NFS3MODE_SOCK 0140000
#define NFS3MODE_FIFO 0010000
-
/* Flags for access() call */
#define NFS3_ACCESS_READ 0x0001
#define NFS3_ACCESS_LOOKUP 0x0002
@@ -33,9 +30,11 @@
#define NFS3_ACCESS_EXECUTE 0x0020
/* Flags for create mode */
-#define NFS3_CREATE_UNCHECKED 0
-#define NFS3_CREATE_GUARDED 1
-#define NFS3_CREATE_EXCLUSIVE 2
+enum nfs3_createmode {
+ NFS3_CREATE_UNCHECKED = 0,
+ NFS3_CREATE_GUARDED = 1,
+ NFS3_CREATE_EXCLUSIVE = 2
+};
/* NFSv3 file system properties */
#define NFS3_FSF_LINK 0x0001
@@ -60,180 +59,41 @@ enum nfs3_ftype {
};
#define NFS3_VERSION 3
-#define NFSPROC_NULL 0
-#define NFSPROC_GETATTR 1
-#define NFSPROC_SETATTR 2
-#define NFSPROC_ROOT 3
-#define NFSPROC_LOOKUP 4
-#define NFSPROC_READLINK 5
-#define NFSPROC_READ 6
-#define NFSPROC_WRITECACHE 7
-#define NFSPROC_WRITE 8
-#define NFSPROC_CREATE 9
-#define NFSPROC_REMOVE 10
-#define NFSPROC_RENAME 11
-#define NFSPROC_LINK 12
-#define NFSPROC_SYMLINK 13
-#define NFSPROC_MKDIR 14
-#define NFSPROC_RMDIR 15
-#define NFSPROC_READDIR 16
-#define NFSPROC_STATFS 17
+#define NFS3PROC_NULL 0
+#define NFS3PROC_GETATTR 1
+#define NFS3PROC_SETATTR 2
+#define NFS3PROC_LOOKUP 3
+#define NFS3PROC_ACCESS 4
+#define NFS3PROC_READLINK 5
+#define NFS3PROC_READ 6
+#define NFS3PROC_WRITE 7
+#define NFS3PROC_CREATE 8
+#define NFS3PROC_MKDIR 9
+#define NFS3PROC_SYMLINK 10
+#define NFS3PROC_MKNOD 11
+#define NFS3PROC_REMOVE 12
+#define NFS3PROC_RMDIR 13
+#define NFS3PROC_RENAME 14
+#define NFS3PROC_LINK 15
+#define NFS3PROC_READDIR 16
+#define NFS3PROC_READDIRPLUS 17
+#define NFS3PROC_FSSTAT 18
+#define NFS3PROC_FSINFO 19
+#define NFS3PROC_PATHCONF 20
+#define NFS3PROC_COMMIT 21
+
+#define NFS_MNT3_PROGRAM 100005
+#define NFS_MNT3_VERSION 3
+#define MOUNTPROC3_NULL 0
+#define MOUNTPROC3_MNT 1
+#define MOUNTPROC3_UMNT 3
+#define MOUNTPROC3_UMNTALL 4
+
#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
/* Number of 32bit words in post_op_attr */
#define NFS3_POST_OP_ATTR_WORDS 22
-struct nfs3_fattr {
- enum nfs3_ftype type;
- __u32 mode;
- __u32 nlink;
- __u32 uid;
- __u32 gid;
- __u64 size;
- __u64 used;
- __u32 rdev_maj;
- __u32 rdev_min;
- __u32 fsid;
- __u32 fileid;
- struct nfs_time atime;
- struct nfs_time mtime;
- struct nfs_time ctime;
-};
-
-struct nfs3_wcc_attr {
- __u64 size;
- struct nfs_time mtime;
- struct nfs_time ctime;
-};
-
-struct nfs3_wcc_data {
- struct nfs3_wcc_attr before;
- struct nfs3_wcc_attr after;
-};
-
-struct nfs3_sattr {
- __u32 valid;
- __u32 mode;
- __u32 uid;
- __u32 gid;
- __u64 size;
- struct nfs_time atime;
- struct nfs_time mtime;
-};
-
-struct nfs3_entry {
- __u32 fileid;
- char * name;
- unsigned int length;
- __u32 cookie;
- __u32 eof;
-};
-
-struct nfs3_fsinfo {
- __u32 tsize;
- __u32 bsize;
- __u32 blocks;
- __u32 bfree;
- __u32 bavail;
-};
-
-#ifdef NFS_NEED_XDR_TYPES
-
-struct nfs3_sattrargs {
- struct nfs_fh * fh;
- struct nfs_sattr * sattr;
-};
-
-struct nfs3_diropargs {
- struct nfs_fh * fh;
- const char * name;
-};
-
-struct nfs3_readargs {
- struct nfs_fh * fh;
- __u32 offset;
- __u32 count;
- void * buffer;
-};
-
-struct nfs3_writeargs {
- struct nfs_fh * fh;
- __u32 offset;
- __u32 count;
- const void * buffer;
-};
-
-struct nfs3_createargs {
- struct nfs_fh * fh;
- const char * name;
- struct nfs_sattr * sattr;
-};
-
-struct nfs3_renameargs {
- struct nfs_fh * fromfh;
- const char * fromname;
- struct nfs_fh * tofh;
- const char * toname;
-};
-
-struct nfs3_linkargs {
- struct nfs_fh * fromfh;
- struct nfs_fh * tofh;
- const char * toname;
-};
-
-struct nfs3_symlinkargs {
- struct nfs_fh * fromfh;
- const char * fromname;
- const char * topath;
- struct nfs_sattr * sattr;
-};
-
-struct nfs3_readdirargs {
- struct nfs_fh * fh;
- __u32 cookie;
- void * buffer;
- unsigned int bufsiz;
-};
-
-struct nfs3_diropok {
- struct nfs_fh * fh;
- struct nfs_fattr * fattr;
-};
-
-struct nfs3_readres {
- struct nfs_fattr * fattr;
- unsigned int count;
-};
-
-struct nfs3_readlinkres {
- char ** string;
- unsigned int * lenp;
- unsigned int maxlen;
- void * buffer;
-};
-
-struct nfs3_readdirres {
- void * buffer;
- unsigned int bufsiz;
-};
-
-/*
- * The following are for NFSv3
- */
-struct nfs3_fh {
- __u32 size;
- __u8 data[NFS3_FHSIZE]
-};
-
-struct nfs3_wcc_attr {
- __u64 size;
- struct nfs_time mtime;
- struct nfs_time ctime;
-};
-
-#endif /* NFS_NEED_XDR_TYPES */
#endif /* __KERNEL__ */
-
-#endif
+#endif /* _LINUX_NFS3_H */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 19f1740f1..5f9a5dded 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -10,14 +10,16 @@
#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/mm.h>
+#include <linux/pagemap.h>
+
+#include <linux/sunrpc/debug.h>
-#include <linux/sunrpc/sched.h>
#include <linux/nfs.h>
-#include <linux/nfs_mount.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_xdr.h>
/*
* Enable debugging support for nfs client.
@@ -63,17 +65,20 @@
#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_PROTO(inode) (NFS_SERVER(inode)->rpc_ops)
#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_COOKIEVERF(inode) ((inode)->u.nfs_i.cookieverf)
#define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies)
-#define NFS_OLDMTIME(inode) ((inode)->u.nfs_i.read_cache_mtime)
+#define NFS_CACHE_CTIME(inode) ((inode)->u.nfs_i.read_cache_ctime)
+#define NFS_CACHE_MTIME(inode) ((inode)->u.nfs_i.read_cache_mtime)
+#define NFS_CACHE_ATIME(inode) ((inode)->u.nfs_i.read_cache_atime)
+#define NFS_CACHE_ISIZE(inode) ((inode)->u.nfs_i.read_cache_isize)
#define NFS_NEXTSCAN(inode) ((inode)->u.nfs_i.nextscan)
#define NFS_CACHEINV(inode) \
do { \
- NFS_READTIME(inode) = jiffies - 1000000; \
- NFS_OLDMTIME(inode) = 0; \
+ NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
} while (0)
#define NFS_ATTRTIMEO(inode) ((inode)->u.nfs_i.attrtimeo)
#define NFS_MINATTRTIMEO(inode) \
@@ -82,15 +87,18 @@ do { \
#define NFS_MAXATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
: NFS_SERVER(inode)->acregmax)
+#define NFS_ATTRTIMEO_UPDATE(inode) ((inode)->u.nfs_i.attrtimeo_timestamp)
#define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
-#define NFS_COOKIES(inode) ((inode)->u.nfs_i.cookies)
-#define NFS_DIREOF(inode) ((inode)->u.nfs_i.direof)
#define NFS_FILEID(inode) ((inode)->u.nfs_i.fileid)
#define NFS_FSID(inode) ((inode)->u.nfs_i.fsid)
+/* Inode Flags */
+#define NFS_USE_READDIRPLUS(inode) ((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
+#define NFS_MONOTONE_COOKIES(inode) ((NFS_SERVER(inode)->flags & NFS_NONMONOTONE_COOKIES) ? 0 : 1)
+
/*
* These are the default flags for swap requests
*/
@@ -124,45 +132,6 @@ unsigned long page_index(struct page *page)
}
#ifdef __KERNEL__
-
-/*
- * linux/fs/nfs/proc.c
- */
-extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr);
-extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr, struct iattr *sattr);
-extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr);
-extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
- int swap, unsigned long offset, unsigned int count,
- void *buffer, struct nfs_fattr *fattr);
-extern int 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);
-extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct iattr *sattr,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr);
-extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir,
- const char *name);
-extern int nfs_proc_rename(struct nfs_server *server,
- struct nfs_fh *old_dir, const char *old_name,
- struct nfs_fh *new_dir, const char *new_name);
-extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fh *dir, const char *name);
-extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, const char *path,
- struct iattr *sattr);
-extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct iattr *sattr,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr);
-extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
- const char *name);
-extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fsinfo *res);
-
-
/*
* linux/fs/nfs/inode.c
*/
@@ -191,8 +160,6 @@ extern struct address_space_operations nfs_file_aops;
extern struct inode_operations nfs_dir_inode_operations;
extern struct file_operations nfs_dir_operations;
extern struct dentry_operations nfs_dentry_operations;
-extern void nfs_flush_dircache(struct inode *);
-extern void nfs_free_dircache(struct inode *);
/*
* linux/fs/nfs/symlink.c
@@ -244,7 +211,7 @@ nfs_wb_all(struct inode *inode)
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);
+ int error = nfs_sync_file(inode, 0, page_index(page), 1, FLUSH_WAIT | FLUSH_STABLE);
return (error < 0) ? error : 0;
}
@@ -268,6 +235,7 @@ extern int nfs_readpage(struct dentry *, struct page *);
* (Used only by nfsroot module)
*/
extern int nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+extern int nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *);
/*
* inline functions
@@ -281,6 +249,30 @@ nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
return __nfs_revalidate_inode(server, dentry);
}
+static inline loff_t
+nfs_size_to_loff_t(__u64 size)
+{
+ loff_t maxsz = (((loff_t) ULONG_MAX) << PAGE_CACHE_SHIFT) + PAGE_CACHE_SIZE - 1;
+ if (size > maxsz)
+ return maxsz;
+ return (loff_t) size;
+}
+
+static inline ino_t
+nfs_fileid_to_ino_t(u64 fileid)
+{
+ ino_t ino = (ino_t) fileid;
+ if (sizeof(ino_t) < sizeof(u64))
+ ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8;
+ return ino;
+}
+
+static inline time_t
+nfs_time_to_secs(__u64 time)
+{
+ return (time_t)(time >> 32);
+}
+
/* NFS root */
extern int nfs_root_mount(struct super_block *sb);
diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h
index d4a80639b..05e259900 100644
--- a/include/linux/nfs_fs_i.h
+++ b/include/linux/nfs_fs_i.h
@@ -1,8 +1,8 @@
#ifndef _NFS_FS_I
#define _NFS_FS_I
-#include <linux/nfs.h>
-#include <linux/pipe_fs_i.h>
+#include <asm/types.h>
+#include <linux/list.h>
/*
* nfs fs inode data in memory
@@ -11,8 +11,8 @@ struct nfs_inode_info {
/*
* The 64bit 'inode number'
*/
- __u32 fsid;
- __u32 fileid;
+ __u64 fsid;
+ __u64 fileid;
/*
* Various flags
@@ -37,8 +37,18 @@ struct nfs_inode_info {
* mtime != read_cache_mtime
*/
unsigned long read_cache_jiffies;
- unsigned long read_cache_mtime;
+ __u64 read_cache_ctime;
+ __u64 read_cache_mtime;
+ __u64 read_cache_atime;
+ __u64 read_cache_isize;
unsigned long attrtimeo;
+ unsigned long attrtimeo_timestamp;
+
+ /*
+ * This is the cookie verifier used for NFSv3 readdir
+ * operations
+ */
+ __u32 cookieverf[2];
/*
* This is the list of dirty unwritten pages.
@@ -55,15 +65,12 @@ struct nfs_inode_info {
struct inode *hash_next,
*hash_prev;
unsigned long nextscan;
-
- /* Readdir caching information. */
- void *cookies;
- u32 direof;
};
/*
* Legal inode flag values
*/
+#define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */
#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 */
@@ -74,6 +81,7 @@ struct nfs_inode_info {
struct nfs_lock_info {
u32 state;
u32 flags;
+ struct nlm_host *host;
};
/*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 418faaa33..da76c1d62 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -1,22 +1,22 @@
#ifndef _NFS_FS_SB
#define _NFS_FS_SB
-#include <linux/nfs.h>
-#include <linux/in.h>
-
/*
* NFS client parameters stored in the superblock.
*/
struct nfs_server {
struct rpc_clnt * client; /* RPC client handle */
+ struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
int flags; /* various flags */
- int rsize; /* read size */
- int wsize; /* write size */
+ unsigned int rsize; /* read size */
+ unsigned int wsize; /* write size */
+ unsigned int dtsize; /* readdir size */
unsigned int bsize; /* server block size */
unsigned int acregmin; /* attr cache timeouts */
unsigned int acregmax;
unsigned int acdirmin;
unsigned int acdirmax;
+ unsigned int namelen;
char * hostname; /* remote hostname */
struct nfs_reqlist * rw_requests; /* async read/write requests */
};
@@ -26,7 +26,6 @@ struct nfs_server {
*/
struct nfs_sb_info {
struct nfs_server s_server;
- struct nfs_fh s_root;
};
#endif
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 60493b150..8e11ef368 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -8,6 +8,8 @@
*
* structure passed from user-space to kernel-space during an nfs mount
*/
+#include <linux/in.h>
+#include <linux/nfs.h>
/*
* WARNING! Do not delete or change the order of these fields. If
@@ -16,12 +18,12 @@
* mount-to-kernel version compatibility. Some of these aren't used yet
* but here they are anyway.
*/
-#define NFS_MOUNT_VERSION 3
+#define NFS_MOUNT_VERSION 4
struct nfs_mount_data {
int version; /* 1 */
int fd; /* 1 */
- struct nfs_fh root; /* 1 */
+ struct nfs2_fh old_root; /* 1 */
int flags; /* 1 */
int rsize; /* 1 */
int wsize; /* 1 */
@@ -35,6 +37,7 @@ struct nfs_mount_data {
char hostname[256]; /* 1 */
int namlen; /* 2 */
unsigned int bsize; /* 3 */
+ struct nfs_fh root; /* 4 */
};
/* bits in the flags field */
@@ -49,5 +52,13 @@ struct nfs_mount_data {
#define NFS_MOUNT_VER3 0x0080 /* 3 */
#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
#define NFS_MOUNT_NONLM 0x0200 /* 3 */
+#define NFS_MOUNT_FLAGMASK 0xFFFF
+
+/*
+ * Private flags - not to be set by mount program
+ */
+#ifdef __KERNEL__
+#define NFS_NONMONOTONE_COOKIES 0x00010000
+#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
new file mode 100644
index 000000000..eca3e1b2d
--- /dev/null
+++ b/include/linux/nfs_xdr.h
@@ -0,0 +1,374 @@
+#ifndef _LINUX_NFS_XDR_H
+#define _LINUX_NFS_XDR_H
+
+extern struct rpc_program nfs_program;
+extern struct rpc_stat nfs_rpcstat;
+
+struct nfs_fattr {
+ unsigned short valid; /* which fields are valid */
+ __u64 pre_size; /* pre_op_attr.size */
+ __u64 pre_mtime; /* pre_op_attr.mtime */
+ __u64 pre_ctime; /* pre_op_attr.ctime */
+ enum nfs_ftype type; /* always use NFSv2 types */
+ __u32 mode;
+ __u32 nlink;
+ __u32 uid;
+ __u32 gid;
+ __u64 size;
+ union {
+ struct {
+ __u32 blocksize;
+ __u32 blocks;
+ } nfs2;
+ struct {
+ __u64 used;
+ } nfs3;
+ } du;
+ __u32 rdev;
+ __u64 fsid;
+ __u64 fileid;
+ __u64 atime;
+ __u64 mtime;
+ __u64 ctime;
+};
+
+#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */
+#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
+#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
+
+/*
+ * Info on the file system
+ */
+struct nfs_fsinfo {
+ __u32 rtmax; /* max. read transfer size */
+ __u32 rtpref; /* pref. read transfer size */
+ __u32 rtmult; /* reads should be multiple of this */
+ __u32 wtmax; /* max. write transfer size */
+ __u32 wtpref; /* pref. write transfer size */
+ __u32 wtmult; /* writes should be multiple of this */
+ __u32 dtpref; /* pref. readdir transfer size */
+ __u64 maxfilesize;
+ __u64 bsize; /* block size */
+ __u64 tbytes; /* total size in bytes */
+ __u64 fbytes; /* # of free bytes */
+ __u64 abytes; /* # of bytes available to user */
+ __u64 tfiles; /* # of files */
+ __u64 ffiles; /* # of free files */
+ __u64 afiles; /* # of files available to user */
+ __u32 linkmax;/* max # of hard links */
+ __u32 namelen;/* max name length */
+};
+
+/* Arguments to the read call.
+ * Note that NFS_READ_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
+ */
+#define NFS_READ_MAXIOV 8
+
+struct nfs_readargs {
+ struct nfs_fh * fh;
+ __u64 offset;
+ __u32 count;
+ unsigned int nriov;
+ struct iovec iov[NFS_READ_MAXIOV];
+};
+
+struct nfs_readres {
+ struct nfs_fattr * fattr;
+ unsigned int count;
+ int eof;
+};
+
+/* Arguments to the write call.
+ * Note that NFS_WRITE_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
+ */
+#define NFS_WRITE_MAXIOV 8
+struct nfs_writeargs {
+ struct nfs_fh * fh;
+ __u32 offset;
+ __u32 count;
+ 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;
+};
+
+/*
+ * Argument struct for decode_entry function
+ */
+struct nfs_entry {
+ struct page * page;
+ __u64 ino;
+ __u64 cookie,
+ prev_cookie;
+ const char * name;
+ unsigned int len;
+ int eof;
+ struct nfs_fh fh;
+ struct nfs_fattr fattr;
+ unsigned long offset,
+ prev;
+};
+
+/*
+ * The following types are for NFSv2 only.
+ */
+struct nfs_sattrargs {
+ struct nfs_fh * fh;
+ struct iattr * sattr;
+};
+
+struct nfs_diropargs {
+ struct nfs_fh * fh;
+ const char * name;
+ unsigned int len;
+};
+
+struct nfs_createargs {
+ struct nfs_fh * fh;
+ const char * name;
+ unsigned int len;
+ struct iattr * sattr;
+};
+
+struct nfs_renameargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ unsigned int fromlen;
+ struct nfs_fh * tofh;
+ const char * toname;
+ unsigned int tolen;
+};
+
+struct nfs_linkargs {
+ struct nfs_fh * fromfh;
+ struct nfs_fh * tofh;
+ const char * toname;
+ unsigned int tolen;
+};
+
+struct nfs_symlinkargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ unsigned int fromlen;
+ const char * topath;
+ unsigned int tolen;
+ struct iattr * sattr;
+};
+
+struct nfs_readdirargs {
+ struct nfs_fh * fh;
+ __u32 cookie;
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs_diropok {
+ struct nfs_fh * fh;
+ struct nfs_fattr * fattr;
+};
+
+struct nfs_readlinkargs {
+ struct nfs_fh * fh;
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs_readlinkres {
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs_readdirres {
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs3_sattrargs {
+ struct nfs_fh * fh;
+ struct iattr * sattr;
+ unsigned int guard;
+ __u64 guardtime;
+};
+
+struct nfs3_diropargs {
+ struct nfs_fh * fh;
+ const char * name;
+ unsigned int len;
+};
+
+struct nfs3_accessargs {
+ struct nfs_fh * fh;
+ __u32 access;
+};
+
+struct nfs3_createargs {
+ struct nfs_fh * fh;
+ const char * name;
+ unsigned int len;
+ struct iattr * sattr;
+ enum nfs3_createmode createmode;
+ __u32 verifier[2];
+};
+
+struct nfs3_mkdirargs {
+ struct nfs_fh * fh;
+ const char * name;
+ unsigned int len;
+ struct iattr * sattr;
+};
+
+struct nfs3_symlinkargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ unsigned int fromlen;
+ const char * topath;
+ unsigned int tolen;
+ struct iattr * sattr;
+};
+
+struct nfs3_mknodargs {
+ struct nfs_fh * fh;
+ const char * name;
+ unsigned int len;
+ enum nfs3_ftype type;
+ struct iattr * sattr;
+ dev_t rdev;
+};
+
+struct nfs3_renameargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ unsigned int fromlen;
+ struct nfs_fh * tofh;
+ const char * toname;
+ unsigned int tolen;
+};
+
+struct nfs3_linkargs {
+ struct nfs_fh * fromfh;
+ struct nfs_fh * tofh;
+ const char * toname;
+ unsigned int tolen;
+};
+
+struct nfs3_readdirargs {
+ struct nfs_fh * fh;
+ __u64 cookie;
+ __u32 verf[2];
+ void * buffer;
+ unsigned int bufsiz;
+ int plus;
+};
+
+struct nfs3_diropres {
+ struct nfs_fattr * dir_attr;
+ struct nfs_fh * fh;
+ struct nfs_fattr * fattr;
+};
+
+struct nfs3_accessres {
+ struct nfs_fattr * fattr;
+ __u32 access;
+};
+
+struct nfs3_readlinkargs {
+ struct nfs_fh * fh;
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs3_readlinkres {
+ struct nfs_fattr * fattr;
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs3_renameres {
+ struct nfs_fattr * fromattr;
+ struct nfs_fattr * toattr;
+};
+
+struct nfs3_linkres {
+ struct nfs_fattr * dir_attr;
+ struct nfs_fattr * fattr;
+};
+
+struct nfs3_readdirres {
+ struct nfs_fattr * dir_attr;
+ __u32 * verf;
+ void * buffer;
+ unsigned int bufsiz;
+ int plus;
+};
+
+/*
+ * RPC procedure vector for NFSv2/NFSv3 demuxing
+ */
+struct nfs_rpc_ops {
+ int version; /* Protocol version */
+
+ int (*getroot) (struct nfs_server *, struct nfs_fh *,
+ struct nfs_fattr *);
+ int (*getattr) (struct dentry *, struct nfs_fattr *);
+ int (*setattr) (struct dentry *, struct nfs_fattr *,
+ struct iattr *);
+ int (*lookup) (struct dentry *, struct qstr *,
+ struct nfs_fh *, struct nfs_fattr *);
+ int (*access) (struct dentry *, int , int);
+ int (*readlink)(struct dentry *, void *, unsigned int);
+ int (*read) (struct dentry *, struct nfs_fattr *,
+ int, loff_t, unsigned int,
+ void *buffer, int *eofp);
+ int (*write) (struct dentry *, struct nfs_fattr *,
+ int, loff_t, unsigned int,
+ void *buffer, struct nfs_writeverf *verfp);
+ int (*commit) (struct dentry *, struct nfs_fattr *,
+ unsigned long, unsigned int);
+ int (*create) (struct dentry *, struct qstr *, struct iattr *,
+ int, struct nfs_fh *, struct nfs_fattr *);
+ int (*remove) (struct dentry *, struct qstr *);
+ int (*rename) (struct dentry *, struct qstr *,
+ struct dentry *, struct qstr *);
+ int (*link) (struct dentry *, struct dentry *, struct qstr *);
+ int (*symlink) (struct dentry *, struct qstr *, struct qstr *,
+ struct iattr *, struct nfs_fh *,
+ struct nfs_fattr *);
+ int (*mkdir) (struct dentry *, struct qstr *, struct iattr *,
+ struct nfs_fh *, struct nfs_fattr *);
+ int (*rmdir) (struct dentry *, struct qstr *);
+ int (*readdir) (struct dentry *, u64 cookie, void *, unsigned int,
+ int);
+ int (*mknod) (struct dentry *, struct qstr *, struct iattr *,
+ dev_t, struct nfs_fh *, struct nfs_fattr *);
+ int (*statfs) (struct nfs_server *, struct nfs_fh *,
+ struct nfs_fsinfo *);
+ u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
+};
+
+/*
+ * NFS_CALL(getattr, inode, (fattr));
+ * into
+ * NFS_PROTO(inode)->getattr(fattr);
+ */
+#define NFS_CALL(op, inode, args) NFS_PROTO(inode)->op args
+
+/*
+ * Function vectors etc. for the NFS client
+ */
+extern struct nfs_rpc_ops nfs_v2_clientops;
+extern struct nfs_rpc_ops nfs_v3_clientops;
+extern struct rpc_version nfs_version2;
+extern struct rpc_version nfs_version3;
+extern struct rpc_program nfs_program;
+
+#endif
diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h
index 22c7ff1e8..f59c6a6ef 100644
--- a/include/linux/nfsd/const.h
+++ b/include/linux/nfsd/const.h
@@ -10,6 +10,8 @@
#define _LINUX_NFSD_CONST_H
#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
/*
* Maximum protocol version supported by knfsd
@@ -21,18 +23,6 @@
*/
#define NFSSVC_MAXBLKSIZE 8192
-#define NFS2_MAXPATHLEN 1024
-#define NFS2_MAXNAMLEN 255
-#define NFS2_FHSIZE NFS_FHSIZE
-#define NFS2_COOKIESIZE 4
-
-#define NFS3_MAXPATHLEN PATH_MAX
-#define NFS3_MAXNAMLEN NAME_MAX
-#define NFS3_FHSIZE 64
-#define NFS3_COOKIEVERFSIZE 8
-#define NFS3_CREATEVERFSIZE 8
-#define NFS3_WRITEVERFSIZE 8
-
#ifdef __KERNEL__
#ifndef NFS_SUPER_MAGIC
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 55423de5c..a5eb6ca4c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -340,7 +340,7 @@ struct pci_dev {
struct resource dma_resource[DEVICE_COUNT_DMA];
struct resource irq_resource[DEVICE_COUNT_IRQ];
- char name[48]; /* device name */
+ char name[80]; /* device name */
char slot_name[8]; /* slot name */
int active; /* ISAPnP: device is active */
int ro; /* ISAPnP: read only */
@@ -510,6 +510,7 @@ int pci_assign_resource(struct pci_dev *dev, int i);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
+void pdev_assign_unassigned_resources(struct pci_dev *dev);
void pci_set_bus_ranges(void);
void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
int (*)(struct pci_dev *, u8, u8));
diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h
index d9ba188a0..fc39f2658 100644
--- a/include/linux/ppp_channel.h
+++ b/include/linux/ppp_channel.h
@@ -16,11 +16,12 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * ==FILEVERSION 20000225==
+ * ==FILEVERSION 20000322==
*/
#include <linux/list.h>
#include <linux/skbuff.h>
+#include <linux/poll.h>
struct ppp_channel;
@@ -61,7 +62,10 @@ extern int ppp_register_channel(struct ppp_channel *);
/* Detach a channel from its PPP unit (e.g. on hangup). */
extern void ppp_unregister_channel(struct ppp_channel *);
-/* Get the unit number associated with a channel */
+/* Get the channel number for a channel */
+extern int ppp_channel_index(struct ppp_channel *);
+
+/* Get the unit number associated with a channel, or -1 if none */
extern int ppp_unit_number(struct ppp_channel *);
/*
diff --git a/include/linux/proc_fs_i.h b/include/linux/proc_fs_i.h
index 5060d08fc..d4bde0989 100644
--- a/include/linux/proc_fs_i.h
+++ b/include/linux/proc_fs_i.h
@@ -2,7 +2,7 @@ struct proc_inode_info {
struct task_struct *task;
int type;
union {
- struct dentry *(*proc_get_link)(struct inode *);
+ int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
int (*proc_read)(struct task_struct *task, char *page);
} op;
struct file *file;
diff --git a/include/linux/raid/md_u.h b/include/linux/raid/md_u.h
index 9478513f9..6ba4ebbcd 100644
--- a/include/linux/raid/md_u.h
+++ b/include/linux/raid/md_u.h
@@ -17,6 +17,12 @@
/* ioctls */
+/* compat */
+#define REGISTER_DEV _IO (MD_MAJOR, 1)
+#define START_MD _IO (MD_MAJOR, 2)
+#define STOP_MD _IO (MD_MAJOR, 3)
+
+
/* status */
#define RAID_VERSION _IOR (MD_MAJOR, 0x10, mdu_version_t)
#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, mdu_array_info_t)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 75d010ca4..aa30e2cc1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -185,12 +185,13 @@ struct fs_struct {
atomic_t count;
int umask;
struct dentry * root, * pwd;
+ struct vfsmount * rootmnt, * pwdmnt;
};
#define INIT_FS { \
ATOMIC_INIT(1), \
0022, \
- NULL, NULL \
+ NULL, NULL, NULL, NULL \
}
/* Maximum number of active map areas.. This is a random (large) number */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 429089cc5..f229d4f82 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -207,20 +207,45 @@ extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb)
return (atomic_t *)(skb->end);
}
+/**
+ * skb_queue_empty - check if a queue is empty
+ * @list: queue head
+ *
+ * Returns true if the queue is empty, false otherwise
+ */
+
extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
{
return (list->next == (struct sk_buff *) list);
}
+/**
+ * skb_get - reference buffer
+ * @skb: buffer to reference
+ *
+ * Makes another reference to a socket buffer and returns a pointer
+ * to the buffer.
+ */
+
extern __inline__ struct sk_buff *skb_get(struct sk_buff *skb)
{
atomic_inc(&skb->users);
return skb;
}
-/* If users==1, we are the only owner and are can avoid redundant
+/*
+ * If users==1, we are the only owner and are can avoid redundant
* atomic change.
*/
+
+/**
+ * kfree_skb - free an sk_buff
+ * @skb: The buffer to free
+ *
+ * Drop a reference to the buffer and free it if the usage count has
+ * hit zero.
+ */
+
extern __inline__ void kfree_skb(struct sk_buff *skb)
{
if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
@@ -234,16 +259,47 @@ extern __inline__ void kfree_skb_fast(struct sk_buff *skb)
kfree_skbmem(skb);
}
+/**
+ * skb_cloned - is the buffer a clone
+ * @skb: Buffer to check
+ *
+ * Returns true if the buffer was generated with skb_clone and is
+ * one of multiple shared copies of the buffer. Cloned buffers are
+ * shared data so must not be written to under normal circumstances.
+ */
+
extern __inline__ int skb_cloned(struct sk_buff *skb)
{
return skb->cloned && atomic_read(skb_datarefp(skb)) != 1;
}
+/**
+ * skb_shared - is the buffer shared
+ * @skb: buffer to check
+ *
+ * Returns true if more than one person has a reference to this
+ * buffer.
+ */
+
extern __inline__ int skb_shared(struct sk_buff *skb)
{
return (atomic_read(&skb->users) != 1);
}
+/**
+ * skb_share_check - check if buffer is shared and if so clone it
+ * @skb: buffer to check
+ * @pri: priority for memory allocation
+ *
+ * If the buffer is shared the buffer is cloned and the old copy
+ * drops a reference. A new clone with a single reference is returned.
+ * If the buffer is not shared the original buffer is returned. When
+ * being called from interrupt status or with spinlocks held pri must
+ * be GFP_ATOMIC.
+ *
+ * NULL is returned on a memory allocation failure.
+ */
+
extern __inline__ struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
{
if (skb_shared(skb)) {
@@ -263,6 +319,20 @@ extern __inline__ struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
* a packet thats being forwarded.
*/
+/**
+ * skb_unshare - make a copy of a shared buffer
+ * @skb: buffer to check
+ * @pri: priority for memory allocation
+ *
+ * If the socket buffer is a clone then this function creates a new
+ * copy of the data, drops a reference count on the old copy and returns
+ * the new copy with the reference count at 1. If the buffer is not a clone
+ * the original buffer is returned. When called with a spinlock held or
+ * from interrupt state pri must be GFP_ATOMIC
+ *
+ * NULL is returned on a memory allocation failure.
+ */
+
extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
{
struct sk_buff *nskb;
@@ -273,11 +343,18 @@ extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
return nskb;
}
-/*
+/**
+ * skb_peek
+ * @list_: list to peek at
+ *
* Peek an sk_buff. Unlike most other operations you _MUST_
* be careful with this one. A peek leaves the buffer on the
- * list and someone else may run off with it. For an interrupt
- * type system cli() peek the buffer copy the data and sti();
+ * list and someone else may run off with it. You must hold
+ * the appropriate locks or have a private queue to do this.
+ *
+ * Returns NULL for an empty list or a pointer to the head element.
+ * The reference count is not incremented and the reference is therefore
+ * volatile. Use with caution.
*/
extern __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
@@ -288,6 +365,20 @@ extern __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
return list;
}
+/**
+ * skb_peek_tail
+ * @list_: list to peek at
+ *
+ * Peek an sk_buff. Unlike most other operations you _MUST_
+ * be careful with this one. A peek leaves the buffer on the
+ * list and someone else may run off with it. You must hold
+ * the appropriate locks or have a private queue to do this.
+ *
+ * Returns NULL for an empty list or a pointer to the tail element.
+ * The reference count is not incremented and the reference is therefore
+ * volatile. Use with caution.
+ */
+
extern __inline__ struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
{
struct sk_buff *list = ((struct sk_buff *)list_)->prev;
@@ -296,8 +387,11 @@ extern __inline__ struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
return list;
}
-/*
- * Return the length of an sk_buff queue
+/**
+ * skb_queue_len - get queue length
+ * @list_: list to measure
+ *
+ * Return the length of an sk_buff queue.
*/
extern __inline__ __u32 skb_queue_len(struct sk_buff_head *list_)
@@ -320,6 +414,17 @@ extern __inline__ void skb_queue_head_init(struct sk_buff_head *list)
* can only be called with interrupts disabled.
*/
+/**
+ * __skb_queue_head - queue a buffer at the list head
+ * @list: list to use
+ * @newsk: buffer to queue
+ *
+ * Queue a buffer at the start of a list. This function takes no locks
+ * and you must therefore hold required locks before calling it.
+ *
+ * A buffer cannot be placed on two lists at the same time.
+ */
+
extern __inline__ void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
{
struct sk_buff *prev, *next;
@@ -334,6 +439,19 @@ extern __inline__ void __skb_queue_head(struct sk_buff_head *list, struct sk_buf
prev->next = newsk;
}
+
+/**
+ * skb_queue_head - queue a buffer at the list head
+ * @list: list to use
+ * @newsk: buffer to queue
+ *
+ * Queue a buffer at the start of the list. This function takes the
+ * list lock and can be used safely with other locking sk_buff functions
+ * safely.
+ *
+ * A buffer cannot be placed on two lists at the same time.
+ */
+
extern __inline__ void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
{
unsigned long flags;
@@ -343,9 +461,17 @@ extern __inline__ void skb_queue_head(struct sk_buff_head *list, struct sk_buff
spin_unlock_irqrestore(&list->lock, flags);
}
-/*
- * Insert an sk_buff at the end of a list.
- */
+/**
+ * __skb_queue_tail - queue a buffer at the list tail
+ * @list: list to use
+ * @newsk: buffer to queue
+ *
+ * Queue a buffer at the end of a list. This function takes no locks
+ * and you must therefore hold required locks before calling it.
+ *
+ * A buffer cannot be placed on two lists at the same time.
+ */
+
extern __inline__ void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
{
@@ -361,6 +487,18 @@ extern __inline__ void __skb_queue_tail(struct sk_buff_head *list, struct sk_buf
prev->next = newsk;
}
+/**
+ * skb_queue_tail - queue a buffer at the list tail
+ * @list: list to use
+ * @newsk: buffer to queue
+ *
+ * Queue a buffer at the tail of the list. This function takes the
+ * list lock and can be used safely with other locking sk_buff functions
+ * safely.
+ *
+ * A buffer cannot be placed on two lists at the same time.
+ */
+
extern __inline__ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
{
unsigned long flags;
@@ -370,8 +508,13 @@ extern __inline__ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff
spin_unlock_irqrestore(&list->lock, flags);
}
-/*
- * Remove an sk_buff from a list.
+/**
+ * __skb_dequeue - remove from the head of the queue
+ * @list: list to dequeue from
+ *
+ * Remove the head of the list. This function does not take any locks
+ * so must be used with appropriate locks held only. The head item is
+ * returned or NULL if the list is empty.
*/
extern __inline__ struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
@@ -394,6 +537,15 @@ extern __inline__ struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
return result;
}
+/**
+ * skb_dequeue - remove from the head of the queue
+ * @list: list to dequeue from
+ *
+ * Remove the head of the list. The list lock is taken so the function
+ * may be used safely with other locking list functions. The head item is
+ * returned or NULL if the list is empty.
+ */
+
extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list)
{
long flags;
@@ -421,9 +573,16 @@ extern __inline__ void __skb_insert(struct sk_buff *newsk,
list->qlen++;
}
-/*
- * Place a packet before a given packet in a list
+/**
+ * skb_insert - insert a buffer
+ * @old: buffer to insert before
+ * @newsk: buffer to insert
+ *
+ * Place a packet before a given packet in a list. The list locks are taken
+ * and this function is atomic with respect to other list locked calls
+ * A buffer cannot be placed on two lists at the same time.
*/
+
extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
{
unsigned long flags;
@@ -442,6 +601,17 @@ extern __inline__ void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
__skb_insert(newsk, old, old->next, old->list);
}
+/**
+ * skb_append - append a buffer
+ * @old: buffer to insert after
+ * @newsk: buffer to insert
+ *
+ * Place a packet after a given packet in a list. The list locks are taken
+ * and this function is atomic with respect to other list locked calls.
+ * A buffer cannot be placed on two lists at the same time.
+ */
+
+
extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
{
unsigned long flags;
@@ -455,6 +625,7 @@ extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
* remove sk_buff from list. _Must_ be called atomically, and with
* the list known..
*/
+
extern __inline__ void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
{
struct sk_buff * next, * prev;
@@ -469,11 +640,17 @@ extern __inline__ void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *li
prev->next = next;
}
-/*
- * Remove an sk_buff from its list. Works even without knowing the list it
- * is sitting on, which can be handy at times. It also means that THE LIST
- * MUST EXIST when you unlink. Thus a list must have its contents unlinked
- * _FIRST_.
+/**
+ * skb_unlink - remove a buffer from a list
+ * @skb: buffer to remove
+ *
+ * Place a packet after a given packet in a list. The list locks are taken
+ * and this function is atomic with respect to other list locked calls
+ *
+ * Works even without knowing the list it is sitting on, which can be
+ * handy at times. It also means that THE LIST MUST EXIST when you
+ * unlink. Thus a list must have its contents unlinked before it is
+ * destroyed.
*/
extern __inline__ void skb_unlink(struct sk_buff *skb)
@@ -491,6 +668,16 @@ extern __inline__ void skb_unlink(struct sk_buff *skb)
}
/* XXX: more streamlined implementation */
+
+/**
+ * __skb_dequeue_tail - remove from the tail of the queue
+ * @list: list to dequeue from
+ *
+ * Remove the tail of the list. This function does not take any locks
+ * so must be used with appropriate locks held only. The tail item is
+ * returned or NULL if the list is empty.
+ */
+
extern __inline__ struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
{
struct sk_buff *skb = skb_peek_tail(list);
@@ -499,6 +686,15 @@ extern __inline__ struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
return skb;
}
+/**
+ * skb_dequeue - remove from the head of the queue
+ * @list: list to dequeue from
+ *
+ * Remove the head of the list. The list lock is taken so the function
+ * may be used safely with other locking list functions. The tail item is
+ * returned or NULL if the list is empty.
+ */
+
extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
{
long flags;
@@ -522,6 +718,16 @@ extern __inline__ unsigned char *__skb_put(struct sk_buff *skb, unsigned int len
return tmp;
}
+/**
+ * skb_put - add data to a buffer
+ * @skb: buffer to use
+ * @len: amount of data to add
+ *
+ * This function extends the used data area of the buffer. If this would
+ * exceed the total buffer size the kernel will panic. A pointer to the
+ * first byte of the extra data is returned
+ */
+
extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp=skb->tail;
@@ -540,6 +746,16 @@ extern __inline__ unsigned char *__skb_push(struct sk_buff *skb, unsigned int le
return skb->data;
}
+/**
+ * skb_push - add data to the start of a buffer
+ * @skb: buffer to use
+ * @len: amount of data to add
+ *
+ * This function extends the used data area of the buffer at the buffer
+ * start. If this would exceed the total buffer headroom the kernel will
+ * panic. A pointer to the first byte of the extra data is returned
+ */
+
extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
{
skb->data-=len;
@@ -556,6 +772,17 @@ extern __inline__ char *__skb_pull(struct sk_buff *skb, unsigned int len)
return skb->data+=len;
}
+/**
+ * skb_pull - remove data from the start of a buffer
+ * @skb: buffer to use
+ * @len: amount of data to remove
+ *
+ * This function removes data from the start of a buffer, returning
+ * the memory to the headroom. A pointer to the next data in the buffer
+ * is returned. Once the data has been pulled future pushes will overwrite
+ * the old data
+ */
+
extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
{
if (len > skb->len)
@@ -563,28 +790,61 @@ extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, unsigned int len
return __skb_pull(skb,len);
}
+/**
+ * skb_headroom - bytes at buffer head
+ * @skb: buffer to check
+ *
+ * Return the number of bytes of free space at the head of an sk_buff
+ */
+
extern __inline__ int skb_headroom(const struct sk_buff *skb)
{
return skb->data-skb->head;
}
+/**
+ * skb_tailroom - bytes at buffer end
+ * @skb: buffer to check
+ *
+ * Return the number of bytes of free space at the tail of an sk_buff
+ */
+
extern __inline__ int skb_tailroom(const struct sk_buff *skb)
{
return skb->end-skb->tail;
}
+/**
+ * skb_reserve - adjust headroom
+ * @skb: buffer to alter
+ * @len: bytes to move
+ *
+ * Increase the headroom of an empty sk_buff by reducing the tail
+ * room. This is only allowed for an empty buffer.
+ */
+
extern __inline__ void skb_reserve(struct sk_buff *skb, unsigned int len)
{
skb->data+=len;
skb->tail+=len;
}
+
extern __inline__ void __skb_trim(struct sk_buff *skb, unsigned int len)
{
skb->len = len;
skb->tail = skb->data+len;
}
+/**
+ * skb_trim - remove end from a buffer
+ * @skb: buffer to alter
+ * @len: new length
+ *
+ * Cut the length of a buffer down by removing data from the tail. If
+ * the buffer is already under the length specified it is not modified.
+ */
+
extern __inline__ void skb_trim(struct sk_buff *skb, unsigned int len)
{
if (skb->len > len) {
@@ -592,6 +852,16 @@ extern __inline__ void skb_trim(struct sk_buff *skb, unsigned int len)
}
}
+/**
+ * skb_orphan - orphan a buffer
+ * @skb: buffer to orphan
+ *
+ * If a buffer currently has an owner then we call the owners
+ * destructor function and make the skb unowned. The buffer continues
+ * to exist but is no longer charged to its former owner.
+ */
+
+
extern __inline__ void skb_orphan(struct sk_buff *skb)
{
if (skb->destructor)
@@ -600,6 +870,16 @@ extern __inline__ void skb_orphan(struct sk_buff *skb)
skb->sk = NULL;
}
+/**
+ * skb_purge - empty a list
+ * @list: list to empty
+ *
+ * Delete all buffers on an sk_buff list. Each buffer is removed from
+ * the list and one reference dropped. This function takes the list
+ * lock and is atomic with respect to other list locking functions.
+ */
+
+
extern __inline__ void skb_queue_purge(struct sk_buff_head *list)
{
struct sk_buff *skb;
@@ -607,6 +887,16 @@ extern __inline__ void skb_queue_purge(struct sk_buff_head *list)
kfree_skb(skb);
}
+/**
+ * __skb_purge - empty a list
+ * @list: list to empty
+ *
+ * Delete all buffers on an sk_buff list. Each buffer is removed from
+ * the list and one reference dropped. This function does not take the
+ * list lock and the caller must hold the relevant locks to use it.
+ */
+
+
extern __inline__ void __skb_queue_purge(struct sk_buff_head *list)
{
struct sk_buff *skb;
@@ -614,6 +904,19 @@ extern __inline__ void __skb_queue_purge(struct sk_buff_head *list)
kfree_skb(skb);
}
+/**
+ * dev_alloc_skb - allocate an skbuff for sending
+ * @length: length to allocate
+ *
+ * Allocate a new sk_buff and assign it a usage count of one. The
+ * buffer has unspecified headroom built in. Users should allocate
+ * the headroom they think they need without accounting for the
+ * built in space. The built in space is used for optimisations.
+ *
+ * NULL is returned in there is no free memory. Although this function
+ * allocates memory it can be called from an interrupt.
+ */
+
extern __inline__ struct sk_buff *dev_alloc_skb(unsigned int length)
{
struct sk_buff *skb;
@@ -624,6 +927,22 @@ extern __inline__ struct sk_buff *dev_alloc_skb(unsigned int length)
return skb;
}
+/**
+ * skb_cow - copy a buffer if need be
+ * @skb: buffer to copy
+ * @headroom: needed headroom
+ *
+ * If the buffer passed lacks sufficient headroom or is a clone then
+ * it is copied and the additional headroom made available. If there
+ * is no free memory NULL is returned. The new buffer is returned if
+ * a copy was made (and the old one dropped a reference). The existing
+ * buffer is returned otherwise.
+ *
+ * This function primarily exists to avoid making two copies when making
+ * a writable copy of a buffer and then growing the headroom.
+ */
+
+
extern __inline__ struct sk_buff *
skb_cow(struct sk_buff *skb, unsigned int headroom)
{
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 279636434..a45f0ae2e 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -63,6 +63,7 @@ struct rpc_task {
void (*tk_callback)(struct rpc_task *);
void (*tk_action)(struct rpc_task *);
void (*tk_exit)(struct rpc_task *);
+ void (*tk_release)(struct rpc_task *);
void * tk_calldata;
/*
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 1e17e52bb..fb33c6b5f 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -10,6 +10,7 @@
#ifndef SUNRPC_SVC_H
#define SUNRPC_SVC_H
+#include <linux/in.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svcauth.h>
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 5a29918e6..98bf0ec20 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -59,6 +59,7 @@ void xdr_init(void);
/*
* Miscellaneous XDR helper functions
*/
+u32 * xdr_encode_array(u32 *p, const char *s, unsigned int len);
u32 * xdr_encode_string(u32 *p, const char *s);
u32 * xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen);
u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
@@ -93,6 +94,9 @@ xdr_adjust_iovec(struct iovec *iov, u32 *p)
return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
}
+void xdr_shift_iovec(struct iovec *, int, size_t);
+void xdr_zero_iovec(struct iovec *, int, size_t);
+
#endif /* __KERNEL__ */
#endif /* _SUNRPC_XDR_H_ */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d79fd68ef..d24ff0e0a 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -154,7 +154,7 @@ static inline int is_page_shared(struct page *page)
return 1;
count = page_count(page);
if (PageSwapCache(page))
- count += swap_count(page) - 2;
+ count += swap_count(page) - 2 - !!page->buffers;
return count > 1;
}
@@ -173,6 +173,8 @@ do { \
#define lru_cache_del(page) \
do { \
+ if (!PageLocked(page)) \
+ BUG(); \
spin_lock(&pagemap_lru_lock); \
list_del(&(page)->lru); \
nr_lru_pages--; \
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 48b7e0819..5d3d791d3 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -376,6 +376,9 @@ extern void start_tty(struct tty_struct * tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
extern int tty_register_driver(struct tty_driver *driver);
extern int tty_unregister_driver(struct tty_driver *driver);
+extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned minor);
+extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
extern void tty_write_message(struct tty_struct *tty, char *msg);
diff --git a/include/linux/udf_fs.h b/include/linux/udf_fs.h
index 47980eaaf..c1a255da9 100644
--- a/include/linux/udf_fs.h
+++ b/include/linux/udf_fs.h
@@ -56,12 +56,4 @@
#define udf_info(f, a...) \
printk (KERN_INFO "UDF-fs INFO " ## f, ## a);
-#ifdef __KERNEL__
-/*
- * Function prototypes (all other prototypes included in udfdecl.h)
- */
-extern int init_udf_fs(void);
-
-#endif /* __KERNEL__ */
-
#endif /* !defined(_LINUX_UDF_FS_H) */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index c011f8238..772264c52 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1,13 +1,6 @@
#ifndef __LINUX_USB_H
#define __LINUX_USB_H
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <linux/version.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h> /* for in_interrupt() */
-
/* USB constants */
/*
@@ -130,6 +123,12 @@
#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/config.h>
#include <linux/list.h>
@@ -364,10 +363,9 @@ struct usb_driver {
*/
typedef int (*usb_device_irq)(int, void *, int, void *);
-/* -------------------------------------------------------------------------------------*
- * New USB Structures *
- * -------------------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*
+ * New USB Structures *
+ *----------------------------------------------------------------------------*/
#define USB_DISABLE_SPD 0x0001
#define USB_ISO_ASAP 0x0002
@@ -499,7 +497,7 @@ struct irq_wrapper_data {
usb_device_irq handler;
};
-/* ------------------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
struct usb_operations {
int (*allocate)(struct usb_device *);
@@ -712,6 +710,7 @@ static inline unsigned int __default_pipe(struct usb_device *dev)
* Send and receive control messages..
*/
int usb_new_device(struct usb_device *dev);
+int usb_reset_device(struct usb_device *dev);
int usb_set_address(struct usb_device *dev);
int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
unsigned char descindex, void *buf, int size);
diff --git a/drivers/usb/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 95eaa937a..95eaa937a 100644
--- a/drivers/usb/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
diff --git a/include/net/sock.h b/include/net/sock.h
index 6782beca0..9b7720969 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -263,10 +263,11 @@ struct tcp_opt {
__u16 mss_cache; /* Cached effective mss, not including SACKS */
__u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
__u16 ext_header_len; /* Network protocol overhead (IP/IPv6 options) */
- __u8 dup_acks; /* Consequetive duplicate acks seen from other end */
+ __u8 dup_acks; /* Consecutive duplicate acks seen from other end */
__u8 retransmits;
- __u16 __empty1;
+ __u8 __empty1;
+ __u8 sorry;
__u8 defer_accept;
/* RTT measurement */
@@ -726,7 +727,7 @@ do { spin_lock_bh(&((__sk)->lock.slock)); \
if ((__sk)->backlog.tail != NULL) \
__release_sock(__sk); \
(__sk)->lock.users = 0; \
- wake_up(&((__sk)->lock.wq)); \
+ if (waitqueue_active(&((__sk)->lock.wq))) wake_up(&((__sk)->lock.wq)); \
spin_unlock_bh(&((__sk)->lock.slock)); \
} while(0)
@@ -837,11 +838,19 @@ extern void sklist_insert_socket(struct sock **list, struct sock *sk);
extern void sklist_destroy_socket(struct sock **list, struct sock *sk);
#ifdef CONFIG_FILTER
-/*
+
+/**
+ * sk_filter - run a packet through a socket filter
+ * @skb: buffer to filter
+ * @filter: filter to apply
+ *
* Run the filter code and then cut skb->data to correct size returned by
* sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
- * than pkt_len we keep whole skb->data.
+ * than pkt_len we keep whole skb->data. This is the socket level
+ * wrapper to sk_run_filter. It returns 0 if the packet should
+ * be accepted or 1 if the packet should be tossed.
*/
+
extern __inline__ int sk_filter(struct sk_buff *skb, struct sk_filter *filter)
{
int pkt_len;
@@ -855,6 +864,14 @@ extern __inline__ int sk_filter(struct sk_buff *skb, struct sk_filter *filter)
return 0;
}
+/**
+ * sk_filter_release: Release a socket filter
+ * @sk: socket
+ * @fp: filter to remove
+ *
+ * Remove a filter from a socket and release its resources.
+ */
+
extern __inline__ void sk_filter_release(struct sock *sk, struct sk_filter *fp)
{
unsigned int size = sk_filter_len(fp);
@@ -1135,6 +1152,12 @@ extern __inline__ unsigned long sock_wspace(struct sock *sk)
return amt;
}
+extern __inline__ void sk_wake_async(struct sock *sk, int how, int band)
+{
+ if (sk->socket && sk->socket->fasync_list)
+ sock_wake_async(sk->socket, how, band);
+}
+
#define SOCK_MIN_SNDBUF 2048
#define SOCK_MIN_RCVBUF 128
/* Must be less or equal SOCK_MIN_SNDBUF */
@@ -1169,6 +1192,14 @@ extern __inline__ int sock_rcvlowat(struct sock *sk, int waitall, int len)
return waitall ? len : min(sk->rcvlowat, len);
}
+/* Alas, with timeout socket operations are not restartable.
+ * Compare this to poll().
+ */
+extern __inline__ int sock_intr_errno(long timeo)
+{
+ return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR;
+}
+
/*
* Enable debug/info messages
*/
diff --git a/include/net/tcp.h b/include/net/tcp.h
index dacdfa2a7..02b320842 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -669,8 +669,6 @@ extern void tcp_v4_send_check(struct sock *sk,
struct tcphdr *th, int len,
struct sk_buff *skb);
-extern void tcp_v4_send_reset(struct sk_buff *skb);
-
extern int tcp_v4_conn_request(struct sock *sk,
struct sk_buff *skb);
@@ -908,6 +906,13 @@ struct tcp_skb_cb {
#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))
+/*
+ * Compute minimal free write space needed to queue new packets.
+ */
+#define tcp_min_write_space(__sk) \
+ (atomic_read(&(__sk)->wmem_alloc) / 2)
+
+
/* This determines how many packets are "in the network" to the best
* of our knowledge. In many cases it is conservative, but where
* detailed information is available from the receiver (via SACK
@@ -1342,6 +1347,15 @@ extern __inline__ void tcp_init_buffer_space(struct sock *sk)
if (sk->rcvbuf < 3*rcvbuf)
sk->rcvbuf = min (3*rcvbuf, sysctl_rmem_max);
+
+ /* Reserve slack space to reduce jitter of advertised window. */
+ if (tp->window_clamp >= tcp_full_space(sk)) {
+ int nwin = tcp_full_space(sk) - tp->mss_clamp;
+
+ if (nwin >= MAX_TCP_WINDOW && nwin >= 2*tp->advmss)
+ tp->window_clamp = nwin;
+ }
+
if (sk->sndbuf < 3*sndbuf)
sk->sndbuf = min (3*sndbuf, sysctl_wmem_max);
}
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 20b7d158e..283e81695 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -11,9 +11,13 @@ Original driver (sg.h):
Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2000 Douglas Gilbert
- Version: 3.1.12 (20000222)
+ Version: 3.1.13 (20000323)
This version is for 2.3/2.4 series kernels.
+ Changes since 3.1.12 (20000222)
+ - make sg_header interface use SCSI_DATA_UNKNOWN
+ - add SG_DXFER_UNKNOWN define to sg interface
+ - stop allocating data buffers to non data transfer commands
Changes since 3.1.10 (20000123)
- make device allocation dynamic (get rid of SG_EXTRA_DEVS)
- move to sg0,sg1,sg2 rather than sga,sgb,sgc
@@ -147,6 +151,7 @@ typedef struct sg_io_hdr
additional property than during indirect
IO the user buffer is copied into the
kernel buffers before the transfer */
+#define SG_DXFER_UNKNOWN -5 /* Unknown data direction */
/* following flag values can be "or"-ed together */
#define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */
diff --git a/init/main.c b/init/main.c
index 01834b424..c1e2ba8b9 100644
--- a/init/main.c
+++ b/init/main.c
@@ -519,19 +519,17 @@ asmlinkage void __init start_kernel(void)
kmem_cache_init();
sti();
calibrate_delay();
-#if 0000
#ifdef CONFIG_BLK_DEV_INITRD
- // FIXME, use the bootmem.h interface.
- if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
+ if (initrd_start && !initrd_below_start_ok &&
+ initrd_start < min_low_pfn << PAGE_SHIFT) {
printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
- "disabling it.\n",initrd_start,memory_start);
+ "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
initrd_start = 0;
}
#endif
#ifdef CONFIG_BINFMT_IRIX
init_inventory();
#endif
-#endif /* 0000 */
mem_init();
kmem_cache_sizes_init();
#ifdef CONFIG_PROC_FS
@@ -584,14 +582,6 @@ static int do_linuxrc(void * shell)
return execve(shell, argv, envp_init);
}
-static int __init no_initrd(char *s)
-{
- mount_initrd = 0;
- return 1;
-}
-
-__setup("noinitrd", no_initrd);
-
#endif
struct task_struct *child_reaper = &init_task;
diff --git a/ipc/shm.c b/ipc/shm.c
index 232feedad..b60a3d9b2 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -18,8 +18,9 @@
* 1) It only can handle one directory.
* 2) Because the directory is represented by the SYSV shm array it
* can only be mounted one time.
- * 3) Read and write are not implemented (should they?)
- * 4) No special nodes are supported
+ * 3) Private writeable mappings are not supported
+ * 4) Read and write are not implemented (should they?)
+ * 5) No special nodes are supported
*
* There are the following mount options:
* - nr_blocks (^= shmall) is the number of blocks of size PAGE_SIZE
@@ -67,6 +68,13 @@ static int shm_readdir (struct file *, void *, filldir_t);
#define SHM_FMT ".IPC_%08x"
#define SHM_FMT_LEN 13
+/* shm_mode upper byte flags */
+/* SHM_DEST and SHM_LOCKED are used in ipcs(8) */
+#define PRV_DEST 0010000 /* segment will be destroyed on last detach */
+#define PRV_LOCKED 0020000 /* segment will not be swapped */
+#define SHM_UNLK 0040000 /* filename is unlinked */
+#define SHM_SYSV 0100000 /* It is a SYSV shm segment */
+
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
@@ -82,7 +90,6 @@ struct shmid_kernel /* private to the kernel */
time_t ctime;
pid_t cpid;
pid_t lpid;
- int unlinked;
int nlen;
char nm[0];
} shmem;
@@ -100,7 +107,7 @@ struct shmid_kernel /* private to the kernel */
#define shm_lprid permap.shmem.lpid
#define shm_namelen permap.shmem.nlen
#define shm_name permap.shmem.nm
-#define shm_unlinked permap.shmem.unlinked
+#define shm_flags shm_perm.mode
#define zsem permap.zero.sema
#define zero_list permap.zero.list
@@ -111,13 +118,11 @@ static struct ipc_ids shm_ids;
#define shm_lockall() ipc_lockall(&shm_ids)
#define shm_unlockall() ipc_unlockall(&shm_ids)
#define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id))
-#define shm_checkid(s, id) \
- ipc_checkid(&shm_ids,&s->shm_perm,id)
#define shm_buildid(id, seq) \
ipc_buildid(&shm_ids, id, seq)
static int newseg (key_t key, const char *name, int namelen, int shmflg, size_t size);
-static void killseg_core(struct shmid_kernel *shp, int doacc);
+static void seg_free(struct shmid_kernel *shp, int doacc);
static void shm_open (struct vm_area_struct *shmd);
static void shm_close (struct vm_area_struct *shmd);
static int shm_remove_name(int id);
@@ -316,6 +321,15 @@ static int shm_remount_fs (struct super_block *sb, int *flags, char *data)
return 0;
}
+static inline int shm_checkid(struct shmid_kernel *s, int id)
+{
+ if (!(s->shm_flags & SHM_SYSV))
+ return -EINVAL;
+ if (ipc_checkid(&shm_ids,&s->shm_perm,id))
+ return -EIDRM;
+ return 0;
+}
+
static inline struct shmid_kernel *shm_rmid(int id)
{
return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
@@ -348,7 +362,7 @@ static void shm_put_super(struct super_block *sb)
printk(KERN_DEBUG "shm_nattch = %ld\n", shp->shm_nattch);
shp = shm_rmid(i);
shm_unlock(i);
- killseg_core(shp, 1);
+ seg_free(shp, 1);
}
dput (sb->s_root);
up(&shm_ids.sem);
@@ -383,7 +397,7 @@ static void shm_read_inode(struct inode * inode)
if (id < SEQ_MULTIPLIER) {
if (!(shp = shm_lock (id)))
return;
- inode->i_mode = shp->shm_perm.mode | S_IFREG;
+ inode->i_mode = (shp->shm_flags & S_IALLUGO) | S_IFREG;
inode->i_uid = shp->shm_perm.uid;
inode->i_gid = shp->shm_perm.gid;
inode->i_size = shp->shm_segsz;
@@ -455,7 +469,7 @@ static int shm_readdir (struct file *filp, void *dirent, filldir_t filldir)
continue;
if (!(shp = shm_get (nr-2)))
continue;
- if (shp->shm_unlinked)
+ if (shp->shm_flags & SHM_UNLK)
continue;
if (filldir(dirent, shp->shm_name, shp->shm_namelen, nr, nr) < 0 )
break;;
@@ -484,7 +498,7 @@ static struct dentry *shm_lookup (struct inode *dir, struct dentry *dent)
continue;
if (!(shp = shm_lock(i)))
continue;
- if (!(shp->shm_unlinked) &&
+ if (!(shp->shm_flags & SHM_UNLK) &&
dent->d_name.len == shp->shm_namelen &&
strncmp(dent->d_name.name, shp->shm_name, shp->shm_namelen) == 0)
goto found;
@@ -522,8 +536,7 @@ static int shm_unlink (struct inode *dir, struct dentry *dent)
down (&shm_ids.sem);
if (!(shp = shm_lock (inode->i_ino)))
BUG();
- shp->shm_unlinked = 1;
- shp->shm_perm.mode |= SHM_DEST;
+ shp->shm_flags |= SHM_UNLK | PRV_DEST;
shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
shm_unlock (inode->i_ino);
up (&shm_ids.sem);
@@ -542,7 +555,7 @@ static int shm_unlink (struct inode *dir, struct dentry *dent)
#define SHM_ENTRY(shp, index) (shp)->shm_dir[(index)/PTRS_PER_PTE][(index)%PTRS_PER_PTE]
-static pte_t **shm_alloc(unsigned long pages)
+static pte_t **shm_alloc(unsigned long pages, int doacc)
{
unsigned short dir = pages / PTRS_PER_PTE;
unsigned short last = pages % PTRS_PER_PTE;
@@ -572,6 +585,12 @@ static pte_t **shm_alloc(unsigned long pages)
for (pte = *ptr; pte < *ptr + last; pte++)
pte_clear (pte);
}
+ if (doacc) {
+ shm_lockall();
+ shm_tot += pages;
+ used_segs++;
+ shm_unlockall();
+ }
return ret;
free:
@@ -584,13 +603,28 @@ nomem:
return ERR_PTR(-ENOMEM);
}
-static void shm_free(pte_t** dir, unsigned long pages)
+static void shm_free(pte_t** dir, unsigned long pages, int doacc)
{
+ int i, rss, swp;
pte_t **ptr = dir+pages/PTRS_PER_PTE;
if (!dir)
return;
+ for (i = 0, rss = 0, swp = 0; i < pages ; i++) {
+ pte_t pte;
+ pte = dir[i/PTRS_PER_PTE][i%PTRS_PER_PTE];
+ if (pte_none(pte))
+ continue;
+ if (pte_present(pte)) {
+ __free_page (pte_page(pte));
+ rss++;
+ } else {
+ swap_free(pte_to_swp_entry(pte));
+ swp++;
+ }
+ }
+
/* first the last page */
if (pages%PTRS_PER_PTE)
kfree (*ptr);
@@ -601,6 +635,15 @@ static void shm_free(pte_t** dir, unsigned long pages)
/* Now the indirect block */
kfree (dir);
+
+ if (doacc) {
+ shm_lockall();
+ shm_rss -= rss;
+ shm_swp -= swp;
+ shm_tot -= pages;
+ used_segs--;
+ shm_unlockall();
+ }
}
static int shm_setattr (struct dentry *dentry, struct iattr *attr)
@@ -611,7 +654,8 @@ static int shm_setattr (struct dentry *dentry, struct iattr *attr)
unsigned long new_pages, old_pages;
pte_t **new_dir, **old_dir;
- if ((error = inode_change_ok(inode, attr)))
+ error = inode_change_ok(inode, attr);
+ if (error)
return error;
if (!(attr->ia_valid & ATTR_SIZE))
goto set_attr;
@@ -620,15 +664,19 @@ static int shm_setattr (struct dentry *dentry, struct iattr *attr)
/* We set old_pages and old_dir for easier cleanup */
old_pages = new_pages = (attr->ia_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- if (shm_tot + new_pages >= shm_ctlall)
- return -ENOSPC;
- if (IS_ERR(old_dir = new_dir = shm_alloc(new_pages)))
+ old_dir = new_dir = shm_alloc(new_pages, 1);
+ if (IS_ERR(new_dir))
return PTR_ERR(new_dir);
if (!(shp = shm_lock(inode->i_ino)))
BUG();
+ error = -ENOSPC;
+ if (shm_tot - shp->shm_npages >= shm_ctlall)
+ goto out;
+ error = 0;
if (shp->shm_segsz == attr->ia_size)
goto out;
+ /* Now we set them to the real values */
old_dir = shp->shm_dir;
old_pages = shp->shm_npages;
if (old_dir){
@@ -650,16 +698,13 @@ static int shm_setattr (struct dentry *dentry, struct iattr *attr)
shp->shm_segsz = attr->ia_size;
out:
shm_unlock(inode->i_ino);
- shm_lockall();
- shm_tot += new_pages - old_pages;
- shm_unlockall();
- shm_free (old_dir, old_pages);
+ shm_free (old_dir, old_pages, 1);
set_attr:
inode_setattr(inode, attr);
- return 0;
+ return error;
}
-static inline struct shmid_kernel *newseg_alloc(int numpages, size_t namelen)
+static struct shmid_kernel *seg_alloc(int numpages, size_t namelen)
{
struct shmid_kernel *shp;
pte_t **dir;
@@ -668,7 +713,7 @@ static inline struct shmid_kernel *newseg_alloc(int numpages, size_t namelen)
if (!shp)
return ERR_PTR(-ENOMEM);
- dir = shm_alloc (numpages);
+ dir = shm_alloc (numpages, namelen);
if (IS_ERR(dir)) {
kfree(shp);
return ERR_PTR(PTR_ERR(dir));
@@ -680,6 +725,12 @@ static inline struct shmid_kernel *newseg_alloc(int numpages, size_t namelen)
return(shp);
}
+static void seg_free(struct shmid_kernel *shp, int doacc)
+{
+ shm_free (shp->shm_dir, shp->shm_npages, doacc);
+ kfree(shp);
+}
+
static int newseg (key_t key, const char *name, int namelen,
int shmflg, size_t size)
{
@@ -696,32 +747,28 @@ static int newseg (key_t key, const char *name, int namelen,
if (shm_tot + numpages >= shm_ctlall)
return -ENOSPC;
- if (!(shp = newseg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1)))
+ if (!(shp = seg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1)))
return -ENOMEM;
id = shm_addid(shp);
if(id == -1) {
- shm_free(shp->shm_dir,numpages);
- kfree(shp);
+ seg_free(shp, 1);
return -ENOSPC;
}
shp->shm_perm.key = key;
- shp->shm_perm.mode = (shmflg & S_IRWXUGO);
+ shp->shm_flags = (shmflg & S_IRWXUGO);
shp->shm_segsz = size;
shp->shm_cprid = current->pid;
shp->shm_lprid = 0;
shp->shm_atim = shp->shm_dtim = 0;
shp->shm_ctim = CURRENT_TIME;
shp->id = shm_buildid(id,shp->shm_perm.seq);
- shp->shm_unlinked = 0;
if (namelen != 0) {
shp->shm_namelen = namelen;
memcpy (shp->shm_name, name, namelen);
} else {
+ shp->shm_flags |= SHM_SYSV;
shp->shm_namelen = sprintf (shp->shm_name, SHM_FMT, shp->id);
}
-
- shm_tot += numpages;
- used_segs++;
shm_unlock(id);
return shp->id;
@@ -768,36 +815,6 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
return err;
}
-static void killseg_core(struct shmid_kernel *shp, int doacc)
-{
- int i, numpages, rss, swp;
-
- numpages = shp->shm_npages;
- for (i = 0, rss = 0, swp = 0; i < numpages ; i++) {
- pte_t pte;
- pte = SHM_ENTRY (shp,i);
- if (pte_none(pte))
- continue;
- if (pte_present(pte)) {
- __free_page (pte_page(pte));
- rss++;
- } else {
- swap_free(pte_to_swp_entry(pte));
- swp++;
- }
- }
- shm_free (shp->shm_dir, numpages);
- kfree(shp);
- if (doacc) {
- shm_lockall();
- shm_rss -= rss;
- shm_swp -= swp;
- shm_tot -= numpages;
- used_segs--;
- shm_unlockall();
- }
-}
-
static void shm_delete (struct inode *ino)
{
int shmid = ino->i_ino;
@@ -811,7 +828,7 @@ static void shm_delete (struct inode *ino)
shp = shm_rmid(shmid);
shm_unlock(shmid);
up(&shm_ids.sem);
- killseg_core(shp, 1);
+ seg_free(shp, 1);
clear_inode(ino);
}
@@ -858,7 +875,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void *b
out->uid = tbuf.shm_perm.uid;
out->gid = tbuf.shm_perm.gid;
- out->mode = tbuf.shm_perm.mode;
+ out->mode = tbuf.shm_flags;
return 0;
}
@@ -871,7 +888,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void *b
out->uid = tbuf_old.shm_perm.uid;
out->gid = tbuf_old.shm_perm.gid;
- out->mode = tbuf_old.shm_perm.mode;
+ out->mode = tbuf_old.shm_flags;
return 0;
}
@@ -975,12 +992,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
return -EINVAL;
if(cmd==SHM_STAT) {
err = -EINVAL;
- if (shmid > shm_ids.max_id)
+ if (!(shp->shm_flags & SHM_SYSV) ||
+ shmid > shm_ids.max_id)
goto out_unlock;
result = shm_buildid(shmid, shp->shm_perm.seq);
} else {
- err = -EIDRM;
- if(shm_checkid(shp,shmid))
+ err = shm_checkid(shp,shmid);
+ if(err)
goto out_unlock;
result = 0;
}
@@ -988,6 +1006,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
if (ipcperms (&shp->shm_perm, S_IRUGO))
goto out_unlock;
kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
+ /* ugly hack to keep binary compatibility for ipcs */
+ tbuf.shm_flags &= PRV_DEST | PRV_LOCKED | S_IRWXUGO;
+ if (tbuf.shm_flags & PRV_DEST)
+ tbuf.shm_flags |= SHM_DEST;
+ if (tbuf.shm_flags & PRV_LOCKED)
+ tbuf.shm_flags |= SHM_LOCKED;
+ tbuf.shm_flags &= SHM_DEST | SHM_LOCKED | S_IRWXUGO;
tbuf.shm_segsz = shp->shm_segsz;
tbuf.shm_atime = shp->shm_atim;
tbuf.shm_dtime = shp->shm_dtim;
@@ -1006,7 +1031,6 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
/* Allow superuser to lock segment in memory */
/* Should the pages be faulted in here or leave it to user? */
/* need to determine interaction with current->swappable */
- struct kern_ipc_perm *ipcp;
if ((shmid % SEQ_MULTIPLIER)== zero_id)
return -EINVAL;
if (!capable(CAP_IPC_LOCK))
@@ -1015,21 +1039,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shp = shm_lock(shmid);
if(shp==NULL)
return -EINVAL;
- err=-EIDRM;
- if(shm_checkid(shp,shmid))
+ err = shm_checkid(shp,shmid);
+ if(err)
goto out_unlock;
- ipcp = &shp->shm_perm;
- if(cmd==SHM_LOCK) {
- if (!(ipcp->mode & SHM_LOCKED)) {
- ipcp->mode |= SHM_LOCKED;
- err = 0;
- }
- } else {
- if (ipcp->mode & SHM_LOCKED) {
- ipcp->mode &= ~SHM_LOCKED;
- err = 0;
- }
- }
+ if(cmd==SHM_LOCK)
+ shp->shm_flags |= PRV_LOCKED;
+ else
+ shp->shm_flags &= ~PRV_LOCKED;
shm_unlock(shmid);
return err;
}
@@ -1053,9 +1069,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
up(&shm_ids.sem);
return -EINVAL;
}
- err = -EIDRM;
- if (shm_checkid(shp, shmid) == 0) {
- if (shp->shm_nattch == 0) {
+ err = shm_checkid(shp, shmid);
+ if (err == 0) {
+ if (shp->shm_nattch == 0 &&
+ !(shp->shm_flags & SHM_UNLK)) {
int id=shp->id;
shm_unlock(shmid);
up(&shm_ids.sem);
@@ -1066,10 +1083,9 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
*/
return shm_remove_name(id);
}
- /* Do not find me any more */
- shp->shm_perm.mode |= SHM_DEST;
- shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
- err = 0;
+ shp->shm_flags |= PRV_DEST;
+ /* Do not find it any more */
+ shp->shm_perm.key = IPC_PRIVATE;
}
/* Unlock */
shm_unlock(shmid);
@@ -1089,8 +1105,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
err=-EINVAL;
if(shp==NULL)
goto out_up;
- err=-EIDRM;
- if(shm_checkid(shp,shmid))
+ err = shm_checkid(shp,shmid);
+ if(err)
goto out_unlock_up;
err=-EPERM;
if (current->euid != shp->shm_perm.uid &&
@@ -1101,7 +1117,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shp->shm_perm.uid = setbuf.uid;
shp->shm_perm.gid = setbuf.gid;
- shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
+ shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO)
| (setbuf.mode & S_IRWXUGO);
shp->shm_ctim = CURRENT_TIME;
break;
@@ -1146,6 +1162,7 @@ static int shm_mmap(struct file * file, struct vm_area_struct * vma)
/*
* Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
*/
+/* MOUNT_REWRITE: kernel vfsmnt of shmfs should be passed to __filp_open() */
asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
{
unsigned long addr;
@@ -1154,6 +1171,8 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
unsigned long flags;
unsigned long prot;
unsigned long o_flags;
+ int acc_mode;
+ struct dentry *dentry;
char name[SHM_FMT_LEN+1];
if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
@@ -1173,19 +1192,35 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
if (shmflg & SHM_RDONLY) {
prot = PROT_READ;
o_flags = O_RDONLY;
+ acc_mode = MAY_READ;
} else {
prot = PROT_READ | PROT_WRITE;
o_flags = O_RDWR;
+ acc_mode = MAY_READ | MAY_WRITE;
}
sprintf (name, SHM_FMT, shmid);
lock_kernel();
- file = filp_open(name, o_flags, 0, dget(shm_sb->s_root));
+ dentry = lookup_one(name, dget(lock_parent(shm_sb->s_root)));
+ unlock_dir(shm_sb->s_root);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto bad_file;
+ err = -ENOENT;
+ if (!dentry->d_inode)
+ goto bad_file;
+ err = permission(dentry->d_inode, acc_mode);
+ if (err)
+ goto bad_file;
+ file = dentry_open(dentry, NULL, o_flags);
+ err = PTR_ERR(file);
if (IS_ERR (file))
goto bad_file;
+ down(&current->mm->mmap_sem);
*raddr = do_mmap (file, addr, file->f_dentry->d_inode->i_size,
prot, flags, 0);
+ up(&current->mm->mmap_sem);
unlock_kernel();
if (IS_ERR(*raddr))
err = PTR_ERR(*raddr);
@@ -1196,7 +1231,7 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
bad_file:
unlock_kernel();
- if ((err = PTR_ERR(file)) == -ENOENT)
+ if (err == -ENOENT)
return -EINVAL;
return err;
}
@@ -1213,13 +1248,32 @@ static void shm_open (struct vm_area_struct *shmd)
static int shm_remove_name(int id)
{
- int err;
+ struct dentry *dir;
+ struct dentry *dentry;
+ int error;
char name[SHM_FMT_LEN+1];
+
sprintf (name, SHM_FMT, id);
lock_kernel();
- err = do_unlink (name, dget(shm_sb->s_root));
+ dir = lock_parent(shm_sb->s_root);
+ dentry = lookup_one(name, dget(dir));
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ /*
+ * We have to do our own unlink to prevent the vfs
+ * permission check. The SYSV IPC layer has already
+ * checked the permissions which do not comply to the
+ * vfs rules.
+ */
+ struct inode *inode = dir->d_inode;
+ down(&inode->i_zombie);
+ error = shm_unlink(inode, dentry);
+ up(&inode->i_zombie);
+ dput(dentry);
+ }
+ unlock_dir(dir);
unlock_kernel();
- return err;
+ return error;
}
/*
@@ -1239,7 +1293,9 @@ static void shm_close (struct vm_area_struct *shmd)
shp->shm_lprid = current->pid;
shp->shm_dtim = CURRENT_TIME;
shp->shm_nattch--;
- if(shp->shm_nattch == 0 && shp->shm_perm.mode & SHM_DEST) {
+ if(shp->shm_nattch == 0 &&
+ shp->shm_flags & PRV_DEST &&
+ !(shp->shm_flags & SHM_UNLK)) {
int pid=shp->id;
int err;
shm_unlock(id);
@@ -1453,7 +1509,7 @@ int shm_swap (int prio, int gfp_mask, zone_t *zone)
shm_lockall();
check_id:
shp = shm_get(swap_id);
- if(shp==NULL || shp->shm_perm.mode & SHM_LOCKED) {
+ if(shp==NULL || shp->shm_flags & SHM_LOCKED) {
next_id:
swap_idx = 0;
if (++swap_id > shm_ids.max_id) {
@@ -1571,7 +1627,7 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l
len += sprintf(buffer + len, format,
shp->shm_perm.key,
shm_buildid(i, shp->shm_perm.seq),
- shp->shm_perm.mode,
+ shp->shm_flags,
shp->shm_segsz,
shp->shm_cprid,
shp->shm_lprid,
@@ -1585,7 +1641,7 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l
shp->shm_ctim,
shp->shm_namelen,
shp->shm_name,
- shp->shm_unlinked ? " (deleted)" : "");
+ shp->shm_flags & SHM_UNLK ? " (deleted)" : "");
shm_unlock(i);
pos += len;
@@ -1637,6 +1693,7 @@ static struct vm_operations_struct shmzero_vm_ops = {
* on the pseudo-file. This is possible because the open/close calls
* are bracketed by the file count update calls.
*/
+/* MOUNT_REWRITE: set ->f_vfsmnt to shmfs one */
static struct file *file_setup(struct file *fzero, struct shmid_kernel *shp)
{
struct file *filp;
@@ -1654,6 +1711,7 @@ static struct file *file_setup(struct file *fzero, struct shmid_kernel *shp)
put_filp(filp);
return(0);
}
+ filp->f_vfsmnt = NULL;
d_instantiate(filp->f_dentry, inp);
/*
@@ -1674,10 +1732,10 @@ int map_zero_setup(struct vm_area_struct *vma)
if (!vm_enough_memory((vma->vm_end - vma->vm_start) >> PAGE_SHIFT))
return -ENOMEM;
- if (IS_ERR(shp = newseg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, 0)))
+ if (IS_ERR(shp = seg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, 0)))
return PTR_ERR(shp);
if ((filp = file_setup(vma->vm_file, shp)) == 0) {
- killseg_core(shp, 0);
+ seg_free(shp, 0);
return -ENOMEM;
}
vma->vm_file = filp;
@@ -1719,7 +1777,7 @@ static void shmzero_close(struct vm_area_struct *shmd)
struct shmid_kernel, zero_list);
list_del(&shp->zero_list);
spin_unlock(&zmap_list_lock);
- killseg_core(shp, 0);
+ seg_free(shp, 0);
}
}
diff --git a/kernel/acct.c b/kernel/acct.c
index f15b6971f..2bd7d121d 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -36,8 +36,7 @@
* but this one obviously doesn't introduce deadlocks. Later. BTW, found
* one race (and leak) in BSD implementation.
* OK, that's better. ANOTHER race and leak in BSD variant. There always
- * is one more bug... TODO: move filp_open into open.c and make
- * parameters sysctl-controllable. 10/11/98, AV.
+ * is one more bug... 10/11/98, AV.
*/
#include <linux/config.h>
@@ -154,7 +153,7 @@ asmlinkage long sys_acct(const char *name)
if (IS_ERR(tmp))
goto out;
/* Difference from BSD - they don't do O_APPEND */
- file = filp_open(tmp, O_WRONLY|O_APPEND, 0, NULL);
+ file = filp_open(tmp, O_WRONLY|O_APPEND, 0);
putname(tmp);
if (IS_ERR(file)) {
error = PTR_ERR(file);
diff --git a/kernel/exit.c b/kernel/exit.c
index 4684b8c37..45f85aec3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -216,7 +216,9 @@ static inline void __exit_fs(struct task_struct *tsk)
tsk->fs = NULL;
if (atomic_dec_and_test(&fs->count)) {
dput(fs->root);
+ mntput(fs->rootmnt);
dput(fs->pwd);
+ mntput(fs->pwdmnt);
kfree(fs);
}
}
@@ -414,12 +416,12 @@ fake_volatile:
#ifdef CONFIG_BSD_PROCESS_ACCT
acct_process(code);
#endif
- task_lock(tsk);
sem_exit();
__exit_mm(tsk);
__exit_files(tsk);
__exit_fs(tsk);
__exit_sighand(tsk);
+ task_lock(tsk);
exit_thread();
tsk->state = TASK_ZOMBIE;
tsk->exit_code = code;
diff --git a/kernel/fork.c b/kernel/fork.c
index 2fbb08e32..6eca792d9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -432,6 +432,8 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
tsk->fs->umask = current->fs->umask;
tsk->fs->root = dget(current->fs->root);
tsk->fs->pwd = dget(current->fs->pwd);
+ tsk->fs->rootmnt = mntget(current->fs->rootmnt);
+ tsk->fs->pwdmnt = mntget(current->fs->pwdmnt);
return 0;
}
diff --git a/kernel/kmod.c b/kernel/kmod.c
index dca806e94..75d31eadf 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -54,11 +54,15 @@ use_init_fs_context(void)
our_fs = current->fs;
dput(our_fs->root);
dput(our_fs->pwd);
+ mntput(our_fs->rootmnt);
+ mntput(our_fs->pwdmnt);
init_fs = init_task.fs;
our_fs->umask = init_fs->umask;
our_fs->root = dget(init_fs->root);
our_fs->pwd = dget(init_fs->pwd);
+ our_fs->rootmnt = mntget(init_fs->rootmnt);
+ our_fs->pwdmnt = mntget(init_fs->pwdmnt);
unlock_kernel();
}
@@ -119,10 +123,20 @@ static int exec_modprobe(void * module_name)
return ret;
}
-/*
- request_module: the function that everyone calls when they need
- a module.
-*/
+/**
+ * request_module - try to load a kernel module
+ * @module_name: Name of module
+ *
+ * Load a module using the user mode module loader. The function returns
+ * zero on success or a negative errno code on failure. Note that a
+ * successful module load does not mean the module did not then unload
+ * and exit on an error of its own. Callers must check that the service
+ * they requested is now available not blindly invoke it.
+ *
+ * If module auto-loading support is disabled then this function
+ * becomes a no-operation.
+ */
+
int request_module(const char * module_name)
{
int pid;
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index ad11eafea..89136a218 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -141,8 +141,9 @@ EXPORT_SYMBOL(iget4);
EXPORT_SYMBOL(iput);
EXPORT_SYMBOL(__namei);
EXPORT_SYMBOL(lookup_dentry);
+EXPORT_SYMBOL(walk_init);
+EXPORT_SYMBOL(walk_name);
EXPORT_SYMBOL(lookup_one);
-EXPORT_SYMBOL(__open_namei);
EXPORT_SYMBOL(sys_close);
EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete);
@@ -153,7 +154,7 @@ EXPORT_SYMBOL(d_move);
EXPORT_SYMBOL(d_instantiate);
EXPORT_SYMBOL(d_alloc);
EXPORT_SYMBOL(d_lookup);
-EXPORT_SYMBOL(d_path);
+EXPORT_SYMBOL(__d_path);
EXPORT_SYMBOL(mark_buffer_dirty);
EXPORT_SYMBOL(__mark_buffer_dirty);
EXPORT_SYMBOL(__mark_inode_dirty);
diff --git a/kernel/panic.c b/kernel/panic.c
index e040ee454..920e4a1a7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -8,6 +8,7 @@
* This function is used through-out the kernel (including mm and fs)
* to indicate a major problem.
*/
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/reboot.h>
@@ -32,10 +33,24 @@ static int __init panic_setup(char *str)
__setup("panic=", panic_setup);
+/**
+ * panic - halt the system
+ * @fmt: The text string to print
+ *
+ * Display a message, then unblank the console and perform
+ * cleanups. Functions in the panic notifier list are called
+ * after the filesystem cache is flushed (when possible).
+ *
+ * This function never returns.
+ */
+
NORET_TYPE void panic(const char * fmt, ...)
{
static char buf[1024];
va_list args;
+#if defined(CONFIG_ARCH_S390)
+ unsigned long caller = (unsigned long) __builtin_return_address(0);
+#endif
va_start(args, fmt);
vsprintf(buf, fmt, args);
@@ -79,6 +94,9 @@ NORET_TYPE void panic(const char * fmt, ...)
printk("Press L1-A to return to the boot prom\n");
}
#endif
+#if defined(CONFIG_ARCH_S390)
+ disabled_wait(caller);
+#endif
sti();
for(;;) {
CHECK_EMERGENCY_SYNC
diff --git a/kernel/sched.c b/kernel/sched.c
index c0ac80395..d1d49df5c 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -405,6 +405,7 @@ signed long schedule_timeout(signed long timeout)
*/
static inline void __schedule_tail(struct task_struct *prev)
{
+ current->need_resched |= prev->need_resched;
#ifdef __SMP__
if ((prev->state == TASK_RUNNING) &&
(prev != idle_task(smp_processor_id()))) {
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 7a6d9db09..0e11fe9ed 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -24,6 +24,7 @@
* true for the boot process anyway)
*/
unsigned long max_low_pfn;
+unsigned long min_low_pfn;
/* return the number of _pages_ that will be allocated for the boot bitmap */
unsigned long __init bootmem_bootmap_pages (unsigned long pages)
@@ -282,6 +283,7 @@ unsigned long __init free_all_bootmem_node (int nid)
unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
{
max_low_pfn = pages;
+ min_low_pfn = start;
return(init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages));
}
diff --git a/mm/filemap.c b/mm/filemap.c
index bccdc9bd2..533747f96 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -250,6 +250,11 @@ int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
count--;
dispose = &young;
+
+ /* avoid unscalable SMP locking */
+ if (!page->buffers && page_count(page) > 1)
+ goto dispose_continue;
+
if (TryLockPage(page))
goto dispose_continue;
@@ -260,22 +265,11 @@ int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
page locked down ;). */
spin_unlock(&pagemap_lru_lock);
- /* avoid unscalable SMP locking */
- if (!page->buffers && page_count(page) > 1)
- goto unlock_noput_continue;
-
- /* Take the pagecache_lock spinlock held to avoid
- other tasks to notice the page while we are looking at its
- page count. If it's a pagecache-page we'll free it
- in one atomic transaction after checking its page count. */
- spin_lock(&pagecache_lock);
-
/* avoid freeing the page while it's locked */
get_page(page);
/* Is it a buffer page? */
if (page->buffers) {
- spin_unlock(&pagecache_lock);
if (!try_to_free_buffers(page))
goto unlock_continue;
/* page was locked, inode can't go away under us */
@@ -283,9 +277,14 @@ int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
atomic_dec(&buffermem_pages);
goto made_buffer_progress;
}
- spin_lock(&pagecache_lock);
}
+ /* Take the pagecache_lock spinlock held to avoid
+ other tasks to notice the page while we are looking at its
+ page count. If it's a pagecache-page we'll free it
+ in one atomic transaction after checking its page count. */
+ spin_lock(&pagecache_lock);
+
/*
* We can't free pages unless there's just one user
* (count == 2 because we added one ourselves above).
@@ -294,12 +293,6 @@ int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
goto cache_unlock_continue;
/*
- * We did the page aging part.
- */
- if (nr_lru_pages < freepages.min * priority)
- goto cache_unlock_continue;
-
- /*
* Is it a page swap page? If so, we want to
* drop it if it is no longer used, even if it
* were to be marked referenced..
@@ -312,8 +305,7 @@ int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
/* is it a page-cache page? */
if (page->mapping) {
- if (!pgcache_under_min())
- {
+ if (!PageDirty(page) && !pgcache_under_min()) {
remove_page_from_inode_queue(page);
remove_page_from_hash_queue(page);
page->mapping = NULL;
@@ -329,21 +321,12 @@ int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
cache_unlock_continue:
spin_unlock(&pagecache_lock);
unlock_continue:
+ spin_lock(&pagemap_lru_lock);
UnlockPage(page);
put_page(page);
-dispose_relock_continue:
- /* even if the dispose list is local, a truncate_inode_page()
- may remove a page from its queue so always
- synchronize with the lru lock while accesing the
- page->lru field */
- spin_lock(&pagemap_lru_lock);
list_add(page_lru, dispose);
continue;
-unlock_noput_continue:
- UnlockPage(page);
- goto dispose_relock_continue;
-
dispose_continue:
list_add(page_lru, dispose);
}
@@ -484,7 +467,7 @@ static inline void __add_to_page_cache(struct page * page,
struct page *alias;
unsigned long flags;
- flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error));
+ flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty));
page->flags = flags | (1 << PG_locked) | (1 << PG_referenced);
get_page(page);
page->index = offset;
@@ -1724,10 +1707,8 @@ static int msync_interval(struct vm_area_struct * vma,
error = vma->vm_ops->sync(vma, start, end-start, flags);
if (!error && (flags & MS_SYNC)) {
struct file * file = vma->vm_file;
- if (file) {
- struct dentry * dentry = file->f_dentry;
- error = file_fsync(file, dentry);
- }
+ if (file)
+ error = file_fsync(file, file->f_dentry);
}
return error;
}
@@ -2237,9 +2218,9 @@ asmlinkage long sys_mincore(unsigned long start, size_t len,
down(&current->mm->mmap_sem);
- if (start & ~PAGE_MASK)
+ if (start & ~PAGE_CACHE_MASK)
goto out;
- len = (len + ~PAGE_MASK) & PAGE_MASK;
+ len = (len + ~PAGE_CACHE_MASK) & PAGE_CACHE_MASK;
end = start + len;
if (end < start)
goto out;
@@ -2371,8 +2352,7 @@ static inline void remove_suid(struct inode *inode)
}
/*
- * Write to a file through the page cache. This is mainly for the
- * benefit of NFS and possibly other network-based file systems.
+ * Write to a file through the page cache.
*
* We currently put everything into the page cache prior to writing it.
* This is not a problem when writing full pages. With partial pages,
@@ -2389,8 +2369,7 @@ static inline void remove_suid(struct inode *inode)
ssize_t
generic_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
loff_t pos;
diff --git a/mm/memory.c b/mm/memory.c
index 1bb7433c0..28791baa2 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1053,7 +1053,7 @@ static int do_swap_page(struct task_struct * tsk,
pte = mk_pte(page, vma->vm_page_prot);
- set_bit(PG_swap_entry, &page->flags);
+ SetPageSwapEntry(page);
/*
* Freeze the "shared"ness of the page, ie page_count + swap_count.
diff --git a/mm/numa.c b/mm/numa.c
index df75e65ad..3826d636e 100644
--- a/mm/numa.c
+++ b/mm/numa.c
@@ -22,10 +22,11 @@ pg_data_t contig_page_data = { bdata: &contig_bootmem_data };
* Should be invoked with paramters (0, 0, unsigned long *[], start_paddr).
*/
void __init free_area_init_node(int nid, pg_data_t *pgdat,
- unsigned long *zones_size, unsigned long zone_start_paddr)
+ unsigned long *zones_size, unsigned long zone_start_paddr,
+ unsigned long *zholes_size)
{
free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size,
- zone_start_paddr);
+ zone_start_paddr, zholes_size);
}
#endif /* !CONFIG_DISCONTIGMEM */
@@ -55,7 +56,8 @@ void show_free_areas_node(int nid)
* Nodes can be initialized parallely, in no particular order.
*/
void __init free_area_init_node(int nid, pg_data_t *pgdat,
- unsigned long *zones_size, unsigned long zone_start_paddr)
+ unsigned long *zones_size, unsigned long zone_start_paddr,
+ unsigned long *zholes_size)
{
int i, size = 0;
struct page *discard;
@@ -63,7 +65,8 @@ void __init free_area_init_node(int nid, pg_data_t *pgdat,
if (mem_map == (mem_map_t *)NULL)
mem_map = (mem_map_t *)PAGE_OFFSET;
- free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_paddr);
+ free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_paddr,
+ zholes_size);
pgdat->node_id = nid;
/*
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a780c6a74..07fdaa021 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -100,12 +100,16 @@ void __free_pages_ok (struct page *page, unsigned long order)
if (page->buffers)
BUG();
+ if (page->mapping)
+ BUG();
if (page-mem_map >= max_mapnr)
BUG();
if (PageSwapCache(page))
BUG();
if (PageLocked(page))
BUG();
+ if (PageDecrAfter(page))
+ BUG();
zone = page->zone;
@@ -487,12 +491,13 @@ static inline void build_zonelists(pg_data_t *pgdat)
* - clear the memory bitmaps
*/
void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
- unsigned long *zones_size, unsigned long zone_start_paddr)
+ unsigned long *zones_size, unsigned long zone_start_paddr,
+ unsigned long *zholes_size)
{
struct page *p, *lmem_map;
unsigned long i, j;
unsigned long map_size;
- unsigned long totalpages, offset;
+ unsigned long totalpages, offset, realtotalpages;
unsigned int cumulative = 0;
pgdat->node_next = pgdat_list;
@@ -503,7 +508,12 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
unsigned long size = zones_size[i];
totalpages += size;
}
- printk("On node %d totalpages: %lu\n", nid, totalpages);
+ realtotalpages = totalpages;
+ if (zholes_size)
+ for (i = 0; i < MAX_NR_ZONES; i++)
+ realtotalpages -= zholes_size[i];
+
+ printk("On node %d totalpages: %lu\n", nid, realtotalpages);
/*
* Select nr of pages we try to keep free for important stuff
@@ -512,7 +522,7 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
* This is fairly arbitrary, but based on some behaviour
* analysis.
*/
- i = totalpages >> 7;
+ i = realtotalpages >> 7;
if (i < 10)
i = 10;
if (i > 256)
@@ -553,21 +563,24 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
for (j = 0; j < MAX_NR_ZONES; j++) {
zone_t *zone = pgdat->node_zones + j;
unsigned long mask;
- unsigned long size;
+ unsigned long size, realsize;
- size = zones_size[j];
+ realsize = size = zones_size[j];
+ if (zholes_size)
+ realsize -= zholes_size[j];
printk("zone(%lu): %lu pages.\n", j, size);
zone->size = size;
zone->name = zone_names[j];
zone->lock = SPIN_LOCK_UNLOCKED;
zone->zone_pgdat = pgdat;
+ zone->free_pages = 0;
if (!size)
continue;
zone->offset = offset;
cumulative += size;
- mask = (size / zone_balance_ratio[j]);
+ mask = (realsize / zone_balance_ratio[j]);
if (mask < zone_balance_min[j])
mask = zone_balance_min[j];
else if (mask > zone_balance_max[j])
@@ -611,7 +624,7 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
void __init free_area_init(unsigned long *zones_size)
{
- free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 0);
+ free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 0, 0);
}
static int __init setup_mem_frac(char *str)
diff --git a/mm/slab.c b/mm/slab.c
index 8bc12e2e7..976f78c1a 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -132,7 +132,7 @@
* SLAB_SELFTEST - 1 to perform a few tests, mainly for development.
*/
#define SLAB_MGMT_CHECKS 1
-#define SLAB_DEBUG_SUPPORT 0
+#define SLAB_DEBUG_SUPPORT 1
#define SLAB_STATS 0
#define SLAB_SELFTEST 0
@@ -1024,6 +1024,16 @@ static int __kmem_cache_shrink(kmem_cache_t *cachep)
slabp = cachep->c_lastp;
if (slabp->s_inuse || slabp == kmem_slab_end(cachep))
break;
+ /*
+ * If this slab is the first slab with free objects
+ * (c_freep), and as we are walking the slab chain
+ * backwards, it is also the last slab with free
+ * objects. After unlinking it, there will be no
+ * slabs with free objects, so point c_freep into the
+ * cache structure.
+ */
+ if (cachep->c_freep == slabp)
+ cachep->c_freep = kmem_slab_end(cachep);
kmem_slab_unlink(slabp);
spin_unlock_irq(&cachep->c_spinlock);
kmem_slab_destroy(cachep, slabp);
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 44adf8bdd..defe9b463 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -88,6 +88,9 @@ void __delete_from_swap_cache(struct page *page)
*/
void delete_from_swap_cache_nolock(struct page *page)
{
+ if (!PageLocked(page))
+ BUG();
+
if (block_flushpage(page, 0))
lru_cache_del(page);
@@ -122,8 +125,8 @@ void free_page_and_swap_cache(struct page *page)
}
UnlockPage(page);
}
-
- clear_bit(PG_swap_entry, &page->flags);
+
+ ClearPageSwapEntry(page);
__free_page(page);
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index e8a2a0b2f..abdb08e57 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -207,7 +207,7 @@ swp_entry_t acquire_swap_entry(struct page *page)
unsigned long offset, type;
swp_entry_t entry;
- if (!test_bit(PG_swap_entry, &page->flags))
+ if (!PageSwapEntry(page))
goto new_swap_entry;
/* We have the old entry in the page offset still */
@@ -538,7 +538,7 @@ int get_swaparea_info(char *buf)
len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
if (ptr->flags & SWP_USED) {
- char * path = d_path(ptr->swap_file, page, PAGE_SIZE);
+ char * path = d_path(ptr->swap_file, NULL, page, PAGE_SIZE);
len += sprintf(buf + len, "%-31s ", path);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index f00e9c535..1057dbb60 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -499,19 +499,19 @@ int kswapd(void *unused)
* the processes needing more memory will wake us
* up on a more timely basis.
*/
- do {
- pgdat = pgdat_list;
- while (pgdat) {
- for (i = 0; i < MAX_NR_ZONES; i++) {
- zone = pgdat->node_zones + i;
- if ((!zone->size) || (!zone->zone_wake_kswapd))
- continue;
- do_try_to_free_pages(GFP_KSWAPD, zone);
- }
- pgdat = pgdat->node_next;
+ pgdat = pgdat_list;
+ while (pgdat) {
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ zone = pgdat->node_zones + i;
+ if (tsk->need_resched)
+ schedule();
+ if ((!zone->size) || (!zone->zone_wake_kswapd))
+ continue;
+ do_try_to_free_pages(GFP_KSWAPD, zone);
}
- run_task_queue(&tq_disk);
- } while (!tsk->need_resched);
+ pgdat = pgdat->node_next;
+ }
+ run_task_queue(&tq_disk);
tsk->state = TASK_INTERRUPTIBLE;
interruptible_sleep_on(&kswapd_wait);
}
diff --git a/net/Config.in b/net/Config.in
index ce5b6faa9..624885478 100644
--- a/net/Config.in
+++ b/net/Config.in
@@ -13,9 +13,9 @@ if [ "$CONFIG_NETLINK" = "y" ]; then
tristate ' Netlink device emulation' CONFIG_NETLINK_DEV
fi
bool 'Network packet filtering (replaces ipchains)' CONFIG_NETFILTER
-#if [ "$CONFIG_NETFILTER" = "y" ]; then
-# bool ' Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
-#fi
+if [ "$CONFIG_NETFILTER" = "y" ]; then
+ bool ' Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
+fi
bool 'Socket Filtering' CONFIG_FILTER
tristate 'Unix domain sockets' CONFIG_UNIX
bool 'TCP/IP networking' CONFIG_INET
diff --git a/net/Makefile b/net/Makefile
index 44b34d799..afdfbb712 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -10,7 +10,7 @@
MOD_SUB_DIRS := ipv4
ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
netrom rose lapb x25 wanrouter netlink sched packet sunrpc \
- econet irda decnet atm khttpd
+ econet irda decnet atm khttpd ipv4/netfilter
SUB_DIRS := core ethernet sched
MOD_LIST_NAME := NET_MISC_MODULES
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 89ee1e0d5..0195f3631 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.40 2000/03/21 21:08:47 davem Exp $
+ * $Id: br.c,v 1.41 2000/03/24 01:33:36 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/bridge/br_input.c b/net/bridge/br_input.c
index fc549d76a..2ca176f95 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.4 2000/03/21 21:08:47 davem Exp $
+ * $Id: br_input.c,v 1.5 2000/03/30 01:22:23 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -94,6 +94,8 @@ static void __br_handle_frame(struct sk_buff *skb)
br_flood(br, skb, 1);
if (!passedup)
br_pass_frame_up(br, skb);
+ else
+ kfree_skb(skb);
return;
}
@@ -102,6 +104,8 @@ static void __br_handle_frame(struct sk_buff *skb)
if (dst != NULL && dst->is_local) {
if (!passedup)
br_pass_frame_up(br, skb);
+ else
+ kfree_skb(skb);
br_fdb_put(dst);
return;
}
diff --git a/net/core/datagram.c b/net/core/datagram.c
index bda174519..7f85645f0 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -87,9 +87,8 @@ static int wait_for_packet(struct sock * sk, int *err, long *timeo_p)
goto out;
/* handle signals */
- error = -ERESTARTSYS;
if (signal_pending(current))
- goto out;
+ goto interrupted;
*timeo_p = schedule_timeout(*timeo_p);
@@ -98,6 +97,8 @@ ready:
remove_wait_queue(sk->sleep, &wait);
return 0;
+interrupted:
+ error = sock_intr_errno(*timeo_p);
out:
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
@@ -248,7 +249,7 @@ unsigned int datagram_poll(struct file * file, struct socket *sock, poll_table *
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
- sk->socket->flags |= SO_NOSPACE;
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
return mask;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index f14753618..81a35e7a0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -176,6 +176,15 @@ int netdev_nit=0;
* change it and subsequent readers will get broken packet.
* --ANK (980803)
*/
+
+/**
+ * dev_add_pack - add packet handler
+ * @pt: packet type declaration
+ *
+ * Add a protocol handler to the networking stack. The passed packet_type
+ * is linked into kernel lists and may not be freed until it has been
+ * removed from the kernel lists.
+ */
void dev_add_pack(struct packet_type *pt)
{
@@ -203,8 +212,14 @@ void dev_add_pack(struct packet_type *pt)
}
-/*
- * Remove a protocol ID from the list.
+/**
+ * dev_remove_pack - remove packet handler
+ * @pt: packet type declaration
+ *
+ * Remove a protocol handler that was previously added to the kernel
+ * protocol handlers by dev_add_pack. The passed packet_type is removed
+ * from the kernel lists and can be freed or reused once this function
+ * returns.
*/
void dev_remove_pack(struct packet_type *pt)
@@ -241,9 +256,15 @@ void dev_remove_pack(struct packet_type *pt)
******************************************************************************************/
-/*
- * Find an interface by name. May be called under rtnl semaphore
- * or dev_base_lock.
+/**
+ * __dev_get_by_name - find a device by its name
+ * @name: name to find
+ *
+ * Find an interface by name. Must be called under rtnl semaphore
+ * or dev_base_lock. If the name is found a pointer to the device
+ * is returned. If the name is not found then NULL is returned. The
+ * reference counters are not incremented so the caller must be
+ * careful with locks.
*/
@@ -258,8 +279,15 @@ struct net_device *__dev_get_by_name(const char *name)
return NULL;
}
-/*
- * Find an interface by name. Any context, dev_put() to release.
+/**
+ * dev_get_by_name - find a device by its name
+ * @name: name to find
+ *
+ * Find an interface by name. This can be called from any
+ * context and does its own locking. The returned handle has
+ * the usage count incremented and the caller must use dev_put() to
+ * release it when it is no longer needed. NULL is returned if no
+ * matching device is found.
*/
struct net_device *dev_get_by_name(const char *name)
@@ -282,6 +310,18 @@ struct net_device *dev_get_by_name(const char *name)
is meaningless, if it was not issued under rtnl semaphore.
*/
+/**
+ * dev_get - test if a device exists
+ * @name: name to test for
+ *
+ * Test if a name exists. Returns true if the name is found. In order
+ * to be sure the name is not allocated or removed during the test the
+ * caller must hold the rtnl semaphore.
+ *
+ * This function primarily exists for back compatibility with older
+ * drivers.
+ */
+
int dev_get(const char *name)
{
struct net_device *dev;
@@ -292,8 +332,14 @@ int dev_get(const char *name)
return dev != NULL;
}
-/*
- * Find an interface by index. May be called under rtnl semaphore
+/**
+ * __dev_get_by_index - find a device by its ifindex
+ * @ifindex: index of device
+ *
+ * Search for an interface by index. Returns NULL if the device
+ * is not found or a pointer to the device. The device has not
+ * had its reference counter increased so the caller must be careful
+ * about locking. The caller must hold either the rtnl semaphore
* or dev_base_lock.
*/
@@ -308,8 +354,15 @@ struct net_device * __dev_get_by_index(int ifindex)
return NULL;
}
-/*
- * Find an interface by index. Any context, dev_put() to release.
+
+/**
+ * dev_get_by_index - find a device by its ifindex
+ * @ifindex: index of device
+ *
+ * Search for an interface by index. Returns NULL if the device
+ * is not found or a pointer to the device. The device returned has
+ * had a reference added and the pointer is safe until the user calls
+ * dev_put to indicate they have finished with it.
*/
struct net_device * dev_get_by_index(int ifindex)
@@ -324,8 +377,18 @@ struct net_device * dev_get_by_index(int ifindex)
return dev;
}
-/*
- * Find an interface by ll addr. May be called only under rtnl semaphore.
+/**
+ * dev_getbyhwaddr - find a device by its hardware addres
+ * @type: media type of device
+ * @ha: hardware address
+ *
+ * Search for an interface by MAC address. Returns NULL if the device
+ * is not found or a pointer to the device. The caller must hold the
+ * rtnl semaphore. The returned device has not had its ref count increased
+ * and the caller must therefore be careful about locking
+ *
+ * BUGS:
+ * If the API was consistent this would be __dev_get_by_hwaddr
*/
struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)
@@ -342,9 +405,16 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)
return NULL;
}
-/*
+/**
+ * dev_alloc_name - allocate a name for a device
+ * @dev: device
+ * @name: name format string
+ *
* Passed a format string - eg "lt%d" it will try and find a suitable
- * id. Not efficient for many devices, not called a lot..
+ * id. Not efficient for many devices, not called a lot. The caller
+ * must hold the dev_base or rtnl lock while allocating the name and
+ * adding the device in order to avoid duplicates. Returns the number
+ * of the unit assigned or a negative errno code.
*/
int dev_alloc_name(struct net_device *dev, const char *name)
@@ -365,6 +435,22 @@ int dev_alloc_name(struct net_device *dev, const char *name)
return -ENFILE; /* Over 100 of the things .. bail out! */
}
+/**
+ * dev_alloc - allocate a network device and name
+ * @name: name format string
+ * @err: error return pointer
+ *
+ * Passed a format string - eg "lt%d" it will allocate a network device
+ * and space for the name. NULL is returned if no memory is available.
+ * If the allocation succeeds then the name is assigned and the
+ * device pointer returned. NULL is returned if the name allocation failed.
+ * The cause of an error is returned as a negative errno code in the
+ * variable err points to.
+ *
+ * The claler must hold the dev_base or rtnl locks when doing this in order
+ * to avoid duplicate name allocations.
+ */
+
struct net_device *dev_alloc(const char *name, int *err)
{
struct net_device *dev=kmalloc(sizeof(struct net_device)+16, GFP_KERNEL);
@@ -382,6 +468,15 @@ struct net_device *dev_alloc(const char *name, int *err)
return dev;
}
+/**
+ * netdev_state_change - device changes state
+ * @dev: device to cause notification
+ *
+ * Called to indicate a device has changed state. This function calls
+ * the notifier chains for netdev_chain and sends a NEWLINK message
+ * to the routing socket.
+ */
+
void netdev_state_change(struct net_device *dev)
{
if (dev->flags&IFF_UP) {
@@ -391,12 +486,17 @@ void netdev_state_change(struct net_device *dev)
}
-/*
- * Find and possibly load an interface.
- */
-
#ifdef CONFIG_KMOD
+/**
+ * dev_load - load a network module
+ * @name: name of interface
+ *
+ * If a network interface is not present and the process has suitable
+ * privileges this function loads the module. If module loading is not
+ * available in this kernel then it becomes a nop.
+ */
+
void dev_load(const char *name)
{
if (!__dev_get_by_name(name) && capable(CAP_SYS_MODULE))
@@ -416,8 +516,17 @@ static int default_rebuild_header(struct sk_buff *skb)
return 1;
}
-/*
- * Prepare an interface for use.
+/**
+ * dev_open - prepare an interface for use.
+ * @dev: device to open
+ *
+ * Takes a device from down to up state. The devices private open
+ * function is invoked and then the multicast lists are loaded. Finally
+ * the device is moved into the up state and a NETDEV_UP message is
+ * sent to the netdev notifier chain.
+ *
+ * Calling this function on an active interface is a nop. On a failure
+ * a negative errno code is returned.
*/
int dev_open(struct net_device *dev)
@@ -508,8 +617,14 @@ void dev_clear_fastroute(struct net_device *dev)
}
#endif
-/*
- * Completely shutdown an interface.
+/**
+ * dev_close - shutdown an interface.
+ * @dev: device to shutdown
+ *
+ * This function moves an active device into down state. A
+ * NETDEV_GOING_DOWN is sent to the netev notifier chain. The device
+ * is then deactivated and finally a NETDEV_DOWN is sent to the notifier
+ * chain.
*/
int dev_close(struct net_device *dev)
@@ -560,12 +675,31 @@ int dev_close(struct net_device *dev)
* Device change register/unregister. These are not inline or static
* as we export them to the world.
*/
+
+/**
+ * register_netdevice_notifier - register a network notifier block
+ * @nb: notifier
+ *
+ * Register a notifier to be called when network device events occur.
+ * The notifier passed is linked into the kernel structures and must
+ * not be reused until it has been unregistered. A negative errno code
+ * is returned on a failure.
+ */
int register_netdevice_notifier(struct notifier_block *nb)
{
return notifier_chain_register(&netdev_chain, nb);
}
+/**
+ * unregister_netdevice_notifier - unregister a network notifier block
+ * @nb: notifier
+ *
+ * Unregister a notifier previously registered by register_netdevice_notifier
+ * The notifier is unlinked into the kernel structures and may
+ * then be reused. A negative errno code is returned on a failure.
+ */
+
int unregister_netdevice_notifier(struct notifier_block *nb)
{
return notifier_chain_unregister(&netdev_chain,nb);
@@ -637,6 +771,19 @@ void dev_loopback_xmit(struct sk_buff *skb)
netif_rx(newskb);
}
+/**
+ * dev_queue_xmit - transmit a buffer
+ * @skb: buffer to transmit
+ *
+ * Queue a buffer for transmission to a network device. The caller must
+ * have set the device and priority and built the buffer before calling this
+ * function. The function can be called from an interrupt.
+ *
+ * A negative errno code is returned on a failure. A success does not
+ * guarantee the frame will be transmitted as it may be dropped due
+ * to congestion or traffic shaping.
+ */
+
int dev_queue_xmit(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
@@ -770,9 +917,14 @@ static void netdev_wakeup(void)
}
#endif
-/*
- * Receive a packet from a device driver and queue it for the upper
- * (protocol) levels. It always succeeds.
+/**
+ * netif_rx - post buffer to the network code
+ * @skb: buffer to post
+ *
+ * This function receives a packet from a device driver and queues it for
+ * the upper (protocol) levels to process. It always succeeds. The buffer
+ * may be dropped during processing for congestion control or by the
+ * protocol layers.
*/
void netif_rx(struct sk_buff *skb)
@@ -922,6 +1074,14 @@ static void net_tx_action(struct softirq_action *h)
}
}
+/**
+ * net_call_rx_atomic
+ * @fn: function to call
+ *
+ * Make a function call that is atomic with respect to the protocol
+ * layers
+ */
+
void net_call_rx_atomic(void (*fn)(void))
{
br_write_lock_bh(BR_NETPROTO_LOCK);
@@ -1063,10 +1223,18 @@ softnet_break:
return;
}
-/* Protocol dependent address dumping routines */
-
static gifconf_func_t * gifconf_list [NPROTO];
+/**
+ * register_gifconf - register a SIOCGIF handler
+ * @family: Address family
+ * @gifconf: Function handler
+ *
+ * Register protocol dependent address dumping routines. The handler
+ * that is passed must not be freed or reused until it has been replaced
+ * by another handler.
+ */
+
int register_gifconf(unsigned int family, gifconf_func_t * gifconf)
{
if (family>=NPROTO)
@@ -1381,6 +1549,18 @@ static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
#endif /* CONFIG_PROC_FS */
#endif /* WIRELESS_EXT */
+/**
+ * netdev_set_master - set up master/slave pair
+ * @slave: slave device
+ * @master: new master device
+ *
+ * Changes the master device of the slave. Pass NULL to break the
+ * bonding. The caller must hold the RTNL semaphore. On a failure
+ * a negative errno code is returned. On success the reference counts
+ * are adjusted, RTM_NEWLINK is sent to the routing socket and the
+ * function returns zero.
+ */
+
int netdev_set_master(struct net_device *slave, struct net_device *master)
{
struct net_device *old = slave->master;
@@ -1409,6 +1589,17 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
return 0;
}
+/**
+ * dev_set_promiscuity - update promiscuity count on a device
+ * @dev: device
+ * @inc: modifier
+ *
+ * Add or remove promsicuity from a device. While the count in the device
+ * remains above zero the interface remains promiscuous. Once it hits zero
+ * the device reverts back to normal filtering operation. A negative inc
+ * value is used to drop promiscuity on the device.
+ */
+
void dev_set_promiscuity(struct net_device *dev, int inc)
{
unsigned short old_flags = dev->flags;
@@ -1430,6 +1621,18 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
}
}
+/**
+ * dev_set_allmulti - update allmulti count on a device
+ * @dev: device
+ * @inc: modifier
+ *
+ * Add or remove reception of all multicast frames to a device. While the
+ * count in the device remains above zero the interface remains listening
+ * to all interfaces. Once it hits zero the device reverts back to normal
+ * filtering operation. A negative inc value is used to drop the counter
+ * when releasing a resource needing all multicasts.
+ */
+
void dev_set_allmulti(struct net_device *dev, int inc)
{
unsigned short old_flags = dev->flags;
@@ -1673,12 +1876,22 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
return -EINVAL;
}
-
/*
* This function handles all "interface"-type I/O control requests. The actual
* 'doing' part of this is dev_ifsioc above.
*/
+/**
+ * dev_ioctl - network device ioctl
+ * @cmd: command to issue
+ * @arg: pointer to a struct ifreq in user space
+ *
+ * Issue ioctl functions to devices. This is normally called by the
+ * user space syscall interfaces but can sometimes be useful for
+ * other purposes. The return value is the return from the syscall if
+ * positive or a negative errno code on error.
+ */
+
int dev_ioctl(unsigned int cmd, void *arg)
{
struct ifreq ifr;
@@ -1811,6 +2024,15 @@ int dev_ioctl(unsigned int cmd, void *arg)
}
}
+
+/**
+ * dev_new_index - allocate an ifindex
+ *
+ * Returns a suitable unique value for a new device interface number.
+ * The caller must hold the rtnl semaphore to be sure it remains
+ * unique.
+ */
+
int dev_new_index(void)
{
static int ifindex;
@@ -1824,6 +2046,19 @@ int dev_new_index(void)
static int dev_boot_phase = 1;
+/**
+ * register_netdevice - register a network device
+ * @dev: device to register
+ *
+ * Take a completed network device structure and add it to the kernel
+ * interfaces. A NETDEV_REGISTER message is sent to the netdev notifier
+ * chain. 0 is returned on success. A negative errno code is returned
+ * on a failure to set up the device, or if the name is a duplicate.
+ *
+ * BUGS:
+ * The locking appears insufficient to guarantee two parallel registers
+ * will not get the same name.
+ */
int register_netdevice(struct net_device *dev)
{
@@ -1917,6 +2152,14 @@ int register_netdevice(struct net_device *dev)
return 0;
}
+/**
+ * netdev_finish_unregister - complete unregistration
+ * @dev: device
+ *
+ * Destroy and free a dead device. A value of zero is returned on
+ * success.
+ */
+
int netdev_finish_unregister(struct net_device *dev)
{
BUG_TRAP(dev->ip_ptr==NULL);
@@ -1924,7 +2167,7 @@ int netdev_finish_unregister(struct net_device *dev)
BUG_TRAP(dev->dn_ptr==NULL);
if (!dev->deadbeaf) {
- printk("Freeing alive device %p, %s\n", dev, dev->name);
+ printk(KERN_ERR "Freeing alive device %p, %s\n", dev, dev->name);
return 0;
}
#ifdef NET_REFCNT_DEBUG
@@ -1937,6 +2180,15 @@ int netdev_finish_unregister(struct net_device *dev)
return 0;
}
+/**
+ * unregister_netdevice - remove device from the kernel
+ * @dev: device
+ *
+ * This function shuts down a device interface and removes it
+ * from the kernel tables. On success 0 is returned, on a failure
+ * a negative errno code is returned.
+ */
+
int unregister_netdevice(struct net_device *dev)
{
unsigned long now;
diff --git a/net/core/filter.c b/net/core/filter.c
index 8749e8c7b..9d16a69fe 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -54,7 +54,12 @@ static u8 *load_pointer(struct sk_buff *skb, int k)
return NULL;
}
-/*
+/**
+ * sk_run_filter - run a filter on a socket
+ * @skb: buffer to run the filter on
+ * @filter: filter to apply
+ * @flen: length of filter
+ *
* Decode and apply filter instructions to the skb->data.
* Return length to keep, 0 for none. skb is the data we are
* filtering, filter is the array of filter instructions, and
@@ -341,9 +346,17 @@ load_b:
return (0);
}
-/*
+/**
+ * sk_chk_filter - verify socket filter code
+ * @filter: filter to verify
+ * @flen: length of filter
+ *
* Check the user's filter code. If we let some ugly
- * filter code slip through kaboom!
+ * filter code slip through kaboom! The filter must contain
+ * no references or jumps that are out of range, no illegal instructions
+ * and no backward jumps. It must end with a RET instruction
+ *
+ * Returns 0 if the rule set is legal or a negative errno code if not.
*/
int sk_chk_filter(struct sock_filter *filter, int flen)
@@ -413,9 +426,15 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
return (BPF_CLASS(filter[flen - 1].code) == BPF_RET)?0:-EINVAL;
}
-/*
+/**
+ * sk_attach_filter - attach a socket filter
+ * @fprog: the filter program
+ * @sk: the socket to use
+ *
* Attach the user's filter code. We first run some sanity checks on
- * it to make sure it does not explode on us later.
+ * it to make sure it does not explode on us later. If an error
+ * occurs or there is insufficient memory for the filter a negative
+ * errno code is returned. On success the return is zero.
*/
int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index dad1f3925..54230a273 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4,7 +4,7 @@
* Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
* Florian La Roche <rzsfl@rz.uni-sb.de>
*
- * Version: $Id: skbuff.c,v 1.70 2000/03/17 14:41:39 davem Exp $
+ * Version: $Id: skbuff.c,v 1.71 2000/03/29 11:58:33 davem Exp $
*
* Fixes:
* Alan Cox : Fixed the worst of the load balancer bugs.
@@ -77,6 +77,15 @@ static union {
* reliable.
*/
+/**
+ * skb_over_panic - private function
+ * @skb: buffer
+ * @sz: size
+ * @here: address
+ *
+ * Out of line support code for skb_put. Not user callable
+ */
+
void skb_over_panic(struct sk_buff *skb, int sz, void *here)
{
printk("skput:over: %p:%d put:%d dev:%s",
@@ -84,6 +93,16 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here)
*(int*)0 = 0;
}
+/**
+ * skb_under_panic - private function
+ * @skb: buffer
+ * @sz: size
+ * @here: address
+ *
+ * Out of line support code for skb_push. Not user callable
+ */
+
+
void skb_under_panic(struct sk_buff *skb, int sz, void *here)
{
printk("skput:under: %p:%d put:%d dev:%s",
@@ -130,6 +149,19 @@ static __inline__ void skb_head_to_pool(struct sk_buff *skb)
*
*/
+/**
+ * alloc_skb - allocate a network buffer
+ * @size: size to allocate
+ * @gfp_mask: allocation mask
+ *
+ * Allocate a new sk_buff. The returned buffer has no headroom and a
+ * tail room of size bytes. The object has a reference count of one.
+ * The return is the buffer. On a failure the return is NULL.
+ *
+ * Buffers may only be allocated from interrupts using a gfp_mask of
+ * GFP_ATOMIC.
+ */
+
struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
{
struct sk_buff *skb;
@@ -227,8 +259,13 @@ void kfree_skbmem(struct sk_buff *skb)
skb_head_to_pool(skb);
}
-/*
- * Free an sk_buff. Release anything attached to the buffer. Clean the state.
+/**
+ * __kfree_skb - private function
+ * @skb: buffer
+ *
+ * Free an sk_buff. Release anything attached to the buffer.
+ * Clean the state. This is an internal helper function. Users should
+ * always call kfree_skb
*/
void __kfree_skb(struct sk_buff *skb)
@@ -258,8 +295,18 @@ void __kfree_skb(struct sk_buff *skb)
kfree_skbmem(skb);
}
-/*
- * Duplicate an sk_buff. The new one is not owned by a socket.
+/**
+ * skb_clone - duplicate an sk_buff
+ * @skb: buffer to clone
+ * @gfp_mask: allocation priority
+ *
+ * Duplicate an sk_buff. The new one is not owned by a socket. Both
+ * copies share the same packet data but not structure. The new
+ * buffer has a reference count of 1. If the allocation fails the
+ * function returns NULL otherwise the new buffer is returned.
+ *
+ * If this function is called from an interrupt gfp_mask must be
+ * GFP_ATOMIC.
*/
struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
@@ -331,8 +378,18 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#endif
}
-/*
- * This is slower, and copies the whole data area
+/**
+ * skb_copy - copy an sk_buff
+ * @skb: buffer to copy
+ * @gfp_mask: allocation priority
+ *
+ * Make a copy of both an sk_buff and its data. This is used when the
+ * caller wishes to modify the data and needs a private copy of the
+ * data to alter. Returns NULL on failure or the pointer to the buffer
+ * on success. The returned buffer has a reference count of 1.
+ *
+ * You must pass GFP_ATOMIC as the allocation priority if this function
+ * is called from an interrupt.
*/
struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
@@ -359,6 +416,26 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
return n;
}
+/**
+ * skb_copy - copy and expand sk_buff
+ * @skb: buffer to copy
+ * @newheadroom: new free bytes at head
+ * @newtailroom: new free bytes at tail
+ * @gfp_mask: allocation priority
+ *
+ * Make a copy of both an sk_buff and its data and while doing so
+ * allocate additional space.
+ *
+ * This is used when the caller wishes to modify the data and needs a
+ * private copy of the data to alter as well as more space for new fields.
+ * Returns NULL on failure or the pointer to the buffer
+ * on success. The returned buffer has a reference count of 1.
+ *
+ * You must pass GFP_ATOMIC as the allocation priority if this function
+ * is called from an interrupt.
+ */
+
+
struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
int newheadroom,
int newtailroom,
diff --git a/net/core/sock.c b/net/core/sock.c
index 21f15b5e7..ce25381c9 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -7,7 +7,7 @@
* handler for protocols to use and generic option handler.
*
*
- * Version: $Id: sock.c,v 1.90 2000/02/27 19:48:11 davem Exp $
+ * Version: $Id: sock.c,v 1.91 2000/03/25 01:55:03 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -731,11 +731,12 @@ static long sock_wait_for_wmem(struct sock * sk, long timeo)
{
DECLARE_WAITQUEUE(wait, current);
- sk->socket->flags &= ~SO_NOSPACE;
+ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
add_wait_queue(sk->sleep, &wait);
for (;;) {
if (signal_pending(current))
break;
+ set_bit(SOCK_NOSPACE, &sk->socket->flags);
set_current_state(TASK_INTERRUPTIBLE);
if (atomic_read(&sk->wmem_alloc) < sk->sndbuf)
break;
@@ -802,18 +803,20 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
* This means we have too many buffers for this socket already.
*/
- sk->socket->flags |= SO_NOSPACE;
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+ set_bit(SOCK_NOSPACE, &sk->socket->flags);
err = -EAGAIN;
if (!timeo)
goto failure;
- err = -ERESTARTSYS;
if (signal_pending(current))
- goto failure;
+ goto interrupted;
timeo = sock_wait_for_wmem(sk, timeo);
}
return skb;
+interrupted:
+ err = sock_intr_errno(timeo);
failure:
*errcode = err;
return NULL;
@@ -1079,7 +1082,7 @@ int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *
void sock_def_wakeup(struct sock *sk)
{
read_lock(&sk->callback_lock);
- if(!sk->dead)
+ if (sk->sleep && waitqueue_active(sk->sleep))
wake_up_interruptible_all(sk->sleep);
read_unlock(&sk->callback_lock);
}
@@ -1087,20 +1090,18 @@ void sock_def_wakeup(struct sock *sk)
void sock_def_error_report(struct sock *sk)
{
read_lock(&sk->callback_lock);
- if (!sk->dead) {
+ if (sk->sleep && waitqueue_active(sk->sleep))
wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket,0,POLL_ERR);
- }
+ sk_wake_async(sk,0,POLL_ERR);
read_unlock(&sk->callback_lock);
}
void sock_def_readable(struct sock *sk, int len)
{
read_lock(&sk->callback_lock);
- if(!sk->dead) {
+ if (sk->sleep && waitqueue_active(sk->sleep))
wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket,1,POLL_IN);
- }
+ sk_wake_async(sk,1,POLL_IN);
read_unlock(&sk->callback_lock);
}
@@ -1111,14 +1112,15 @@ void sock_def_write_space(struct sock *sk)
/* Do not wake up a writer until he can make "significant"
* progress. --DaveM
*/
- if(!sk->dead &&
- ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) {
- wake_up_interruptible(sk->sleep);
+ if((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf) {
+ if (sk->sleep && waitqueue_active(sk->sleep))
+ wake_up_interruptible(sk->sleep);
/* Should agree with poll, otherwise some programs break */
if (sock_writeable(sk))
- sock_wake_async(sk->socket, 2, POLL_OUT);
+ sk_wake_async(sk, 2, POLL_OUT);
}
+
read_unlock(&sk->callback_lock);
}
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index a2453c06a..c560ea01e 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1670,14 +1670,14 @@ static int dn_recvmsg(struct socket *sock, struct msghdr *msg, int size,
goto out;
}
- sock->flags |= SO_WAITDATA;
+ set_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
SOCK_SLEEP_PRE(sk)
if (!dn_data_ready(sk, queue, flags, target))
schedule();
SOCK_SLEEP_POST(sk)
- sock->flags &= ~SO_WAITDATA;
+ clear_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
}
for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 854ed0e92..00e62aa76 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -438,7 +438,8 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig
if (!sk->dead) {
struct socket *sock = sk->socket;
wake_up_interruptible(sk->sleep);
- if (!(sock->flags & SO_WAITDATA) && sock->fasync_list)
+ if (sock && sock->fasync_list &&
+ !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
kill_fasync(sock->fasync_list, sig,
(sig == SIGURG) ? POLL_PRI : POLL_IN);
}
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index ebbf4163f..669aeccce 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -133,13 +133,13 @@ struct sk_buff *dn_alloc_send_skb(struct sock *sk, int *size, int noblock, int *
}
if (space < len) {
- sk->socket->flags |= SO_NOSPACE;
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
if (noblock) {
*err = EWOULDBLOCK;
break;
}
- sk->socket->flags &= ~SO_NOSPACE;
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
SOCK_SLEEP_PRE(sk)
if ((sk->sndbuf - atomic_read(&sk->wmem_alloc)) < len)
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index b848151a9..d3fc0e38f 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -5,7 +5,7 @@
*
* PF_INET protocol family socket handler.
*
- * Version: $Id: af_inet.c,v 1.108 2000/02/21 16:25:59 davem Exp $
+ * Version: $Id: af_inet.c,v 1.109 2000/03/25 01:55:10 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -607,7 +607,7 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
if (!timeo || !inet_wait_for_connect(sk, timeo))
goto out;
- err = -ERESTARTSYS;
+ err = sock_intr_errno(timeo);
if (signal_pending(current))
goto out;
}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 7561e190b..7c462ac08 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -3,7 +3,7 @@
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.66 2000/03/17 14:41:50 davem Exp $
+ * Version: $Id: icmp.c,v 1.67 2000/03/25 01:55:11 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -1128,6 +1128,7 @@ void __init icmp_init(struct net_proto_family *ops)
if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0)
panic("Failed to create the ICMP control socket.\n");
icmp_socket->sk->allocation=GFP_ATOMIC;
+ icmp_socket->sk->sndbuf = SK_WMEM_MAX*2;
icmp_socket->sk->protinfo.af_inet.ttl = MAXTTL;
/* Unhash it so that IP input processing does not even
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index f3013ca57..5792c5de7 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.82 2000/03/17 14:41:50 davem Exp $
+ * Version: $Id: ip_output.c,v 1.83 2000/03/25 01:52:08 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -415,14 +415,13 @@ int ip_queue_xmit(struct sk_buff *skb)
/* OK, we know where to send it, allocate and build IP header. */
iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
- iph->version = 4;
- iph->ihl = 5;
- iph->tos = sk->protinfo.af_inet.tos;
+ *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (sk->protinfo.af_inet.tos & 0xff));
+ iph->tot_len = htons(skb->len);
iph->frag_off = 0;
iph->ttl = sk->protinfo.af_inet.ttl;
- iph->daddr = rt->rt_dst;
- iph->saddr = rt->rt_src;
iph->protocol = sk->protocol;
+ iph->saddr = rt->rt_src;
+ iph->daddr = rt->rt_dst;
skb->nh.iph = iph;
/* Transport layer set skb->h.foo itself. */
@@ -431,8 +430,6 @@ int ip_queue_xmit(struct sk_buff *skb)
ip_options_build(skb, opt, sk->daddr, rt, 0);
}
- iph->tot_len = htons(skb->len);
-
return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
ip_queue_xmit2);
diff --git a/net/ipv4/netfilter/.cvsignore b/net/ipv4/netfilter/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/net/ipv4/netfilter/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/net/ipv4/netfilter/Config.in b/net/ipv4/netfilter/Config.in
index bf2a28269..406d2ea3d 100644
--- a/net/ipv4/netfilter/Config.in
+++ b/net/ipv4/netfilter/Config.in
@@ -39,6 +39,7 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then
if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
dep_tristate ' Full NAT' CONFIG_IP_NF_NAT $CONFIG_IP_NF_IPTABLES
if [ "$CONFIG_IP_NF_NAT" != "n" ]; then
+ define_bool CONFIG_IP_NF_NAT_NEEDED y
dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
fi
@@ -56,8 +57,14 @@ fi
if [ "$CONFIG_IP_NF_CONNTRACK" != "y" ]; then
if [ "$CONFIG_IP_NF_IPTABLES" != "y" ]; then
tristate 'ipchains (2.2-style) support' CONFIG_IP_NF_COMPAT_IPCHAINS
+ if [ "$CONFIG_IP_NF_COMPAT_IPCHAINS" != "n" ]; then
+ define_bool CONFIG_IP_NF_NAT_NEEDED y
+ fi
if [ "$CONFIG_IP_NF_COMPAT_IPCHAINS" != "y" ]; then
tristate 'ipfwadm (2.0-style) support' CONFIG_IP_NF_COMPAT_IPFWADM
+ if [ "$CONFIG_IP_NF_COMPAT_IPFWADM" != "n" ]; then
+ define_bool CONFIG_IP_NF_NAT_NEEDED y
+ fi
fi
fi
fi
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index c507acc31..db276076a 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -15,10 +15,12 @@ IP_NF_CONNTRACK_OBJ:=ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntra
IP_NF_NAT_OBJ:=ip_nat_core.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
+# All the parts of conntrack and NAT required for compatibility layer.
+IP_NF_COMPAT_LAYER:=ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(IP_NF_CONNTRACK_OBJ) $(IP_NF_NAT_OBJ)
+
# Link order matters here.
ifeq ($(CONFIG_IP_NF_CONNTRACK),y)
-OX_OBJS += ip_conntrack_standalone.o
-O_OBJS += $(IP_NF_CONNTRACK_OBJ)
+O_OBJS += ip_conntrack_standalone.o $(IP_NF_CONNTRACK_OBJ)
else
ifeq ($(CONFIG_IP_NF_CONNTRACK),m)
MI_OBJS += $(IP_NF_CONNTRACK_OBJ)
@@ -27,16 +29,8 @@ else
endif
endif
-ifeq ($(CONFIG_IP_NF_QUEUE),y)
-O_OBJS += ip_queue.o
-else
- ifeq ($(CONFIG_IP_NF_QUEUE),m)
- M_OBJS += ip_queue.o
- endif
-endif
-
ifeq ($(CONFIG_IP_NF_FTP),y)
-OX_OBJS += ip_conntrack_ftp.o
+O_OBJS += ip_conntrack_ftp.o
else
ifeq ($(CONFIG_IP_NF_FTP),m)
MX_OBJS += ip_conntrack_ftp.o
@@ -47,7 +41,7 @@ ifeq ($(CONFIG_IP_NF_IPTABLES),y)
O_OBJS += ip_tables.o
else
ifeq ($(CONFIG_IP_NF_IPTABLES),m)
- M_OBJS += ip_tables.o
+ MX_OBJS += ip_tables.o
endif
endif
@@ -115,17 +109,8 @@ else
endif
endif
-ifeq ($(CONFIG_IP_NF_FILTER),y)
-O_OBJS += iptable_filter.o
-else
- ifeq ($(CONFIG_IP_NF_FILTER),m)
- M_OBJS += iptable_filter.o
- endif
-endif
-
ifeq ($(CONFIG_IP_NF_NAT),y)
-OX_OBJS += ip_nat_standalone.o
-O_OBJS += ip_nat_rule.o $(IP_NF_NAT_OBJ)
+O_OBJS += ip_nat_standalone.o ip_nat_rule.o $(IP_NF_NAT_OBJ)
ifeq ($(CONFIG_IP_NF_FTP),y)
O_OBJS += ip_nat_ftp.o
endif
@@ -140,6 +125,14 @@ else
endif
endif
+ifeq ($(CONFIG_IP_NF_FILTER),y)
+O_OBJS += iptable_filter.o
+else
+ ifeq ($(CONFIG_IP_NF_FILTER),m)
+ M_OBJS += iptable_filter.o
+ endif
+endif
+
ifeq ($(CONFIG_IP_NF_MANGLE),y)
O_OBJS += iptable_mangle.o
else
@@ -205,7 +198,7 @@ else
endif
ifeq ($(CONFIG_IP_NF_COMPAT_IPCHAINS),y)
-O_OBJS += ipchains.o
+O_OBJS += ipchains_core.o $(IP_NF_COMPAT_LAYER)
else
ifeq ($(CONFIG_IP_NF_COMPAT_IPCHAINS),m)
M_OBJS += ipchains.o
@@ -213,13 +206,21 @@ else
endif
ifeq ($(CONFIG_IP_NF_COMPAT_IPFWADM),y)
-O_OBJS += ipfwadm.o
+O_OBJS += ipfwadm_core.o $(IP_NF_COMPAT_LAYER)
else
ifeq ($(CONFIG_IP_NF_COMPAT_IPFWADM),m)
M_OBJS += ipfwadm.o
endif
endif
+ifeq ($(CONFIG_IP_NF_QUEUE),y)
+O_OBJS += ip_queue.o
+else
+ ifeq ($(CONFIG_IP_NF_QUEUE),m)
+ M_OBJS += ip_queue.o
+ endif
+endif
+
include $(TOPDIR)/Rules.make
ip_conntrack.o: ip_conntrack_standalone.o $(IP_NF_CONNTRACK_OBJ)
@@ -228,11 +229,8 @@ ip_conntrack.o: ip_conntrack_standalone.o $(IP_NF_CONNTRACK_OBJ)
iptable_nat.o: ip_nat_standalone.o ip_nat_rule.o $(IP_NF_NAT_OBJ)
$(LD) -r -o $@ ip_nat_standalone.o ip_nat_rule.o $(IP_NF_NAT_OBJ)
-# All the parts of conntrack and NAT required for compatibility layer.
-IP_NF_COMPAT_LAYER:=ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(IP_NF_CONNTRACK_OBJ) $(IP_NF_NAT_OBJ)
-
ipfwadm.o: ipfwadm_core.o $(IP_NF_COMPAT_LAYER)
$(LD) -r -o $@ ipfwadm_core.o $(IP_NF_COMPAT_LAYER)
-ipchains.o: ipchains_core.o $(IP_NF_COMPAT_LAYER)
+ipchains.o: ipchains_core.o $(IP_NF_COMPAT_LAYER)
$(LD) -r -o $@ ipchains_core.o $(IP_NF_COMPAT_LAYER)
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 9007cdc89..197c2e3b4 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -22,6 +22,7 @@
#include <net/checksum.h>
#include <linux/stddef.h>
#include <linux/sysctl.h>
+#include <linux/slab.h>
/* This rwlock protects the main hash table, protocol/helper/expected
registrations, conntrack timers*/
@@ -43,13 +44,14 @@
DECLARE_RWLOCK(ip_conntrack_lock);
void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
-static LIST_HEAD(expect_list);
-static LIST_HEAD(protocol_list);
+LIST_HEAD(expect_list);
+LIST_HEAD(protocol_list);
static LIST_HEAD(helpers);
unsigned int ip_conntrack_htable_size = 0;
static int ip_conntrack_max = 0;
static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
struct list_head *ip_conntrack_hash;
+static kmem_cache_t *ip_conntrack_cachep;
extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
@@ -167,7 +169,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
if (ip_conntrack_destroyed)
ip_conntrack_destroyed(ct);
- kfree(ct);
+ kmem_cache_free(ip_conntrack_cachep, ct);
atomic_dec(&ip_conntrack_count);
}
@@ -355,7 +357,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
return 1;
}
- conntrack = kmalloc(sizeof(struct ip_conntrack), GFP_ATOMIC);
+ conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
if (!conntrack) {
DEBUGP("Can't allocate conntrack.\n");
return 1;
@@ -374,7 +376,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
conntrack->infos[i].master = &conntrack->ct_general;
if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
- kfree(conntrack);
+ kmem_cache_free(ip_conntrack_cachep, conntrack);
return 1;
}
@@ -384,7 +386,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
if (__ip_conntrack_find(tuple, NULL)) {
WRITE_UNLOCK(&ip_conntrack_lock);
printk("ip_conntrack: Wow someone raced us!\n");
- kfree(conntrack);
+ kmem_cache_free(ip_conntrack_cachep, conntrack);
return 0;
}
conntrack->helper = LIST_FIND(&helpers, helper_cmp,
@@ -796,6 +798,7 @@ static struct nf_sockopt_ops so_getorigdst
#define NET_IP_CONNTRACK_MAX 2089
#define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max"
+#ifdef CONFIG_SYSCTL
static struct ctl_table_header *ip_conntrack_sysctl_header;
static ctl_table ip_conntrack_table[] = {
@@ -813,6 +816,7 @@ static ctl_table ip_conntrack_root_table[] = {
{CTL_NET, "net", NULL, 0, 0555, ip_conntrack_dir_table, 0, 0, 0, 0, 0},
{ 0 }
};
+#endif /*CONFIG_SYSCTL*/
static int kill_all(const struct ip_conntrack *i, void *data)
{
@@ -823,8 +827,11 @@ static int kill_all(const struct ip_conntrack *i, void *data)
supposed to kill the mall. */
void ip_conntrack_cleanup(void)
{
+#ifdef CONFIG_SYSCTL
unregister_sysctl_table(ip_conntrack_sysctl_header);
+#endif
ip_ct_selective_cleanup(kill_all, NULL);
+ kmem_cache_destroy(ip_conntrack_cachep);
vfree(ip_conntrack_hash);
nf_unregister_sockopt(&so_getorigdst);
}
@@ -855,6 +862,16 @@ int __init ip_conntrack_init(void)
return -ENOMEM;
}
+ ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
+ sizeof(struct ip_conntrack), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!ip_conntrack_cachep) {
+ printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
+ vfree(ip_conntrack_hash);
+ nf_unregister_sockopt(&so_getorigdst);
+ return -ENOMEM;
+ }
+
/* Don't NEED lock here, but good form anyway. */
WRITE_LOCK(&ip_conntrack_lock);
/* Sew in builtin protocols. */
@@ -873,19 +890,12 @@ int __init ip_conntrack_init(void)
ip_conntrack_sysctl_header
= register_sysctl_table(ip_conntrack_root_table, 0);
if (ip_conntrack_sysctl_header == NULL) {
+ kmem_cache_destroy(ip_conntrack_cachep);
vfree(ip_conntrack_hash);
nf_unregister_sockopt(&so_getorigdst);
return -ENOMEM;
}
#endif /*CONFIG_SYSCTL*/
- ret = ip_conntrack_protocol_tcp_init();
- if (ret != 0) {
- unregister_sysctl_table(ip_conntrack_sysctl_header);
- vfree(ip_conntrack_hash);
- nf_unregister_sockopt(&so_getorigdst);
- }
-
return ret;
}
-
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 23ccf74cf..1600156f7 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -10,6 +10,7 @@
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
DECLARE_LOCK(ip_ftp_lock);
+struct module *ip_conntrack_ftp = THIS_MODULE;
#define SERVER_STRING "227 Entering Passive Mode ("
#define CLIENT_STRING "PORT "
@@ -240,9 +241,5 @@ static void __exit fini(void)
ip_conntrack_helper_unregister(&ftp);
}
-struct module *ip_conntrack_ftp = THIS_MODULE;
-EXPORT_SYMBOL(ip_conntrack_ftp);
-EXPORT_SYMBOL(ip_ftp_lock);
-
module_init(init);
module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index 1d1256be5..cbbc1ab8c 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -2,6 +2,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/netfilter.h>
+#include <linux/in.h>
#include <linux/icmp.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 3dd448252..893248943 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -4,6 +4,7 @@
#include <linux/timer.h>
#include <linux/netfilter.h>
#include <linux/module.h>
+#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
@@ -220,8 +221,3 @@ struct ip_conntrack_protocol ip_conntrack_protocol_tcp
= { { NULL, NULL }, IPPROTO_TCP, "tcp",
tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
tcp_packet, tcp_new, NULL };
-
-int __init ip_conntrack_protocol_tcp_init(void)
-{
- return 0;
-}
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
index 688ae10fb..79ec82151 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
@@ -2,6 +2,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/netfilter.h>
+#include <linux/in.h>
#include <linux/udp.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index a69be542d..9030d9d41 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -276,6 +276,7 @@ static void __exit fini(void)
module_init(init);
module_exit(fini);
+#ifdef MODULE
EXPORT_SYMBOL(ip_conntrack_protocol_register);
EXPORT_SYMBOL(invert_tuplepr);
EXPORT_SYMBOL(ip_conntrack_alter_reply);
@@ -284,11 +285,9 @@ EXPORT_SYMBOL(ip_conntrack_get);
EXPORT_SYMBOL(ip_conntrack_module);
EXPORT_SYMBOL(ip_conntrack_helper_register);
EXPORT_SYMBOL(ip_conntrack_helper_unregister);
-EXPORT_SYMBOL(ip_conntrack_lock);
-EXPORT_SYMBOL(find_proto);
-EXPORT_SYMBOL(get_tuple);
EXPORT_SYMBOL(ip_ct_selective_cleanup);
EXPORT_SYMBOL(ip_ct_refresh);
EXPORT_SYMBOL(ip_conntrack_expect_related);
EXPORT_SYMBOL(ip_conntrack_tuple_taken);
EXPORT_SYMBOL(ip_ct_gather_frags);
+#endif
diff --git a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c
index 72dc3d816..2a08ee89c 100644
--- a/net/ipv4/netfilter/ip_fw_compat.c
+++ b/net/ipv4/netfilter/ip_fw_compat.c
@@ -14,8 +14,6 @@ struct notifier_block;
#include <linux/netfilter_ipv4/compat_firewall.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
-EXPORT_NO_SYMBOLS;
-
static struct firewall_ops *fwops;
/* From ip_fw_compat_redir.c */
diff --git a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c
index e0074c1e2..96bdc9d8d 100644
--- a/net/ipv4/netfilter/ip_fw_compat_masq.c
+++ b/net/ipv4/netfilter/ip_fw_compat_masq.c
@@ -5,6 +5,7 @@
DO IT.
*/
#include <linux/skbuff.h>
+#include <linux/in.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/udp.h>
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
index 8252e6d9b..12d40f554 100644
--- a/net/ipv4/netfilter/ip_nat_ftp.c
+++ b/net/ipv4/netfilter/ip_nat_ftp.c
@@ -11,8 +11,6 @@
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-EXPORT_NO_SYMBOLS;
-
#if 0
#define DEBUGP printk
#else
@@ -374,8 +372,6 @@ static struct ip_nat_helper ftp
static struct ip_nat_expect ftp_expect
= { { NULL, NULL }, ftp_nat_expected };
-extern struct module *ip_conntrack_ftp;
-
static int __init init(void)
{
int ret;
@@ -384,9 +380,7 @@ static int __init init(void)
if (ret == 0) {
ret = ip_nat_helper_register(&ftp);
- if (ret == 0)
- __MOD_INC_USE_COUNT(ip_conntrack_ftp);
- else
+ if (ret != 0)
ip_nat_expect_unregister(&ftp_expect);
}
return ret;
@@ -394,7 +388,6 @@ static int __init init(void)
static void __exit fini(void)
{
- __MOD_DEC_USE_COUNT(ip_conntrack_ftp);
ip_nat_helper_unregister(&ftp);
ip_nat_expect_unregister(&ftp_expect);
}
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 603111063..bfcc435c2 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -230,11 +230,13 @@ static int init_or_cleanup(int init)
printk("ip_nat_init: can't register local out hook.\n");
goto cleanup_outops;
}
- __MOD_INC_USE_COUNT(ip_conntrack_module);
+ if (ip_conntrack_module)
+ __MOD_INC_USE_COUNT(ip_conntrack_module);
return ret;
cleanup:
- __MOD_DEC_USE_COUNT(ip_conntrack_module);
+ if (ip_conntrack_module)
+ __MOD_DEC_USE_COUNT(ip_conntrack_module);
nf_unregister_hook(&ip_nat_local_out_ops);
cleanup_outops:
nf_unregister_hook(&ip_nat_out_ops);
@@ -262,9 +264,11 @@ static void __exit fini(void)
module_init(init);
module_exit(fini);
+#ifdef MODULE
EXPORT_SYMBOL(ip_nat_setup_info);
EXPORT_SYMBOL(ip_nat_helper_register);
EXPORT_SYMBOL(ip_nat_helper_unregister);
EXPORT_SYMBOL(ip_nat_expect_register);
EXPORT_SYMBOL(ip_nat_expect_unregister);
EXPORT_SYMBOL(ip_nat_cheat_check);
+#endif
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 532538321..80e43d977 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -2,7 +2,7 @@
* This is a module which is used for queueing IPv4 packets and
* communicating with userspace via netlink.
*
- * (C) 2000 James Morris
+ * (C) 2000 James Morris, this code is GPL.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
@@ -13,7 +13,6 @@
#include <linux/netfilter.h>
#include <linux/netlink.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/rtnetlink.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
@@ -21,20 +20,13 @@
#include <linux/netfilter_ipv4/ip_queue.h>
-EXPORT_NO_SYMBOLS;
-
-#define IPQ_THR_NAME "kipq"
-#define IPQ_NAME "ip_queue"
#define IPQ_QMAX_DEFAULT 1024
-
#define IPQ_PROC_FS_NAME "ip_queue"
-
#define NET_IPQ_QMAX 2088
#define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
typedef struct ipq_queue_element {
struct list_head list; /* Links element into queue */
- unsigned char state; /* State of this element */
int verdict; /* Current verdict */
struct nf_info *info; /* Extra info from netfilter */
struct sk_buff *skb; /* Packet inside */
@@ -50,178 +42,70 @@ typedef struct ipq_peer {
ipq_send_cb_t send; /* Callback for sending data to peer */
} ipq_peer_t;
-typedef struct ipq_thread {
- pid_t pid; /* PID of kernel thread */
- unsigned char terminate; /* Termination flag */
- unsigned char running; /* Running flag */
- wait_queue_head_t wq; /* I/O wait queue */
- void (*process)(void *data); /* Queue processing function */
-} ipq_thread_t;
-
typedef struct ipq_queue {
int len; /* Current queue len */
int *maxlen; /* Maximum queue len, via sysctl */
- unsigned char state; /* Current queue state */
+ unsigned char flushing; /* If queue is being flushed */
+ unsigned char terminate; /* If the queue is being terminated */
struct list_head list; /* Head of packet queue */
spinlock_t lock; /* Queue spinlock */
ipq_peer_t peer; /* Userland peer */
- ipq_thread_t thread; /* Thread context */
} ipq_queue_t;
/****************************************************************************
-*
-* Kernel thread
-*
-****************************************************************************/
-
-static void ipq_thread_init(char *thread_name)
-{
- lock_kernel();
- exit_files(current);
- daemonize();
- strcpy(current->comm, thread_name);
- unlock_kernel();
- spin_lock_irq(&current->sigmask_lock);
- flush_signals(current);
- sigfillset(&current->blocked);
- recalc_sigpending(current);
- spin_unlock_irq(&current->sigmask_lock);
-}
-
-static int ipq_thread_start(void *data)
-{
- ipq_queue_t *q = (ipq_queue_t *)data;
-
- q->thread.running = 1;
- ipq_thread_init(IPQ_THR_NAME);
- q->thread.pid = current->pid;
- while (!q->thread.terminate) {
- interruptible_sleep_on(&q->thread.wq);
- q->thread.process(q);
- }
- q->thread.running = 0;
- return 0;
-}
-
-static void ipq_thread_stop(ipq_queue_t *q)
-{
- if (!(q->thread.pid || q->thread.running))
- return;
- q->state = IPQ_QS_FLUSH;
- q->thread.terminate = 1;
- wake_up_interruptible(&q->thread.wq);
- current->state = TASK_INTERRUPTIBLE;
- while (q->thread.running) {
- schedule_timeout(HZ/10);
- current->state = TASK_RUNNING;
- }
-}
-
-static int ipq_thread_create(ipq_queue_t *q)
-{
- int status = kernel_thread(ipq_thread_start, q, 0);
- return (status < 0) ? status : 0;
-}
-
-
-/****************************************************************************
*
* Packet queue
*
****************************************************************************/
-/* Must be called under spinlock */
-static __inline__ void
-ipq_dequeue(ipq_queue_t *q,
- ipq_queue_element_t *e)
-{
- list_del(&e->list);
- nf_reinject(e->skb, e->info, e->verdict);
- kfree(e);
- q->len--;
-}
-
-/* Must be called under spinlock */
-static __inline__ void
-ipq_queue_drop(ipq_queue_t *q,
- ipq_queue_element_t *e)
+/* Dequeue with element packet ID, or from end of queue if ID is zero. */
+static ipq_queue_element_t *ipq_dequeue(ipq_queue_t *q, unsigned long id)
{
- e->verdict = NF_DROP;
- ipq_dequeue(q, e);
-}
-
-static int
-ipq_notify_peer(ipq_queue_t *q,
- ipq_queue_element_t *e)
-{
- int status = q->peer.send(e);
+ struct list_head *i;
+ ipq_queue_element_t *e = NULL;
- if (status >= 0) {
- e->state = IPQ_PS_WAITING;
- return status;
+ spin_lock_bh(&q->lock);
+ if (q->len == 0)
+ goto out_unlock;
+ i = q->list.prev;
+ if (id > 0) {
+ while (i != &q->list) {
+ if (id == (unsigned long )i)
+ goto out_unlink;
+ i = i->prev;
+ }
+ goto out_unlock;
}
- if (status == -ERESTARTSYS || status == -EAGAIN)
- return 0;
- printk(KERN_INFO "%s: error notifying peer %d, resetting "
- "state and flushing queue\n", IPQ_NAME, q->peer.pid);
- q->state = IPQ_QS_FLUSH;
- q->peer.died = 1;
- q->peer.pid = 0;
- q->peer.copy_mode = IPQ_COPY_META;
- q->peer.copy_range = 0;
- return status;
+out_unlink:
+ e = (ipq_queue_element_t *)i;
+ list_del(&e->list);
+ q->len--;
+out_unlock:
+ spin_unlock_bh(&q->lock);
+ return e;
}
-static void
-ipq_queue_process(void *data)
+static void ipq_flush(ipq_queue_t *q)
{
- struct list_head *i;
- ipq_queue_t *q = (ipq_queue_t *)data;
-
-restart:
- if (q->state == IPQ_QS_HOLD)
- return;
+ ipq_queue_element_t *e;
+
spin_lock_bh(&q->lock);
- for (i = q->list.prev; i != &q->list; i = i->prev) {
- ipq_queue_element_t *e = (ipq_queue_element_t *)i;
-
- if (q->state == IPQ_QS_FLUSH) {
- QDEBUG("flushing packet %p\n", e);
- ipq_queue_drop(q, e);
- continue;
- }
- switch (e->state) {
- case IPQ_PS_NEW: {
- int status = ipq_notify_peer(q, e);
- if (status < 0) {
- spin_unlock_bh(&q->lock);
- goto restart;
- }
- break;
- }
- case IPQ_PS_VERDICT:
- ipq_dequeue(q, e);
- break;
- case IPQ_PS_WAITING:
- break;
- default:
- printk(KERN_INFO "%s: dropping stuck packet %p "
- "with ps=%d qs=%d\n", IPQ_NAME,
- e, e->state, q->state);
- ipq_queue_drop(q, e);
- }
+ q->flushing = 1;
+ spin_unlock_bh(&q->lock);
+ while ((e = ipq_dequeue(q, 0))) {
+ e->verdict = NF_DROP;
+ nf_reinject(e->skb, e->info, e->verdict);
+ kfree(e);
}
+ spin_lock_bh(&q->lock);
+ q->flushing = 0;
spin_unlock_bh(&q->lock);
- if (q->state == IPQ_QS_FLUSH)
- q->state = IPQ_QS_HOLD;
}
-static ipq_queue_t *
-ipq_queue_create(nf_queue_outfn_t outfn,
- ipq_send_cb_t send_cb,
- int *errp,
- int *sysctl_qmax)
+static ipq_queue_t *ipq_create_queue(nf_queue_outfn_t outfn,
+ ipq_send_cb_t send_cb,
+ int *errp, int *sysctl_qmax)
{
int status;
ipq_queue_t *q;
@@ -232,18 +116,15 @@ ipq_queue_create(nf_queue_outfn_t outfn,
*errp = -ENOMEM;
return NULL;
}
- q->thread.terminate = 0;
- q->thread.running = 0;
- q->thread.process = ipq_queue_process;
- init_waitqueue_head(&q->thread.wq);
q->peer.pid = 0;
q->peer.died = 0;
- q->peer.copy_mode = IPQ_COPY_META;
+ q->peer.copy_mode = IPQ_COPY_NONE;
q->peer.copy_range = 0;
q->peer.send = send_cb;
q->len = 0;
q->maxlen = sysctl_qmax;
- q->state = IPQ_QS_HOLD;
+ q->flushing = 0;
+ q->terminate = 0;
INIT_LIST_HEAD(&q->list);
spin_lock_init(&q->lock);
status = nf_register_queue_handler(PF_INET, outfn, q);
@@ -252,91 +133,92 @@ ipq_queue_create(nf_queue_outfn_t outfn,
kfree(q);
return NULL;
}
- status = ipq_thread_create(q);
- if (status < 0) {
- nf_unregister_queue_handler(PF_INET);
- *errp = status;
- kfree(q);
- return NULL;
- }
return q;
}
-static int
-ipq_enqueue(ipq_queue_t *q,
- struct sk_buff *skb,
- struct nf_info *info)
+static int ipq_enqueue(ipq_queue_t *q,
+ struct sk_buff *skb, struct nf_info *info)
{
- ipq_queue_element_t *e = NULL;
-
+ ipq_queue_element_t *e;
+ int status;
+
e = kmalloc(sizeof(*e), GFP_ATOMIC);
if (e == NULL) {
- printk(KERN_ERR "%s: out of memory in %s\n",
- IPQ_NAME, __FUNCTION__);
- return -ENOMEM;
+ printk(KERN_ERR "ip_queue: OOM in enqueue\n");
+ return -ENOMEM;
}
- e->state = IPQ_PS_NEW;
e->verdict = NF_DROP;
e->info = info;
e->skb = skb;
spin_lock_bh(&q->lock);
if (q->len >= *q->maxlen) {
spin_unlock_bh(&q->lock);
- printk(KERN_WARNING "%s: queue full at %d entries, "
- "dropping packet.\n", IPQ_NAME, q->len);
- kfree(e);
- nf_reinject(skb, info, NF_DROP);
- return 0;
+ if (net_ratelimit())
+ printk(KERN_WARNING "ip_queue: full at %d entries, "
+ "dropping packet(s).\n", q->len);
+ goto free_drop;
+ }
+ if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
+ || q->peer.pid == 0 || q->peer.died || q->terminate) {
+ spin_unlock_bh(&q->lock);
+ goto free_drop;
+ }
+ status = q->peer.send(e);
+ if (status > 0) {
+ list_add(&e->list, &q->list);
+ q->len++;
+ spin_unlock_bh(&q->lock);
+ return status;
}
- list_add(&e->list, &q->list);
- q->len++;
spin_unlock_bh(&q->lock);
- wake_up_interruptible(&q->thread.wq);
- return 0;
+ if (status == -ECONNREFUSED) {
+ printk(KERN_INFO "ip_queue: peer %d died, "
+ "resetting state and flushing queue\n", q->peer.pid);
+ q->peer.died = 1;
+ q->peer.pid = 0;
+ q->peer.copy_mode = IPQ_COPY_NONE;
+ q->peer.copy_range = 0;
+ ipq_flush(q);
+ }
+free_drop:
+ kfree(e);
+ return -EBUSY;
}
-/* FIXME: need to find a way to notify user during module unload */
-static void
-ipq_queue_destroy(ipq_queue_t *q)
+static void ipq_destroy_queue(ipq_queue_t *q)
{
- ipq_thread_stop(q);
nf_unregister_queue_handler(PF_INET);
+ spin_lock_bh(&q->lock);
+ q->terminate = 1;
+ spin_unlock_bh(&q->lock);
+ ipq_flush(q);
kfree(q);
}
-static int
-ipq_queue_mangle_ipv4(unsigned char *buf,
- ipq_verdict_msg_t *v,
- ipq_queue_element_t *e)
+static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
{
- struct iphdr *user_iph = (struct iphdr *)buf;
+ struct iphdr *user_iph = (struct iphdr *)v->payload;
if (v->data_len < sizeof(*user_iph))
return 0;
-
if (e->skb->nh.iph->check != user_iph->check) {
int diff = v->data_len - e->skb->len;
if (diff < 0)
skb_trim(e->skb, v->data_len);
else if (diff > 0) {
- if (v->data_len > 0xFFFF) {
- e->verdict = NF_DROP;
+ if (v->data_len > 0xFFFF)
return -EINVAL;
- }
if (diff > skb_tailroom(e->skb)) {
struct sk_buff *newskb;
- /* Ack, we waste a memcpy() of data here */
newskb = skb_copy_expand(e->skb,
skb_headroom(e->skb),
diff,
GFP_ATOMIC);
if (newskb == NULL) {
- printk(KERN_WARNING "%s: OOM in %s, "
- "dropping packet\n",
- IPQ_THR_NAME, __FUNCTION__);
- e->verdict = NF_DROP;
+ printk(KERN_WARNING "ip_queue: OOM "
+ "in mangle, dropping packet\n");
return -ENOMEM;
}
kfree_skb(e->skb);
@@ -344,101 +226,76 @@ ipq_queue_mangle_ipv4(unsigned char *buf,
}
skb_put(e->skb, diff);
}
- memcpy(e->skb->data, buf, v->data_len);
+ memcpy(e->skb->data, v->payload, v->data_len);
e->skb->nfcache |= NFC_ALTERED;
}
return 0;
}
-static int
-ipq_queue_set_verdict(ipq_queue_t *q,
- ipq_verdict_msg_t *v,
- unsigned char *buf,
- unsigned int len)
+static int ipq_set_verdict(ipq_queue_t *q,
+ ipq_verdict_msg_t *v, unsigned int len)
{
- struct list_head *i;
+ ipq_queue_element_t *e;
if (v->value < 0 || v->value > NF_MAX_VERDICT)
return -EINVAL;
- spin_lock_bh(&q->lock);
- for (i = q->list.next; i != &q->list; i = i->next) {
- ipq_queue_element_t *e = (ipq_queue_element_t *)i;
-
- if (v->id == (unsigned long )e) {
- int status = 0;
- e->state = IPQ_PS_VERDICT;
- e->verdict = v->value;
-
- if (buf && v->data_len == len)
- status = ipq_queue_mangle_ipv4(buf, v, e);
- spin_unlock_bh(&q->lock);
- return status;
- }
+ e = ipq_dequeue(q, v->id);
+ if (e == NULL)
+ return -ENOENT;
+ else {
+ e->verdict = v->value;
+ if (v->data_len && v->data_len == len)
+ if (ipq_mangle_ipv4(v, e) < 0)
+ e->verdict = NF_DROP;
+ nf_reinject(e->skb, e->info, e->verdict);
+ kfree(e);
+ return 0;
}
- spin_unlock_bh(&q->lock);
- return -ENOENT;
}
-static int
-ipq_receive_peer(ipq_queue_t *q,
- ipq_peer_msg_t *m,
- unsigned char type,
- unsigned int len)
+static int ipq_receive_peer(ipq_queue_t *q, ipq_peer_msg_t *m,
+ unsigned char type, unsigned int len)
{
- if (q->state == IPQ_QS_FLUSH)
- return -EBUSY;
+ int status = 0;
+
+ spin_lock_bh(&q->lock);
+ if (q->terminate || q->flushing)
+ return -EBUSY;
+ spin_unlock_bh(&q->lock);
if (len < sizeof(ipq_peer_msg_t))
return -EINVAL;
-
switch (type) {
case IPQM_MODE:
switch (m->msg.mode.value) {
- case IPQ_COPY_NONE:
- q->peer.copy_mode = IPQ_COPY_NONE;
- q->peer.copy_range = 0;
- q->state = IPQ_QS_FLUSH;
- break;
case IPQ_COPY_META:
- if (q->state == IPQ_QS_FLUSH)
- return -EAGAIN;
q->peer.copy_mode = IPQ_COPY_META;
q->peer.copy_range = 0;
- q->state = IPQ_QS_COPY;
break;
case IPQ_COPY_PACKET:
- if (q->state == IPQ_QS_FLUSH)
- return -EAGAIN;
q->peer.copy_mode = IPQ_COPY_PACKET;
q->peer.copy_range = m->msg.mode.range;
- q->state = IPQ_QS_COPY;
+ if (q->peer.copy_range > 0xFFFF)
+ q->peer.copy_range = 0xFFFF;
break;
default:
- return -EINVAL;
+ status = -EINVAL;
}
break;
- case IPQM_VERDICT: {
- int status;
- unsigned char *data = NULL;
-
+ case IPQM_VERDICT:
if (m->msg.verdict.value > NF_MAX_VERDICT)
- return -EINVAL;
- if (m->msg.verdict.data_len)
- data = (unsigned char *)m + sizeof(*m);
- status = ipq_queue_set_verdict(q, &m->msg.verdict,
- data, len - sizeof(*m));
- if (status < 0)
- return status;
+ status = -EINVAL;
+ else
+ status = ipq_set_verdict(q,
+ &m->msg.verdict,
+ len - sizeof(*m));
break;
- }
default:
- return -EINVAL;
+ status = -EINVAL;
}
- wake_up_interruptible(&q->thread.wq);
- return 0;
+ return status;
}
-
/****************************************************************************
*
* Netfilter interface
@@ -449,16 +306,10 @@ ipq_receive_peer(ipq_queue_t *q,
* Packets arrive here from netfilter for queuing to userspace.
* All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
*/
-static int
-receive_netfilter(struct sk_buff *skb,
- struct nf_info *info,
- void *data)
+static int netfilter_receive(struct sk_buff *skb,
+ struct nf_info *info, void *data)
{
- ipq_queue_t *q = (ipq_queue_t *)data;
-
- if (q->state == IPQ_QS_FLUSH)
- return -EBUSY;
- return ipq_enqueue(q, skb, info);
+ return ipq_enqueue((ipq_queue_t *)data, skb, info);
}
/****************************************************************************
@@ -467,36 +318,10 @@ receive_netfilter(struct sk_buff *skb,
*
****************************************************************************/
-static struct sk_buff *
-netlink_build_message(ipq_queue_element_t *e,
- int *errp);
-
-extern __inline__ void
-receive_user_skb(struct sk_buff *skb);
-
-static int
-netlink_send_peer(ipq_queue_element_t *e);
-
static struct sock *nfnl = NULL;
ipq_queue_t *nlq = NULL;
-static int
-netlink_send_peer(ipq_queue_element_t *e)
-{
- int status = 0;
- struct sk_buff *skb;
-
- if (!nlq->peer.pid)
- return -EINVAL;
- skb = netlink_build_message(e, &status);
- if (skb == NULL)
- return status;
- return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
-}
-
-static struct sk_buff *
-netlink_build_message(ipq_queue_element_t *e,
- int *errp)
+static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp)
{
unsigned char *old_tail;
size_t size = 0;
@@ -519,6 +344,7 @@ netlink_build_message(ipq_queue_element_t *e,
else
data_len = copy_range;
size = NLMSG_SPACE(sizeof(*pm) + data_len);
+
break;
case IPQ_COPY_NONE:
default:
@@ -542,7 +368,7 @@ netlink_build_message(ipq_queue_element_t *e,
if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
else pm->outdev_name[0] = '\0';
if (data_len)
- memcpy(++pm, e->skb->data, data_len);
+ memcpy(pm->payload, e->skb->data, data_len);
nlh->nlmsg_len = skb->tail - old_tail;
NETLINK_CB(skb).dst_groups = 0;
return skb;
@@ -550,16 +376,24 @@ nlmsg_failure:
if (skb)
kfree(skb);
*errp = 0;
- printk(KERN_ERR "%s: error creating netlink message\n", IPQ_NAME);
+ printk(KERN_ERR "ip_queue: error creating netlink message\n");
return NULL;
}
+static int netlink_send_peer(ipq_queue_element_t *e)
+{
+ int status = 0;
+ struct sk_buff *skb;
+
+ skb = netlink_build_message(e, &status);
+ if (skb == NULL)
+ return status;
+ return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
+}
+
#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
-/*
- * FIXME: ping old peer if we detect a new peer then resend.
- */
-extern __inline__ void
-receive_user_skb(struct sk_buff *skb)
+
+extern __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
{
int status, type;
struct nlmsghdr *nlh;
@@ -581,9 +415,11 @@ receive_user_skb(struct sk_buff *skb)
if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
RCV_SKB_FAIL(-EPERM);
if (nlq->peer.pid && !nlq->peer.died
- && (nlq->peer.pid != nlh->nlmsg_pid))
- printk(KERN_WARNING "%s: peer pid changed from %d to %d\n",
- IPQ_NAME, nlq->peer.pid, nlh->nlmsg_pid);
+ && (nlq->peer.pid != nlh->nlmsg_pid)) {
+ printk(KERN_WARNING "ip_queue: peer pid changed from %d to "
+ "%d, flushing queue\n", nlq->peer.pid, nlh->nlmsg_pid);
+ ipq_flush(nlq);
+ }
nlq->peer.pid = nlh->nlmsg_pid;
nlq->peer.died = 0;
status = ipq_receive_peer(nlq, NLMSG_DATA(nlh),
@@ -596,9 +432,7 @@ receive_user_skb(struct sk_buff *skb)
}
/* Note: we are only dealing with single part messages at the moment. */
-static void
-receive_user_sk(struct sock *sk,
- int len)
+static void netlink_receive_user_sk(struct sock *sk, int len)
{
do {
struct sk_buff *skb;
@@ -606,28 +440,25 @@ receive_user_sk(struct sock *sk,
if (rtnl_shlock_nowait())
return;
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
- receive_user_skb(skb);
+ netlink_receive_user_skb(skb);
kfree_skb(skb);
}
up(&rtnl_sem);
} while (nfnl && nfnl->receive_queue.qlen);
}
-
/****************************************************************************
*
* System events
*
****************************************************************************/
-static int
-receive_event(struct notifier_block *this,
- unsigned long event,
- void *ptr)
+static int receive_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
{
if (event == NETDEV_UNREGISTER)
if (nlq)
- ipq_thread_stop(nlq);
+ ipq_destroy_queue(nlq);
return NOTIFY_DONE;
}
@@ -637,7 +468,6 @@ struct notifier_block ipq_dev_notifier = {
0
};
-
/****************************************************************************
*
* Sysctl - queue tuning.
@@ -670,33 +500,28 @@ static ctl_table ipq_root_table[] = {
*
****************************************************************************/
-static int
-ipq_get_info(char *buffer, char **start, off_t offset, int length)
+static int ipq_get_info(char *buffer, char **start, off_t offset, int length)
{
int len;
spin_lock_bh(&nlq->lock);
len = sprintf(buffer,
- "Thread pid : %d\n"
- "Thread terminate : %d\n"
- "Thread running : %d\n"
- "Peer pid : %d\n"
- "Peer died : %d\n"
- "Peer copy mode : %d\n"
- "Peer copy range : %d\n"
- "Queue length : %d\n"
- "Queue max. length : %d\n"
- "Queue state : %d\n",
- nlq->thread.pid,
- nlq->thread.terminate,
- nlq->thread.running,
+ "Peer pid : %d\n"
+ "Peer died : %d\n"
+ "Peer copy mode : %d\n"
+ "Peer copy range : %d\n"
+ "Queue length : %d\n"
+ "Queue max. length : %d\n"
+ "Queue flushing : %d\n"
+ "Queue terminate : %d\n",
nlq->peer.pid,
nlq->peer.died,
nlq->peer.copy_mode,
nlq->peer.copy_range,
nlq->len,
*nlq->maxlen,
- nlq->state);
+ nlq->flushing,
+ nlq->terminate);
spin_unlock_bh(&nlq->lock);
*start = buffer + offset;
len -= offset;
@@ -716,18 +541,18 @@ ipq_get_info(char *buffer, char **start, off_t offset, int length)
static int __init init(void)
{
int status = 0;
-
- nfnl = netlink_kernel_create(NETLINK_FIREWALL, receive_user_sk);
+
+ nfnl = netlink_kernel_create(NETLINK_FIREWALL, netlink_receive_user_sk);
if (nfnl == NULL) {
- printk(KERN_ERR "%s: initialisation failed: unable to "
- "create kernel netlink socket\n", IPQ_NAME);
+ printk(KERN_ERR "ip_queue: initialisation failed: unable to "
+ "create kernel netlink socket\n");
return -ENOMEM;
}
- nlq = ipq_queue_create(receive_netfilter,
+ nlq = ipq_create_queue(netfilter_receive,
netlink_send_peer, &status, &sysctl_maxlen);
if (nlq == NULL) {
- printk(KERN_ERR "%s: initialisation failed: unable to "
- "initialise queue\n", IPQ_NAME);
+ printk(KERN_ERR "ip_queue: initialisation failed: unable to "
+ "create queue\n");
sock_release(nfnl->socket);
return status;
}
@@ -742,7 +567,7 @@ static void __exit fini(void)
unregister_sysctl_table(ipq_sysctl_header);
proc_net_remove(IPQ_PROC_FS_NAME);
unregister_netdevice_notifier(&ipq_dev_notifier);
- ipq_queue_destroy(nlq);
+ ipq_destroy_queue(nlq);
sock_release(nfnl->socket);
}
@@ -750,3 +575,4 @@ MODULE_DESCRIPTION("IPv4 packet queue handler");
module_init(init);
module_exit(fini);
+
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 8cc8c24ac..66f47c386 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -12,15 +12,13 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
+#include <net/ip.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
+#include <linux/proc_fs.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-#ifndef IP_OFFSET
-#define IP_OFFSET 0x1FFF
-#endif
-
/*#define DEBUG_IP_FIREWALL*/
/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
/*#define DEBUG_IP_FIREWALL_USER*/
@@ -288,9 +286,16 @@ ipt_do_table(struct sk_buff **pskb,
+ TABLE_OFFSET(table->private, smp_processor_id());
e = get_entry(table_base, table->private->hook_entry[hook]);
- /* Check noone else using our table */
- IP_NF_ASSERT(((struct ipt_entry *)table_base)->comefrom == 0xdead57ac);
#ifdef CONFIG_NETFILTER_DEBUG
+ /* Check noone else using our table */
+ if (((struct ipt_entry *)table_base)->comefrom != 0xdead57ac
+ && ((struct ipt_entry *)table_base)->comefrom != 0xeeeeeeec) {
+ printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
+ smp_processor_id(),
+ table->name,
+ &((struct ipt_entry *)table_base)->comefrom,
+ ((struct ipt_entry *)table_base)->comefrom);
+ }
((struct ipt_entry *)table_base)->comefrom = 0x57acc001;
#endif
@@ -343,11 +348,28 @@ ipt_do_table(struct sk_buff **pskb,
e = get_entry(table_base, v);
} else {
+ /* Targets which reenter must return
+ abs. verdicts */
+#ifdef CONFIG_NETFILTER_DEBUG
+ ((struct ipt_entry *)table_base)->comefrom
+ = 0xeeeeeeec;
+#endif
verdict = t->u.target->target(pskb, hook,
in, out,
t->data,
userdata);
+#ifdef CONFIG_NETFILTER_DEBUG
+ if (((struct ipt_entry *)table_base)->comefrom
+ != 0xeeeeeeec
+ && verdict == IPT_CONTINUE) {
+ printk("Target %s reentered!\n",
+ t->u.target->name);
+ verdict = NF_DROP;
+ }
+ ((struct ipt_entry *)table_base)->comefrom
+ = 0x57acc001;
+#endif
/* Target might have changed stuff. */
ip = (*pskb)->nh.iph;
protohdr = (u_int32_t *)ip + ip->ihl;
@@ -1631,6 +1653,43 @@ static struct ipt_match udp_matchstruct
static struct ipt_match icmp_matchstruct
= { { NULL, NULL }, "icmp", &icmp_match, &icmp_checkentry, NULL };
+#ifdef CONFIG_PROC_FS
+static inline int print_name(const struct ipt_table *t,
+ off_t start_offset, char *buffer, int length,
+ off_t *pos, unsigned int *count)
+{
+ if ((*count)++ >= start_offset) {
+ unsigned int namelen;
+
+ namelen = sprintf(buffer + *pos, "%s\n", t->name);
+ if (*pos + namelen > length) {
+ /* Stop iterating */
+ return 1;
+ }
+ *pos += namelen;
+ }
+ return 0;
+}
+
+static int ipt_get_tables(char *buffer, char **start, off_t offset, int length)
+{
+ off_t pos = 0;
+ unsigned int count = 0;
+
+ if (down_interruptible(&ipt_mutex) != 0)
+ return 0;
+
+ LIST_FIND(&ipt_tables, print_name, struct ipt_table *,
+ offset, buffer, length, &pos, &count);
+
+ up(&ipt_mutex);
+
+ /* `start' hack - see fs/proc/generic.c line ~105 */
+ *start=(char *)((unsigned long)count-offset);
+ return pos;
+}
+#endif /*CONFIG_PROC_FS*/
+
static int __init init(void)
{
int ret;
@@ -1651,13 +1710,23 @@ static int __init init(void)
return ret;
}
- printk("iptables: (c)2000 Netfilter core team\n");
+#ifdef CONFIG_PROC_FS
+ if (!proc_net_create("ip_tables_names", 0, ipt_get_tables)) {
+ nf_unregister_sockopt(&ipt_sockopts);
+ return -ENOMEM;
+ }
+#endif
+
+ printk("ip_tables: (c)2000 Netfilter core team\n");
return 0;
}
static void __exit fini(void)
{
nf_unregister_sockopt(&ipt_sockopts);
+#ifdef CONFIG_PROC_FS
+ proc_net_remove("ip_tables_names");
+#endif
}
module_init(init);
diff --git a/net/ipv4/netfilter/ipchains_core.c b/net/ipv4/netfilter/ipchains_core.c
index 02bd7ad83..419b0382c 100644
--- a/net/ipv4/netfilter/ipchains_core.c
+++ b/net/ipv4/netfilter/ipchains_core.c
@@ -145,7 +145,9 @@
/*#define DEBUG_IP_FIREWALL_USER*/
/*#define DEBUG_IP_FIREWALL_LOCKING*/
+#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
static struct sock *ipfwsk;
+#endif
#ifdef CONFIG_SMP
#define SLOT_NUMBER() (cpu_number_map(smp_processor_id())*2 + !in_interrupt())
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 6e69d6a90..4675a94b8 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -24,10 +24,6 @@ struct esphdr {
__u32 spi;
}; /* FIXME evil kludge */
-/* Make init and cleanup non-static, so gcc doesn't warn about unused,
- but don't export the symbols */
-EXPORT_NO_SYMBOLS;
-
/* Use lock to serialize, so printks don't overlap */
static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
@@ -353,15 +349,15 @@ static struct ipt_target ipt_log_reg
static int __init init(void)
{
- if (ipt_register_target(&ipt_log_reg))
- return -EINVAL;
+ if (ipt_register_target(&ipt_log_reg))
+ return -EINVAL;
- return 0;
+ return 0;
}
static void __exit fini(void)
{
- ipt_unregister_target(&ipt_log_reg);
+ ipt_unregister_target(&ipt_log_reg);
}
module_init(init);
diff --git a/net/ipv4/netfilter/ipt_MARK.c b/net/ipv4/netfilter/ipt_MARK.c
index 32906eefe..924e00e5c 100644
--- a/net/ipv4/netfilter/ipt_MARK.c
+++ b/net/ipv4/netfilter/ipt_MARK.c
@@ -7,8 +7,6 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_MARK.h>
-EXPORT_NO_SYMBOLS;
-
static unsigned int
target(struct sk_buff **pskb,
unsigned int hooknum,
@@ -53,15 +51,15 @@ static struct ipt_target ipt_mark_reg
static int __init init(void)
{
- if (ipt_register_target(&ipt_mark_reg))
- return -EINVAL;
+ if (ipt_register_target(&ipt_mark_reg))
+ return -EINVAL;
- return 0;
+ return 0;
}
static void __exit fini(void)
{
- ipt_unregister_target(&ipt_mark_reg);
+ ipt_unregister_target(&ipt_mark_reg);
}
module_init(init);
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 9f94f8f44..071e2c3cd 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -11,8 +11,6 @@
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-EXPORT_NO_SYMBOLS;
-
#if 0
#define DEBUGP printk
#else
diff --git a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c
index 9dec181c1..dba913387 100644
--- a/net/ipv4/netfilter/ipt_MIRROR.c
+++ b/net/ipv4/netfilter/ipt_MIRROR.c
@@ -29,7 +29,6 @@
#include <linux/route.h>
struct in_device;
#include <net/route.h>
-EXPORT_NO_SYMBOLS;
#if 0
#define DEBUGP printk
@@ -49,7 +48,7 @@ static int route_mirror(struct sk_buff *skb)
}
/* check if the interface we are living by is the same as the one we arrived on */
- if (skb->rx_dev != rt->u.dst.dev) {
+ if (skb->rx_dev == rt->u.dst.dev) {
/* Drop old route. */
dst_release(skb->dst);
skb->dst = &rt->u.dst;
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 690d3a8a1..aa7ac5e5d 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -12,8 +12,6 @@
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_nat_rule.h>
-EXPORT_NO_SYMBOLS;
-
#if 0
#define DEBUGP printk
#else
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index b183e822c..7e82c908c 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -6,12 +6,11 @@
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/icmp.h>
-#include <net/tcp.h>
+#include <net/ip.h>
struct in_device;
#include <net/route.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>
-EXPORT_NO_SYMBOLS;
#if 0
#define DEBUGP printk
@@ -28,6 +27,9 @@ static unsigned int reject(struct sk_buff **pskb,
{
const struct ipt_reject_info *reject = targinfo;
+ /* WARNING: This code has causes reentry within iptables.
+ This means that the iptables jump stack is now crap. We
+ must return an absolute verdict. --RR */
switch (reject->with) {
case IPT_ICMP_NET_UNREACHABLE:
icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0);
@@ -62,9 +64,6 @@ static unsigned int reject(struct sk_buff **pskb,
}
}
break;
- case IPT_TCP_RESET:
- tcp_v4_send_reset(*pskb);
- break;
}
return NF_DROP;
@@ -115,12 +114,6 @@ static int check(const char *tablename,
DEBUGP("REJECT: ECHOREPLY illegal for non-ping\n");
return 0;
}
- } else if (rejinfo->with == IPT_TCP_RESET) {
- if (e->ip.proto != IPPROTO_TCP
- || (e->ip.invflags & IPT_INV_PROTO)) {
- DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
- return 0;
- }
}
return 1;
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index fbfb4974f..f0c293868 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -7,8 +7,6 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_TOS.h>
-EXPORT_NO_SYMBOLS;
-
static unsigned int
target(struct sk_buff **pskb,
unsigned int hooknum,
@@ -72,15 +70,15 @@ static struct ipt_target ipt_tos_reg
static int __init init(void)
{
- if (ipt_register_target(&ipt_tos_reg))
- return -EINVAL;
+ if (ipt_register_target(&ipt_tos_reg))
+ return -EINVAL;
- return 0;
+ return 0;
}
static void __exit fini(void)
{
- ipt_unregister_target(&ipt_tos_reg);
+ ipt_unregister_target(&ipt_tos_reg);
}
module_init(init);
diff --git a/net/ipv4/netfilter/ipt_limit.c b/net/ipv4/netfilter/ipt_limit.c
index 3785ba371..5e2b86029 100644
--- a/net/ipv4/netfilter/ipt_limit.c
+++ b/net/ipv4/netfilter/ipt_limit.c
@@ -14,7 +14,6 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_limit.h>
-EXPORT_NO_SYMBOLS;
#define IP_PARTS_NATIVE(n) \
(unsigned int)((n)>>24)&0xFF, \
diff --git a/net/ipv4/netfilter/ipt_mac.c b/net/ipv4/netfilter/ipt_mac.c
index 90dbec59d..7de798767 100644
--- a/net/ipv4/netfilter/ipt_mac.c
+++ b/net/ipv4/netfilter/ipt_mac.c
@@ -5,7 +5,6 @@
#include <linux/netfilter_ipv4/ipt_mac.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-EXPORT_NO_SYMBOLS;
static int
match(const struct sk_buff *skb,
diff --git a/net/ipv4/netfilter/ipt_mark.c b/net/ipv4/netfilter/ipt_mark.c
index 0d828fd20..66c3d1186 100644
--- a/net/ipv4/netfilter/ipt_mark.c
+++ b/net/ipv4/netfilter/ipt_mark.c
@@ -5,8 +5,6 @@
#include <linux/netfilter_ipv4/ipt_mark.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-EXPORT_NO_SYMBOLS;
-
static int
match(const struct sk_buff *skb,
const struct net_device *in,
diff --git a/net/ipv4/netfilter/ipt_multiport.c b/net/ipv4/netfilter/ipt_multiport.c
index 08cc4a968..6170ce65e 100644
--- a/net/ipv4/netfilter/ipt_multiport.c
+++ b/net/ipv4/netfilter/ipt_multiport.c
@@ -14,8 +14,6 @@
#define duprintf(format, args...)
#endif
-EXPORT_NO_SYMBOLS;
-
/* Returns 1 if the port is matched by the test, 0 otherwise. */
static inline int
ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags,
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
index 5438571d3..501916414 100644
--- a/net/ipv4/netfilter/ipt_owner.c
+++ b/net/ipv4/netfilter/ipt_owner.c
@@ -1,7 +1,7 @@
/* Kernel module to match various things tied to sockets associated with
locally generated outgoing packets.
- (C)2000 Marc Boucher
+ Copyright (C) 2000 Marc Boucher
*/
#include <linux/module.h>
#include <linux/skbuff.h>
@@ -11,8 +11,6 @@
#include <linux/netfilter_ipv4/ipt_owner.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-EXPORT_NO_SYMBOLS;
-
static int
match_pid(const struct sk_buff *skb, pid_t pid)
{
diff --git a/net/ipv4/netfilter/ipt_state.c b/net/ipv4/netfilter/ipt_state.c
index 1baa54d62..b559e7f56 100644
--- a/net/ipv4/netfilter/ipt_state.c
+++ b/net/ipv4/netfilter/ipt_state.c
@@ -6,7 +6,6 @@
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_state.h>
-EXPORT_NO_SYMBOLS;
static int
match(const struct sk_buff *skb,
@@ -47,14 +46,17 @@ static struct ipt_match state_match
static int __init init(void)
{
- __MOD_INC_USE_COUNT(ip_conntrack_module);
+ /* NULL if ip_conntrack not a module */
+ if (ip_conntrack_module)
+ __MOD_INC_USE_COUNT(ip_conntrack_module);
return ipt_register_match(&state_match);
}
static void __exit fini(void)
{
ipt_unregister_match(&state_match);
- __MOD_DEC_USE_COUNT(ip_conntrack_module);
+ if (ip_conntrack_module)
+ __MOD_DEC_USE_COUNT(ip_conntrack_module);
}
module_init(init);
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index 6da72b2d8..b144704e4 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -5,8 +5,6 @@
#include <linux/netfilter_ipv4/ipt_tos.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-EXPORT_NO_SYMBOLS;
-
static int
match(const struct sk_buff *skb,
const struct net_device *in,
diff --git a/net/ipv4/netfilter/ipt_unclean.c b/net/ipv4/netfilter/ipt_unclean.c
index 056224a87..72fab2b18 100644
--- a/net/ipv4/netfilter/ipt_unclean.c
+++ b/net/ipv4/netfilter/ipt_unclean.c
@@ -9,8 +9,6 @@
#include <linux/netfilter_ipv4/ip_tables.h>
-EXPORT_NO_SYMBOLS;
-
#define limpk(format, args...) \
do { \
if (net_ratelimit()) \
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 471eb9e70..098d91ba1 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.165 2000/03/23 05:30:32 davem Exp $
+ * Version: $Id: tcp.c,v 1.166 2000/03/25 01:55:11 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -445,12 +445,6 @@ static __inline__ unsigned int tcp_listen_poll(struct sock *sk, poll_table *wait
}
/*
- * Compute minimal free write space needed to queue new packets.
- */
-#define tcp_min_write_space(__sk) \
- (atomic_read(&(__sk)->wmem_alloc) / 2)
-
-/*
* Wait for a TCP event.
*
* Note that we don't need to lock the socket, as the upper poll layers
@@ -520,7 +514,15 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
if (sock_wspace(sk) >= tcp_min_write_space(sk)) {
mask |= POLLOUT | POLLWRNORM;
} else { /* send SIGIO later */
- sk->socket->flags |= SO_NOSPACE;
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+ set_bit(SOCK_NOSPACE, &sk->socket->flags);
+
+ /* Race breaker. If space is freed after
+ * wspace test but before the flags are set,
+ * IO signal will be lost.
+ */
+ if (sock_wspace(sk) >= tcp_min_write_space(sk))
+ mask |= POLLOUT | POLLWRNORM;
}
}
@@ -534,18 +536,26 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
* Socket write_space callback.
* This (or rather the sock_wake_async) should agree with poll.
*
- * WARNING. This callback is called from any context (process,
- * bh or irq). Do not make anything more smart from it.
+ * WARNING. This callback is called, when socket is not locked.
+ *
+ * This wakeup is used by TCP only as dead-lock breaker, real
+ * wakeup occurs when incoming ack frees some space in buffer.
*/
void tcp_write_space(struct sock *sk)
{
+ struct socket *sock;
+
read_lock(&sk->callback_lock);
- if (!sk->dead) {
- /* Why??!! Does it really not overshedule? --ANK */
- wake_up_interruptible(sk->sleep);
+ if ((sock = sk->socket) != NULL && atomic_read(&sk->wmem_alloc) == 0) {
+ if (test_bit(SOCK_NOSPACE, &sock->flags)) {
+ if (sk->sleep && waitqueue_active(sk->sleep)) {
+ clear_bit(SOCK_NOSPACE, &sock->flags);
+ wake_up_interruptible(sk->sleep);
+ }
+ }
- if (sock_wspace(sk) >= tcp_min_write_space(sk))
- sock_wake_async(sk->socket, 2, POLL_OUT);
+ if (sock->fasync_list)
+ sock_wake_async(sock, 2, POLL_OUT);
}
read_unlock(&sk->callback_lock);
}
@@ -636,7 +646,6 @@ int tcp_listen_start(struct sock *sk)
sk->write_space = tcp_listen_write_space;
sk_dst_reset(sk);
sk->prot->hash(sk);
- sk->socket->flags |= SO_ACCEPTCON;
return 0;
}
@@ -742,7 +751,7 @@ static int wait_for_tcp_connect(struct sock * sk, int flags, long *timeo_p)
if(!*timeo_p)
return -EAGAIN;
if(signal_pending(tsk))
- return -ERESTARTSYS;
+ return sock_intr_errno(*timeo_p);
__set_task_state(tsk, TASK_INTERRUPTIBLE);
add_wait_queue(sk->sleep, &wait);
@@ -772,9 +781,12 @@ static long wait_for_tcp_memory(struct sock * sk, long timeo)
if (!tcp_memory_free(sk)) {
DECLARE_WAITQUEUE(wait, current);
- sk->socket->flags &= ~SO_NOSPACE;
+ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+
add_wait_queue(sk->sleep, &wait);
for (;;) {
+ set_bit(SOCK_NOSPACE, &sk->socket->flags);
+
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current))
@@ -830,7 +842,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
goto out_unlock;
/* This should be in poll */
- sk->socket->flags &= ~SO_NOSPACE; /* clear SIGIO XXX */
+ clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
mss_now = tcp_current_mss(sk);
@@ -943,13 +955,15 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
/* If we didn't get any memory, we need to sleep. */
if (skb == NULL) {
- sk->socket->flags |= SO_NOSPACE;
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+ set_bit(SOCK_NOSPACE, &sk->socket->flags);
+
if (!timeo) {
err = -EAGAIN;
goto do_interrupted;
}
if (signal_pending(current)) {
- err = -ERESTARTSYS;
+ err = sock_intr_errno(timeo);
goto do_interrupted;
}
__tcp_push_pending_frames(sk, tp, mss_now);
@@ -1062,7 +1076,8 @@ static int tcp_recv_urg(struct sock * sk, long timeo,
msg->msg_flags|=MSG_OOB;
if(len>0) {
- err = memcpy_toiovec(msg->msg_iov, &c, 1);
+ if (!(flags & MSG_PEEK))
+ err = memcpy_toiovec(msg->msg_iov, &c, 1);
len = 1;
} else
msg->msg_flags|=MSG_TRUNC;
@@ -1188,14 +1203,14 @@ static long tcp_data_wait(struct sock *sk, long timeo)
__set_current_state(TASK_INTERRUPTIBLE);
- sk->socket->flags |= SO_WAITDATA;
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
release_sock(sk);
if (skb_queue_empty(&sk->receive_queue))
timeo = schedule_timeout(timeo);
lock_sock(sk);
- sk->socket->flags &= ~SO_WAITDATA;
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
remove_wait_queue(sk->sleep, &wait);
__set_current_state(TASK_RUNNING);
@@ -1287,9 +1302,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
if (signal_pending(current)) {
if (copied)
break;
- copied = -ERESTARTSYS;
- if (!timeo)
- copied = -EAGAIN;
+ copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
break;
}
@@ -1362,7 +1375,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
if (tp->ucopy.task == user_recv) {
/* Install new reader */
- if (user_recv == NULL && !(flags&MSG_PEEK)) {
+ if (user_recv == NULL && !(flags&(MSG_TRUNC|MSG_PEEK))) {
user_recv = current;
tp->ucopy.task = user_recv;
tp->ucopy.iov = msg->msg_iov;
@@ -1370,7 +1383,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
tp->ucopy.len = len;
- BUG_TRAP(tp->copied_seq == tp->rcv_nxt || (flags&MSG_PEEK));
+ BUG_TRAP(tp->copied_seq == tp->rcv_nxt || (flags&(MSG_PEEK|MSG_TRUNC)));
/* Ugly... If prequeue is not empty, we have to
* process it before releasing socket, otherwise
@@ -1458,12 +1471,15 @@ do_prequeue:
}
}
- err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
- if (err) {
- /* Exception. Bailout! */
- if (!copied)
- copied = -EFAULT;
- break;
+ err = 0;
+ if (!(flags&MSG_TRUNC)) {
+ err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
+ if (err) {
+ /* Exception. Bailout! */
+ if (!copied)
+ copied = -EFAULT;
+ break;
+ }
}
*seq += used;
@@ -1961,7 +1977,7 @@ static int wait_for_connect(struct sock * sk, long timeo)
err = -EINVAL;
if (sk->state != TCP_LISTEN)
break;
- err = -ERESTARTSYS;
+ err = sock_intr_errno(timeo);
if (signal_pending(current))
break;
err = -EAGAIN;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 575ec3036..3ba12bc52 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.190 2000/03/21 19:34:23 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.191 2000/03/25 01:55:13 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1181,6 +1181,9 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
if (ack != tp->snd_una || (flag == 0 && !th->fin))
dst_confirm(sk->dst_cache);
+ if (ack != tp->snd_una)
+ tp->sorry = 1;
+
/* Remember the highest ack received. */
tp->snd_una = ack;
return 1;
@@ -1614,7 +1617,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
tp->fin_seq = TCP_SKB_CB(skb)->end_seq;
- tcp_send_ack(sk);
+ tp->ack.pending = 1;
sk->shutdown |= RCV_SHUTDOWN;
@@ -1644,6 +1647,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
break;
case TCP_FIN_WAIT2:
/* Received a FIN -- send ACK and enter TIME_WAIT. */
+ tcp_send_ack(sk);
tcp_time_wait(sk, TCP_TIME_WAIT, 0);
break;
default:
@@ -1944,7 +1948,7 @@ queue_and_out:
if (eaten) {
kfree_skb(skb);
- } else
+ } else if (!sk->dead)
sk->data_ready(sk, 0);
return;
}
@@ -2074,6 +2078,30 @@ drop:
kfree_skb(skb);
}
+/* When incoming ACK allowed to free some skb from write_queue,
+ * we remember this in flag tp->sorry and wake up socket on the exit
+ * from tcp input handler. Probably, handler has already eat this space
+ * sending ACK and cloned frames from tcp_write_xmit().
+ */
+static __inline__ void tcp_new_space(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct socket *sock;
+
+ tp->sorry = 0;
+
+ if (sock_wspace(sk) >= tcp_min_write_space(sk) &&
+ (sock = sk->socket) != NULL) {
+ clear_bit(SOCK_NOSPACE, &sock->flags);
+
+ if (sk->sleep && waitqueue_active(sk->sleep))
+ wake_up_interruptible(sk->sleep);
+
+ if (sock->fasync_list)
+ sock_wake_async(sock, 2, POLL_OUT);
+ }
+}
+
static void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
@@ -2114,7 +2142,14 @@ static __inline__ void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
*/
/* More than one full frame received or... */
- if (((tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss) ||
+ if (((tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss
+#ifdef TCP_MORE_COARSE_ACKS
+ /* Avoid to send immediate ACK from input path, if it
+ * does not advance window far enough. tcp_recvmsg() will do this.
+ */
+ && (!sysctl_tcp_retrans_collapse || __tcp_select_window(sk) >= tp->rcv_wnd)
+#endif
+ ) ||
/* We ACK each frame or... */
tcp_in_quickack_mode(tp) ||
/* We have out of order data or */
@@ -2480,6 +2515,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
TCP_SKB_CB(skb)->ack_seq, len);
kfree_skb(skb);
tcp_data_snd_check(sk);
+ if (tp->sorry)
+ tcp_new_space(sk);
return 0;
} else { /* Header too small */
TCP_INC_STATS_BH(TcpInErrs);
@@ -2633,6 +2670,8 @@ step5:
if(sk->state != TCP_CLOSE) {
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
+ if (tp->sorry)
+ tcp_new_space(sk);
}
return 0;
@@ -2739,6 +2778,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
newtp->saw_tstamp = 0;
newtp->probes_out = 0;
+ newtp->num_sacks = 0;
newtp->syn_seq = req->rcv_isn;
newtp->fin_seq = req->rcv_isn;
newtp->urg_data = 0;
@@ -3112,6 +3152,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
tcp_sync_mss(sk, tp->pmtu_cookie);
tcp_initialize_rcv_mss(sk);
tcp_init_metrics(sk);
+ tcp_init_buffer_space(sk);
if (sk->keepopen)
tcp_reset_keepalive_timer(sk, keepalive_time_when(tp));
@@ -3516,6 +3557,8 @@ step6:
if (sk->state != TCP_CLOSE) {
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
+ if (tp->sorry)
+ tcp_new_space(sk);
}
if (!queued) {
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 456f12968..3c9f4e82b 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.203 2000/03/22 17:55:03 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.205 2000/03/26 09:16:08 davem Exp $
*
* IPv4 specific functions
*
@@ -1039,7 +1039,6 @@ out:
void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
struct sk_buff *skb)
{
- th->check = 0;
th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr,
csum_partial((char *)th, th->doff<<2, skb->csum));
}
@@ -1057,7 +1056,7 @@ void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
* Exception: precedence violation. We do not implement it in any case.
*/
-void tcp_v4_send_reset(struct sk_buff *skb)
+static void tcp_v4_send_reset(struct sk_buff *skb)
{
struct tcphdr *th = skb->h.th;
struct tcphdr rth;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 887aaa519..600140764 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.122 2000/02/21 15:51:41 davem Exp $
+ * Version: $Id: tcp_output.c,v 1.123 2000/03/25 01:52:05 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -126,7 +126,7 @@ int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
#define SYSCTL_FLAG_SACK 0x4
sysctl_flags = 0;
- if(tcb->flags & TCPCB_FLAG_SYN) {
+ if (tcb->flags & TCPCB_FLAG_SYN) {
tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS;
if(sysctl_tcp_timestamps) {
tcp_header_size += TCPOLEN_TSTAMP_ALIGNED;
@@ -141,7 +141,7 @@ int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
if(!(sysctl_flags & SYSCTL_FLAG_TSTAMPS))
tcp_header_size += TCPOLEN_SACKPERM_ALIGNED;
}
- } else if(tp->sack_ok && tp->num_sacks) {
+ } else if (tp->num_sacks) {
/* A SACK is 2 pad bytes, a 2 byte header, plus
* 2 32-bit sequence numbers for each SACK block.
*/
@@ -157,16 +157,19 @@ int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
th->dest = sk->dport;
th->seq = htonl(TCP_SKB_CB(skb)->seq);
th->ack_seq = htonl(tp->rcv_nxt);
- th->doff = (tcp_header_size >> 2);
- th->res1 = 0;
- *(((__u8 *)th) + 13) = tcb->flags;
- th->check = 0;
- th->urg_ptr = ntohs(tcb->urg_ptr);
- if(tcb->flags & TCPCB_FLAG_SYN) {
+ *(((__u16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | tcb->flags);
+ if (tcb->flags & TCPCB_FLAG_SYN) {
/* RFC1323: The window in SYN & SYN/ACK segments
* is never scaled.
*/
th->window = htons(tp->rcv_wnd);
+ } else {
+ th->window = htons(tcp_select_window(sk));
+ }
+ th->check = 0;
+ th->urg_ptr = ntohs(tcb->urg_ptr);
+
+ if (tcb->flags & TCPCB_FLAG_SYN) {
tcp_syn_build_options((__u32 *)(th + 1),
tcp_advertise_mss(sk),
(sysctl_flags & SYSCTL_FLAG_TSTAMPS),
@@ -176,13 +179,12 @@ int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
TCP_SKB_CB(skb)->when,
tp->ts_recent);
} else {
- th->window = htons(tcp_select_window(sk));
tcp_build_and_update_options((__u32 *)(th + 1),
tp, TCP_SKB_CB(skb)->when);
}
tp->af_specific->send_check(sk, th, skb->len, skb);
- if (th->ack)
+ if (tcb->flags & TCPCB_FLAG_ACK)
tcp_event_ack_sent(sk);
if (skb->len != tcp_header_size)
@@ -1097,10 +1099,26 @@ err_out:
void tcp_send_delayed_ack(struct sock *sk)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ long ato = tp->ack.ato;
unsigned long timeout;
+ if (ato > TCP_DELACK_MIN) {
+ int max_ato;
+
+ /* If some rtt estimate is known, use it to bound delayed ack.
+ * Do not use tp->rto here, use results of rtt measurements
+ * directly.
+ */
+ if (tp->srtt)
+ max_ato = (tp->srtt >> 3) + tp->mdev;
+ else
+ max_ato = TCP_DELACK_MAX;
+
+ ato = min(ato, max_ato);
+ }
+
/* Stay within the limit we were given */
- timeout = jiffies + tp->ack.ato;
+ timeout = jiffies + ato;
/* Use new timeout only if there wasn't a older one earlier. */
spin_lock_bh(&sk->timer_lock);
@@ -1111,7 +1129,7 @@ void tcp_send_delayed_ack(struct sock *sk)
/* If delack timer was blocked or is about to expire,
* send ACK now.
*/
- if (tp->ack.blocked || time_before_eq(tp->delack_timer.expires, jiffies+(tp->ack.ato>>2))) {
+ if (tp->ack.blocked || time_before_eq(tp->delack_timer.expires, jiffies+(ato>>2))) {
spin_unlock_bh(&sk->timer_lock);
tcp_send_ack(sk);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index ffb0787e8..41ce4b997 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.27 2000/02/22 23:54:28 davem Exp $
+ * $Id: icmp.c,v 1.28 2000/03/25 01:55:20 davem Exp $
*
* Based on net/ipv4/icmp.c
*
@@ -660,6 +660,7 @@ int __init icmpv6_init(struct net_proto_family *ops)
sk = icmpv6_socket->sk;
sk->allocation = GFP_ATOMIC;
+ sk->sndbuf = SK_WMEM_MAX*2;
sk->prot->unhash(sk);
inet6_add_protocol(&icmpv6_protocol);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index b0e8ee714..c6fd03355 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.121 2000/03/08 19:36:47 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.122 2000/03/25 01:52:11 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -910,7 +910,6 @@ static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len,
struct sk_buff *skb)
{
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
- th->check = 0;
th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
csum_partial((char *)th, th->doff<<2,
diff --git a/net/ipx/af_spx.c b/net/ipx/af_spx.c
index 9f52dfe4e..1eb7a725c 100644
--- a/net/ipx/af_spx.c
+++ b/net/ipx/af_spx.c
@@ -89,7 +89,7 @@ static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, p
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
- sk->socket->flags |= SO_NOSPACE;
+ set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
return mask;
}
@@ -231,7 +231,7 @@ static int spx_listen(struct socket *sock, int backlog)
sk->ack_backlog = 0;
sk->state = TCP_LISTEN;
}
- sk->socket->flags |= SO_ACCEPTCON;
+ sk->socket->flags |= __SO_ACCEPTCON;
return (0);
}
@@ -248,7 +248,7 @@ static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
return (-EINVAL);
sk = sock->sk;
- if((sock->state != SS_UNCONNECTED) || !(sock->flags & SO_ACCEPTCON))
+ if((sock->state != SS_UNCONNECTED) || !(sock->flags & __SO_ACCEPTCON))
return (-EINVAL);
if(sock->type != SOCK_SEQPACKET)
return (-EOPNOTSUPP);
diff --git a/net/khttpd/security.c b/net/khttpd/security.c
index 7e0780a26..16503ceb5 100644
--- a/net/khttpd/security.c
+++ b/net/khttpd/security.c
@@ -115,14 +115,12 @@ struct file *OpenFileForSecurity(char *Filename)
lock_kernel();
- filp = filp_open(Filename, 0, O_RDONLY, NULL);
+ filp = filp_open(Filename, O_RDONLY, 0);
unlock_kernel();
- if ((IS_ERR(filp))||(filp==NULL)||(filp->f_dentry==NULL))
- {
+ if (IS_ERR(filp))
return NULL;
- }
#ifndef BENCHMARK
permission = filp->f_dentry->d_inode->i_mode;
diff --git a/net/khttpd/sockets.c b/net/khttpd/sockets.c
index 60e66fdf8..74bfe614d 100644
--- a/net/khttpd/sockets.c
+++ b/net/khttpd/sockets.c
@@ -79,7 +79,6 @@ int StartListening(const int Port)
error=sock->ops->listen(sock,48);
if (error!=0)
(void)printk(KERN_ERR "kHTTPd: Error listening on socket \n");
- sock->flags |= SO_ACCEPTCON;
MainSocket = sock;
diff --git a/net/khttpd/waitheaders.c b/net/khttpd/waitheaders.c
index 47fa1581d..2c24f3744 100644
--- a/net/khttpd/waitheaders.c
+++ b/net/khttpd/waitheaders.c
@@ -239,7 +239,6 @@ static int DecodeHeader(const int CPUNR, struct http_request *Request)
return 0;
}
else
- if ((Request->filp->f_dentry!=NULL)&&(Request->filp->f_dentry->d_inode!=NULL))
{
Request->FileLength = (int)Request->filp->f_dentry->d_inode->i_size;
Request->Time = Request->filp->f_dentry->d_inode->i_mtime;
@@ -262,12 +261,6 @@ static int DecodeHeader(const int CPUNR, struct http_request *Request)
}
- } else
- {
- /* Ehhh... */
-
- printk(KERN_CRIT "kHTTPd: Unexpected filesystem response\n");
- return -1;
}
LeaveFunction("DecodeHeader");
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 0136d15c2..b76a07274 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -436,7 +436,7 @@ retry:
if (signal_pending(current)) {
kfree_skb(skb);
- return -ERESTARTSYS;
+ return sock_intr_errno(timeo);
}
goto retry;
}
diff --git a/net/netsyms.c b/net/netsyms.c
index c6745cafe..9a7030d7e 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -340,7 +340,6 @@ EXPORT_SYMBOL(tcp_sendmsg);
EXPORT_SYMBOL(tcp_v4_rebuild_header);
EXPORT_SYMBOL(tcp_v4_send_check);
EXPORT_SYMBOL(tcp_v4_conn_request);
-EXPORT_SYMBOL(tcp_v4_send_reset);
EXPORT_SYMBOL(tcp_create_openreq_child);
EXPORT_SYMBOL(tcp_bucket_create);
EXPORT_SYMBOL(__tcp_put_port);
@@ -596,6 +595,51 @@ EXPORT_SYMBOL(nf_setsockopt);
EXPORT_SYMBOL(nf_getsockopt);
#endif
+#ifdef CONFIG_IP_NF_CONNTRACK
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+EXPORT_SYMBOL(ip_conntrack_protocol_register);
+EXPORT_SYMBOL(invert_tuplepr);
+EXPORT_SYMBOL(ip_conntrack_alter_reply);
+EXPORT_SYMBOL(ip_conntrack_destroyed);
+EXPORT_SYMBOL(ip_conntrack_get);
+EXPORT_SYMBOL(ip_conntrack_module);
+EXPORT_SYMBOL(ip_conntrack_helper_register);
+EXPORT_SYMBOL(ip_conntrack_helper_unregister);
+EXPORT_SYMBOL(ip_ct_selective_cleanup);
+EXPORT_SYMBOL(ip_ct_refresh);
+EXPORT_SYMBOL(ip_conntrack_expect_related);
+EXPORT_SYMBOL(ip_conntrack_tuple_taken);
+EXPORT_SYMBOL(ip_ct_gather_frags);
+#ifdef CONFIG_IP_NF_FTP
+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+EXPORT_SYMBOL(ip_ftp_lock);
+#endif
+#endif /*CONFIG_IP_NF_CONNTRACK*/
+
+#ifdef CONFIG_IP_NF_NAT
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+EXPORT_SYMBOL(ip_nat_setup_info);
+EXPORT_SYMBOL(ip_nat_helper_register);
+EXPORT_SYMBOL(ip_nat_helper_unregister);
+EXPORT_SYMBOL(ip_nat_expect_register);
+EXPORT_SYMBOL(ip_nat_expect_unregister);
+EXPORT_SYMBOL(ip_nat_cheat_check);
+#endif
+
+#ifdef CONFIG_IP_NF_IPTABLES
+#include <linux/netfilter_ipv4/ip_tables.h>
+EXPORT_SYMBOL(ipt_register_table);
+EXPORT_SYMBOL(ipt_unregister_table);
+EXPORT_SYMBOL(ipt_register_target);
+EXPORT_SYMBOL(ipt_unregister_target);
+EXPORT_SYMBOL(ipt_register_match);
+EXPORT_SYMBOL(ipt_unregister_match);
+#endif
+
EXPORT_SYMBOL(register_gifconf);
EXPORT_SYMBOL(net_call_rx_atomic);
diff --git a/net/socket.c b/net/socket.c
index edaf48a3b..fb5158241 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -690,20 +690,17 @@ int sock_wake_async(struct socket *sock, int how, int band)
switch (how)
{
case 1:
- if (sock->flags & SO_WAITDATA)
+
+ if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
break;
goto call_kill;
case 2:
- if (!(sock->flags & SO_NOSPACE))
+ if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags))
break;
- sock->flags &= ~SO_NOSPACE;
/* fall through */
case 0:
call_kill:
- /* read_lock(&sock->sk->callback_lock); */
- if(sock->fasync_list != NULL)
- kill_fasync(sock->fasync_list, SIGIO, band);
- /* read_unlock(&sock->sk->callback_lock); */
+ kill_fasync(sock->fasync_list, SIGIO, band);
break;
case 3:
kill_fasync(sock->fasync_list, SIGURG, band);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 806e14bce..c41dfc1eb 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -32,6 +32,8 @@
#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+
#define RPC_SLACK_SPACE 1024 /* total overkill */
@@ -78,6 +80,7 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
#ifdef RPC_DEBUG
rpc_register_sysctl();
#endif
+ xdr_init();
if (!xprt)
goto out;
@@ -198,7 +201,6 @@ rpc_release_client(struct rpc_clnt *clnt)
static void
rpc_default_callback(struct rpc_task *task)
{
- rpc_release_task(task);
}
/*
@@ -263,9 +265,10 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
/* Set up the call info struct and execute the task */
if (task->tk_status == 0)
status = rpc_execute(task);
- else
+ else {
status = task->tk_status;
- rpc_release_task(task);
+ rpc_release_task(task);
+ }
rpc_clnt_sigunmask(clnt, &oldset);
@@ -344,10 +347,9 @@ rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
void
rpc_restart_call(struct rpc_task *task)
{
- if (task->tk_flags & RPC_TASK_KILLED) {
- rpc_release_task(task);
+ if (RPC_ASSASSINATED(task))
return;
- }
+
task->tk_action = call_reserve;
rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
}
@@ -715,7 +717,7 @@ call_decode(struct rpc_task *task)
* The following is an NFS-specific hack to cater for setuid
* processes whose uid is mapped to nobody on the server.
*/
- if (task->tk_client->cl_prog == 100003 &&
+ if (task->tk_client->cl_prog == NFS_PROGRAM &&
(ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {
if (RPC_IS_SETUID(task) && task->tk_suid_retry) {
dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index bfbfc1580..da46ab910 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -508,6 +508,7 @@ __rpc_execute(struct rpc_task *task)
return 0;
}
+ restarted:
while (1) {
/*
* Execute any pending callback.
@@ -586,10 +587,29 @@ __rpc_execute(struct rpc_task *task)
}
}
+ if (task->tk_exit) {
+ task->tk_exit(task);
+ /* If tk_action is non-null, the user wants us to restart */
+ if (task->tk_action) {
+ if (!RPC_ASSASSINATED(task)) {
+ /* Release RPC slot and buffer memory */
+ if (task->tk_rqstp)
+ xprt_release(task);
+ if (task->tk_buffer) {
+ rpc_free(task->tk_buffer);
+ task->tk_buffer = NULL;
+ }
+ goto restarted;
+ }
+ printk(KERN_ERR "RPC: dead task tries to walk away.\n");
+ }
+ }
+
dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);
status = task->tk_status;
- if (task->tk_exit)
- task->tk_exit(task);
+
+ /* Release all resources associated with the task */
+ rpc_release_task(task);
return status;
}
@@ -599,22 +619,32 @@ __rpc_execute(struct rpc_task *task)
*
* This may be called recursively if e.g. an async NFS task updates
* the attributes and finds that dirty pages must be flushed.
+ * NOTE: Upon exit of this function the task is guaranteed to be
+ * released. In particular note that tk_release() will have
+ * been called, so your task memory may have been freed.
*/
int
rpc_execute(struct rpc_task *task)
{
+ int status = -EIO;
if (rpc_inhibit) {
printk(KERN_INFO "RPC: execution inhibited!\n");
- return -EIO;
+ goto out_release;
}
- task->tk_flags |= RPC_TASK_RUNNING;
+
+ status = -EWOULDBLOCK;
if (task->tk_active) {
printk(KERN_ERR "RPC: active task was run twice!\n");
- return -EWOULDBLOCK;
+ goto out_err;
}
+
task->tk_active = 1;
-
+ task->tk_flags |= RPC_TASK_RUNNING;
return __rpc_execute(task);
+ out_release:
+ rpc_release_task(task);
+ out_err:
+ return status;
}
/*
@@ -700,7 +730,7 @@ rpc_allocate(unsigned int flags, unsigned int size)
}
if (flags & RPC_TASK_ASYNC)
return NULL;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ>>4);
} while (!signalled());
@@ -758,6 +788,13 @@ rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
current->pid);
}
+static void
+rpc_default_free_task(struct rpc_task *task)
+{
+ dprintk("RPC: %4d freeing task\n", task->tk_pid);
+ rpc_free(task);
+}
+
/*
* Create a new task for the specified client. We have to
* clean up after an allocation failure, as the client may
@@ -774,6 +811,9 @@ rpc_new_task(struct rpc_clnt *clnt, rpc_action callback, int flags)
rpc_init_task(task, clnt, callback, flags);
+ /* Replace tk_release */
+ task->tk_release = rpc_default_free_task;
+
dprintk("RPC: %4d allocated task\n", task->tk_pid);
task->tk_flags |= RPC_TASK_DYNAMIC;
out:
@@ -849,12 +889,8 @@ rpc_release_task(struct rpc_task *task)
#ifdef RPC_DEBUG
task->tk_magic = 0;
#endif
-
- if (task->tk_flags & RPC_TASK_DYNAMIC) {
- dprintk("RPC: %4d freeing task\n", task->tk_pid);
- task->tk_flags &= ~RPC_TASK_DYNAMIC;
- rpc_free(task);
- }
+ if (task->tk_release)
+ task->tk_release(task);
}
/*
@@ -886,7 +922,6 @@ rpc_child_exit(struct rpc_task *child)
__rpc_wake_up(parent);
}
spin_unlock_bh(&rpc_queue_lock);
- rpc_release_task(child);
}
/*
@@ -1028,7 +1063,7 @@ rpciod_killall(void)
__rpc_schedule();
if (all_tasks) {
dprintk("rpciod_killall: waiting for tasks to exit\n");
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
}
@@ -1099,7 +1134,7 @@ rpciod_down(void)
* wait briefly before checking the process id.
*/
current->sigpending = 0;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
/*
* Display a message if we're going to wait longer.
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 92559fa65..36da3b619 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -27,7 +27,6 @@ EXPORT_SYMBOL(rpc_allocate);
EXPORT_SYMBOL(rpc_free);
EXPORT_SYMBOL(rpc_execute);
EXPORT_SYMBOL(rpc_init_task);
-EXPORT_SYMBOL(rpc_release_task);
EXPORT_SYMBOL(rpc_sleep_on);
EXPORT_SYMBOL(rpc_wake_up_next);
EXPORT_SYMBOL(rpc_wake_up_task);
@@ -89,12 +88,15 @@ EXPORT_SYMBOL(svc_proc_read);
#endif
/* Generic XDR */
+EXPORT_SYMBOL(xdr_encode_array);
EXPORT_SYMBOL(xdr_encode_string);
EXPORT_SYMBOL(xdr_decode_string);
EXPORT_SYMBOL(xdr_decode_netobj);
EXPORT_SYMBOL(xdr_encode_netobj);
EXPORT_SYMBOL(xdr_zero);
EXPORT_SYMBOL(xdr_one);
+EXPORT_SYMBOL(xdr_shift_iovec);
+EXPORT_SYMBOL(xdr_zero_iovec);
/* RPC errors */
EXPORT_SYMBOL(rpc_success);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 97e323d0c..d99033fa5 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -769,7 +769,7 @@ again:
* We have to be able to interrupt this wait
* to bring down the daemons ...
*/
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&rqstp->rq_wait, &wait);
spin_unlock_bh(&serv->sv_lock);
@@ -940,7 +940,6 @@ svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin)
if (protocol == IPPROTO_TCP) {
if ((error = sock->ops->listen(sock, 5)) < 0)
goto bummer;
- sock->flags |= SO_ACCEPTCON;
}
if ((svsk = svc_setup_socket(serv, sock, &error, 1)) != NULL)
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 6ebd94079..99b286af9 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -9,6 +9,7 @@
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/string.h>
+#include <linux/kernel.h>
#include <linux/in.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h>
@@ -56,8 +57,8 @@ xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
{
unsigned int quadlen = XDR_QUADLEN(obj->len);
+ p[quadlen] = 0; /* zero trailing bytes */
*p++ = htonl(obj->len);
- p[quadlen-1] = 0; /* zero trailing bytes */
memcpy(p, obj->data, obj->len);
return p + XDR_QUADLEN(obj->len);
}
@@ -84,18 +85,23 @@ xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
}
u32 *
-xdr_encode_string(u32 *p, const char *string)
+xdr_encode_array(u32 *p, const char *array, unsigned int len)
{
- int len = strlen(string);
int quadlen = XDR_QUADLEN(len);
p[quadlen] = 0;
*p++ = htonl(len);
- memcpy(p, string, len);
+ memcpy(p, array, len);
return p + quadlen;
}
u32 *
+xdr_encode_string(u32 *p, const char *string)
+{
+ return xdr_encode_array(p, string, strlen(string));
+}
+
+u32 *
xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
{
unsigned int len;
@@ -116,3 +122,51 @@ xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
return p + XDR_QUADLEN(len);
}
+/*
+ * Realign the iovec if the server missed out some reply elements
+ * (such as post-op attributes,...)
+ * Note: This is a simple implementation that assumes that
+ * len <= iov->iov_len !!!
+ * The RPC header (assumed to be the 1st element in the iov array)
+ * is not shifted.
+ */
+void xdr_shift_iovec(struct iovec *iov, int nr, size_t len)
+{
+ struct iovec *pvec;
+
+ for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) {
+ struct iovec *svec = pvec - 1;
+
+ if (len > pvec->iov_len) {
+ printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+ return;
+ }
+ memmove((char *)pvec->iov_base + len, pvec->iov_base,
+ pvec->iov_len - len);
+
+ if (len > svec->iov_len) {
+ printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+ return;
+ }
+ memcpy(pvec->iov_base,
+ (char *)svec->iov_base + svec->iov_len - len, len);
+ }
+}
+
+/*
+ * Zero the last n bytes in an iovec array of 'nr' elements
+ */
+void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+{
+ struct iovec *pvec;
+
+ for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
+ if (n < pvec->iov_len) {
+ memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
+ n = 0;
+ } else {
+ memset(pvec->iov_base, 0, pvec->iov_len);
+ n -= pvec->iov_len;
+ }
+ }
+}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 06d682223..b353aa37a 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -48,6 +48,7 @@
#include <linux/version.h>
#include <linux/types.h>
#include <linux/malloc.h>
+#include <linux/capability.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/socket.h>
@@ -227,7 +228,7 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req)
*/
break;
case -EAGAIN:
- if (sock->flags & SO_NOSPACE)
+ if (test_bit(SOCK_NOSPACE, &sock->flags))
result = -ENOMEM;
break;
case -ENOTCONN:
@@ -1569,8 +1570,8 @@ xprt_create_socket(int proto, struct rpc_timeout *to)
goto failed;
}
- /* If the caller has root privs, bind to a reserved port */
- if (!current->fsuid && xprt_bindresvport(sock) < 0)
+ /* If the caller has the capability, bind to a reserved port */
+ if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0)
goto failed;
return sock;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index cbe730b5d..12a4b1eb3 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -8,7 +8,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: af_unix.c,v 1.90 2000/03/16 20:38:45 davem Exp $
+ * Version: $Id: af_unix.c,v 1.91 2000/03/25 01:55:34 davem Exp $
*
* Fixes:
* Linus Torvalds : Assorted bug cures.
@@ -297,9 +297,10 @@ static __inline__ int unix_writable(struct sock *sk)
static void unix_write_space(struct sock *sk)
{
read_lock(&sk->callback_lock);
- if (!sk->dead && unix_writable(sk)) {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 2, POLL_OUT);
+ if (unix_writable(sk)) {
+ if (sk->sleep && waitqueue_active(sk->sleep))
+ wake_up_interruptible(sk->sleep);
+ sk_wake_async(sk, 2, POLL_OUT);
}
read_unlock(&sk->callback_lock);
}
@@ -356,8 +357,10 @@ static int unix_release_sock (unix_socket *sk, int embrion)
if (!skb_queue_empty(&sk->receive_queue) || embrion)
skpair->err = ECONNRESET;
unix_state_wunlock(skpair);
- sk->state_change(skpair);
- sock_wake_async(sk->socket,1,POLL_HUP);
+ skpair->state_change(skpair);
+ read_lock(&skpair->callback_lock);
+ sk_wake_async(skpair,1,POLL_HUP);
+ read_unlock(&skpair->callback_lock);
}
sock_put(skpair); /* It may now die */
unix_peer(sk) = NULL;
@@ -418,7 +421,6 @@ static int unix_listen(struct socket *sock, int backlog)
wake_up_interruptible_all(&sk->protinfo.af_unix.peer_wait);
sk->max_ack_backlog=backlog;
sk->state=TCP_LISTEN;
- sock->flags |= SO_ACCEPTCON;
/* set credentials so connect can copy them */
sk->peercred.pid = current->pid;
sk->peercred.uid = current->euid;
@@ -562,39 +564,51 @@ static unix_socket *unix_find_other(struct sockaddr_un *sunname, int len,
int type, unsigned hash, int *error)
{
unix_socket *u;
+ struct dentry *dentry;
+ int err;
- if (sunname->sun_path[0])
- {
- struct dentry *dentry;
-
+ if (sunname->sun_path[0]) {
/* Do not believe to VFS, grab kernel lock */
lock_kernel();
- dentry = __open_namei(sunname->sun_path, 2|O_NOFOLLOW, S_IFSOCK, NULL);
+ dentry = lookup_dentry(sunname->sun_path,LOOKUP_POSITIVE);
+ err = PTR_ERR(dentry);
if (IS_ERR(dentry)) {
- *error = PTR_ERR(dentry);
unlock_kernel();
- return NULL;
+ goto fail;
}
+ err = permission(dentry->d_inode,MAY_WRITE);
+ if (err)
+ goto put_fail;
+
+ err = -ECONNREFUSED;
+ if (!S_ISSOCK(dentry->d_inode->i_mode))
+ goto put_fail;
u=unix_find_socket_byinode(dentry->d_inode);
+ if (!u)
+ goto put_fail;
+
dput(dentry);
unlock_kernel();
- if (u && u->type != type)
- {
- *error=-EPROTOTYPE;
+ err=-EPROTOTYPE;
+ if (u->type != type) {
sock_put(u);
- return NULL;
+ goto fail;
}
- }
- else
+ } else {
+ err = -ECONNREFUSED;
u=unix_find_socket_byname(sunname, len, type, hash);
-
- if (u==NULL)
- {
- *error=-ECONNREFUSED;
- return NULL;
+ if (!u)
+ goto fail;
}
return u;
+
+put_fail:
+ dput(dentry);
+ unlock_kernel();
+fail:
+ *error=err;
+ return NULL;
}
@@ -827,7 +841,7 @@ restart:
timeo = unix_wait_for_peer(other, timeo);
- err = -ERESTARTSYS;
+ err = sock_intr_errno(timeo);
if (signal_pending(current))
goto out;
sock_put(other);
@@ -1156,7 +1170,7 @@ restart:
timeo = unix_wait_for_peer(other, timeo);
- err = -ERESTARTSYS;
+ err = sock_intr_errno(timeo);
if (signal_pending(current))
goto out_free;
@@ -1228,8 +1242,8 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len,
* much.
*/
- if (size > 4096-16)
- limit = 4096-16; /* Fall back to a page if we can't grab a big buffer this instant */
+ if (size > PAGE_SIZE-16)
+ limit = PAGE_SIZE-16; /* Fall back to a page if we can't grab a big buffer this instant */
else
limit = 0; /* Otherwise just grab and wait */
@@ -1383,11 +1397,11 @@ static long unix_stream_data_wait(unix_socket * sk, long timeo)
!timeo)
break;
- sk->socket->flags |= SO_WAITDATA;
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
unix_state_runlock(sk);
timeo = schedule_timeout(timeo);
unix_state_rlock(sk);
- sk->socket->flags &= ~SO_WAITDATA;
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
}
__set_current_state(TASK_RUNNING);
@@ -1455,7 +1469,7 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size
timeo = unix_stream_data_wait(sk, timeo);
if (signal_pending(current)) {
- err = -ERESTARTSYS;
+ err = sock_intr_errno(timeo);
goto out;
}
down(&sk->protinfo.af_unix.readsem);
@@ -1556,10 +1570,12 @@ static int unix_shutdown(struct socket *sock, int mode)
other->shutdown |= peer_mode;
unix_state_wunlock(other);
other->state_change(other);
+ read_lock(&other->callback_lock);
if (peer_mode == SHUTDOWN_MASK)
- sock_wake_async(other->socket,1,POLL_HUP);
+ sk_wake_async(other,1,POLL_HUP);
else if (peer_mode & RCV_SHUTDOWN)
- sock_wake_async(other->socket,1,POLL_IN);
+ sk_wake_async(other,1,POLL_IN);
+ read_unlock(&other->callback_lock);
}
if (other)
sock_put(other);
@@ -1658,7 +1674,7 @@ static int unix_read_proc(char *buffer, char **start, off_t offset,
s,
atomic_read(&s->refcnt),
0,
- s->state == TCP_LISTEN ? SO_ACCEPTCON : 0,
+ s->state == TCP_LISTEN ? __SO_ACCEPTCON : 0,
s->type,
s->socket ?
(s->state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) :
diff --git a/scripts/Menuconfig b/scripts/Menuconfig
index d43739a67..3e0da2a9f 100644
--- a/scripts/Menuconfig
+++ b/scripts/Menuconfig
@@ -404,7 +404,7 @@ function help () {
$DIALOG --backtitle "$backtitle" \
--textbox help.out $ROWS $COLS
fi
- rm help.out
+ rm -f help.out
}
#
@@ -1362,7 +1362,7 @@ Use the <TAB> key to move from the input field to the buttons below it."
DIALOG="./scripts/lxdialog/lxdialog"
-kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"
+kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
backtitle="Linux Kernel v$kernel_version Configuration"
@@ -1450,4 +1450,10 @@ else
echo Your kernel configuration changes were NOT saved.
echo
fi
+
+# Remove log if empty.
+if [ ! -s .menuconfig.log ] ; then
+ rm -f .menuconfig.log
+fi
+
exit 0
diff --git a/scripts/checkincludes.pl b/scripts/checkincludes.pl
new file mode 100644
index 000000000..8e6b716c1
--- /dev/null
+++ b/scripts/checkincludes.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+#
+# checkincludes: Find files included more than once in (other) files.
+# Copyright abandoned, 2000, Niels Kristian Bech Jensen <nkbj@image.dk>.
+
+foreach $file (@ARGV) {
+ open(FILE, $file) or die "Cannot open $file: $!.\n";
+
+ my %includedfiles = ();
+
+ while (<FILE>) {
+ if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) {
+ ++$includedfiles{$1};
+ }
+ }
+
+ foreach $filename (keys %includedfiles) {
+ if ($includedfiles{$filename} > 1) {
+ print "$file: $filename is included more than once.\n";
+ }
+ }
+
+ close(FILE);
+}
diff --git a/scripts/docproc.c b/scripts/docproc.c
index 0c23e87c1..0f7eaa218 100644
--- a/scripts/docproc.c
+++ b/scripts/docproc.c
@@ -12,7 +12,7 @@
int main(int argc, char *argv[])
{
char buf[1024];
- char *vec[1024];
+ char *vec[8192];
char type[64];
int i;
int vp=2;
@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
*/
vec[0]="kernel-doc";
vec[1]="-docbook";
- for(i=1;vp<1021;i++)
+ for(i=1;vp<8189;i++)
{
if(argv[i]==NULL)
break;
@@ -67,7 +67,7 @@ int main(int argc, char *argv[])
exit(1);
case 0:
execvp("scripts/kernel-doc", vec);
- perror("exec");
+ perror("exec scripts/kernel-doc");
exit(1);
default:
waitpid(pid, NULL,0);
diff --git a/scripts/gen-all-syms b/scripts/gen-all-syms
index d65e196ca..b15b16004 100644
--- a/scripts/gen-all-syms
+++ b/scripts/gen-all-syms
@@ -3,5 +3,5 @@ for i in $*
do
grep "EXPORT_SYMBOL.*(.*)" "$i" \
| sed -e "s/EXPORT_SYMBOL.*(/ /" \
- | sed -e "s/).*$//"
+ | sed -e "s/).*$//" | sed -e "s/^ //"
done
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 1e24b8169..b9e872d20 100644
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -238,6 +238,7 @@ sub output_highlight {
if ($line eq ""){
print $lineprefix, $blankline;
} else {
+ $line =~ s/\\\\\\/\&/g;
print $lineprefix, $line;
}
print "\n";
@@ -640,6 +641,12 @@ sub dump_function {
}
$type = join " ", @args;
+ if ($type eq "" && $param eq "...")
+ {
+ $type="...";
+ $param="...";
+ $parameters{"..."} = "variable arguments";
+ }
if ($type eq "")
{
$type="";
@@ -753,6 +760,9 @@ foreach $file (@ARGV) {
$newcontents = $2;
if ($contents ne "") {
+ $contents =~ s/\&/\\\\\\amp;/g;
+ $contents =~ s/\</\\\\\\lt;/g;
+ $contents =~ s/\>/\\\\\\gt;/g;
dump_section($section, $contents);
$section = $section_default;
}
@@ -765,6 +775,9 @@ foreach $file (@ARGV) {
} elsif (/$doc_end/) {
if ($contents ne "") {
+ $contents =~ s/\&/\\\\\\amp;/g;
+ $contents =~ s/\</\\\\\\lt;/g;
+ $contents =~ s/\>/\\\\\\gt;/g;
dump_section($section, $contents);
$section = $section_default;
$contents = "";
@@ -777,6 +790,9 @@ foreach $file (@ARGV) {
# miguel-style comment kludge, look for blank lines after
# @parameter line to signify start of description
if ($1 eq "" && $section =~ m/^@/) {
+ $contents =~ s/\&/\\\\\\amp;/g;
+ $contents =~ s/\</\\\\\\lt;/g;
+ $contents =~ s/\>/\\\\\\gt;/g;
dump_section($section, $contents);
$section = $section_default;
$contents = "";